Ejemplo n.º 1
0
// Get the engineID of the SNMP entity at the given host/port.
int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
                                   const OctetStr &host, int port) const
{
  if (!table)
    return SNMPv3_MP_NOT_INITIALIZED;

  BEGIN_REENTRANT_CODE_BLOCK_CONST;

  int i, found = 0;

  for (i = 0; i < entries; i++)
    if ((table[i].port == port) &&
        (table[i].host == host))
    {
      found=1;
      break;
    }
  if (!found)
  {
    LOG_BEGIN(loggerModuleName, INFO_LOG | 4);
    LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
    LOG(host.get_printable());
    LOG(port);
    LOG_END;

    return SNMPv3_MP_ERROR;
  }

  engine_id = table[i].engine_id;

  return SNMPv3_MP_OK;
}
Ejemplo n.º 2
0
// Remove the entry for the given address/port from the table.
int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
{
  if (!table)
    return SNMPv3_MP_NOT_INITIALIZED;

  int i, found = 0;

  BEGIN_REENTRANT_CODE_BLOCK;

  for (i = 0; i < entries; i++)
    if ((table[i].port == port) &&
        (table[i].host == host))
    {
      found=1;
      break;
    }
  if (!found)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 4);
    LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
    LOG(host.get_printable());
    LOG(port);
    LOG_END;

    return SNMPv3_MP_ERROR;
  }

  /* i is the entry to remove */
  if (i != entries - 1)
    table[i] = table[entries-1];

  entries--;

  return SNMPv3_MP_OK;
}
Ejemplo n.º 3
0
// Get the engine_id of the SNMP entity at the given host/port.
int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
                                   const OctetStr &hostport) const
{
  int port;
  char host[MAX_HOST_NAME_LENGTH + 1];
  char *ptr;

  /* Check length */
  if (hostport.len() > MAX_HOST_NAME_LENGTH)
    return SNMPv3_MP_ERROR;

  /* split up port from hostport */
  strcpy(host, hostport.get_printable());

  ptr = strstr((char*)host,"/");
  if (!ptr)
    return SNMPv3_MP_ERROR;

  *ptr = '\0';
  port = atol(ptr + 1);

  /* Check for IPv6 address with [] */
  if (host[0] == '[')
  {
    if (*(ptr -1) == ']')
    {
      *(ptr-1) = '\0';
      return get_entry(engine_id, &(host[1]), port);
    }
    else
      return SNMPv3_MP_ERROR;
  }
  return get_entry(engine_id, host, port);
}
Ejemplo n.º 4
0
// Add an entry to the table.
int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
                                   const OctetStr &host, int port)
{
  if (!table)
    return SNMPv3_MP_NOT_INITIALIZED;

  LOG_BEGIN(loggerModuleName, INFO_LOG | 9);
  LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
  LOG(engine_id.get_printable());
  LOG(host.get_printable());
  LOG(port);
  LOG_END;

  BEGIN_REENTRANT_CODE_BLOCK;

  for (int i = 0; i < entries; i++)
    if (((table[i].port == port) &&
         (table[i].host == host)) ||
	(table[i].engine_id == engine_id))
    {
      LOG_BEGIN(loggerModuleName, INFO_LOG | 2);
      LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
      LOG(table[i].engine_id.get_printable());
      LOG(table[i].host.get_printable());
      LOG(table[i].port);
      LOG(engine_id.get_printable());
      LOG(host.get_printable());
      LOG(port);
      LOG_END;

      table[i].engine_id = engine_id;
      table[i].host = host;
      table[i].port = port;

      return SNMPv3_MP_OK;         // host is in table
    }

  table[entries].engine_id = engine_id;
  table[entries].host = host;
  table[entries].port = port;

  entries++;
  if (entries == max_entries)
  {
    // resize Table
    struct Entry_T *tmp;
    tmp = new struct Entry_T[2 * max_entries];
    if (!tmp)
    {
      entries--;
      return SNMPv3_MP_ERROR;
    }
    for (int i = 0; i < entries; i++)
      tmp[i] = table[i];

    delete [] table;
    table = tmp;
    max_entries *= 2;
  }

  return SNMPv3_MP_OK;
}
Ejemplo n.º 5
0
// Send a report message.
int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
		      struct snmp_pdu *pdu, int errorCode, int sLevel,
		      int sModel, OctetStr &sName,
		      UdpAddress &destination, Snmp *snmp_session)
{
  debugprintf(2, "v3MP::send_report: Sending report message.");

  unsigned char *data;
  int dataLength;
  int pdu_type = 0;
  unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
  unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
  int cEngineIDLength = MAXLENGTH_ENGINEID+1;
  int cNameLength = MAXLENGTH_CONTEXT_NAME+1;

  debugprintf(2, "v3MP::send_report: securityLevel %d",sLevel);

  if (scopedPDULength != MAX_SNMP_PACKET)
  {
    // try to get scopedPDU and PDU
    data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
				 cEngineID, &cEngineIDLength,
				 cName, &cNameLength);
    if (data == NULL) {
      debugprintf(1, "mp: Error while trying to parse  scopedPDU!");
      cEngineID[0] = '\0';
      cEngineIDLength = 0;
      cName[0] = '\0';
      cNameLength = 0;
      // Dont send encrypted report if decryption failed:
      //if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
     //   sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
    }
    else { // data != NULL
      dataLength = scopedPDULength;

      // parse data of scopedPDU
      snmp_parse_data_pdu(pdu, data, dataLength);
      pdu_type = pdu->command;

      if (!data) {
        debugprintf(0, "mp: Error while trying to parse PDU!");
      }
    } // end of: if (data == NULL)
  } // end if (scopedPDULength != MAX_SNMP_PACKET)
  else { // scopedPDULength == MAX_SNMP_PACKET
    cEngineID[0] = '\0';
    cEngineIDLength = 0;
    cName[0] = '\0';
    cNameLength = 0;
    pdu->reqid = 0;
  }

  clear_pdu(pdu);   // Clear pdu and free all content

  debugprintf(4, "pdu->reqid = %ld",pdu->reqid);
  pdu->errstat = 0;
  pdu->errindex = 0;
  pdu->command = REPORT_MSG;

  Vb counterVb;
  Oid counterOid;
  SmiLPOID smioid;
  SmiVALUE smival;

  switch (errorCode) {
    case SNMPv3_MP_INVALID_MESSAGE:
    case SNMPv3_USM_PARSE_ERROR: {
      counterVb.set_oid(oidSnmpInvalidMsgs);
      counterVb.set_value(Counter32(get_stats_invalid_msgs()));
      break;
    }
    case SNMPv3_USM_NOT_IN_TIME_WINDOW:
    case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
      counterVb.set_oid(oidUsmStatsNotInTimeWindows);
      counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
      break;
    }
    case SNMPv3_USM_DECRYPTION_ERROR: {
      counterVb.set_oid(oidUsmStatsDecryptionErrors);
      counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
      //sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      break;
    }
    case SNMPv3_USM_AUTHENTICATION_ERROR:
    case SNMPv3_USM_AUTHENTICATION_FAILURE: {
      counterVb.set_oid(oidUsmStatsWrongDigests);
      counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
      //sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      break;
    }
    case SNMPv3_USM_UNKNOWN_ENGINEID:
    case SNMPv3_MP_INVALID_ENGINEID: {
      //sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
      counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
      break;
    }
    case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
      counterVb.set_oid(oidSnmpUnknownSecurityModels);
      counterVb.set_value(Counter32(get_stats_unknown_security_models()));
      sModel = SNMP_SECURITY_MODEL_USM;
      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
    break;
    }
    case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
      counterVb.set_oid(oidUsmStatsUnknownUserNames);
      counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
      break;
    }
    case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
      counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
      counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      break;
    }
    default: {
      counterVb.set_oid(oidSnmpInvalidMsgs);
      counterVb.set_value(Counter32(get_stats_invalid_msgs()));
      sModel = SNMP_SECURITY_MODEL_USM;
      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      sName.set_data(0, 0);

      debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
    }
  } // end switch

  counterVb.get_oid(counterOid);
  smioid = counterOid.oidval();

  int status = convertVbToSmival(counterVb, &smival);
  if (status != SNMP_CLASS_SUCCESS) {
    return SNMPv3_MP_ERROR;
  }
  snmp_add_var(pdu, smioid->ptr,
               (int) smioid->len, &smival);
  freeSmivalDescriptor(&smival);

  Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
  int sendbufferlen= MAX_SNMP_PACKET;
  status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
		       own_engine_id_oct, sName, sModel, sLevel,
		       OctetStr(cEngineID, cEngineIDLength),
		       OctetStr(cName, cNameLength));
  if (status != SNMPv3_MP_OK) {
    debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
    return SNMPv3_MP_ERROR;
  }
  SnmpSocket send_fd = INVALID_SOCKET;
  if (pdu_type == sNMP_PDU_INFORM)
  {
    debugprintf(4, "Received a snmpInform pdu.");
    if (snmp_session->get_eventListHolder()->notifyEventList())
      send_fd = snmp_session->get_eventListHolder()->notifyEventList()->get_notify_fd();
  }

  status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
                                       (size_t)sendbufferlen,// pdu to send
			               destination,          // target address
			               send_fd);             // the fd to use
  if ( status != 0)
  {
    debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
    return SNMPv3_MP_ERROR;
  }
  debugprintf(3, "v3MP::send_report: Report sent.");
  return SNMPv3_MP_OK;
}
Ejemplo n.º 6
0
// Do the complete process of encoding the given values into the buffer
// ready to send to the target.
int v3MP::snmp_build(struct snmp_pdu *pdu,
		     unsigned char *packet,
		     int *out_length,             // maximum Bytes in packet
		     const OctetStr &securityEngineID,
		     const OctetStr &securityName,
		     int securityModel,
		     int securityLevel,
		     const OctetStr &contextEngineID,
		     const OctetStr &contextName)
{
  Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
  unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
  unsigned char globalData[MAXLENGTH_GLOBALDATA];
  int globalDataLength = MAXLENGTH_GLOBALDATA;
  int scopedPDULength, maxLen = *out_length;
  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
  unsigned char *bufPtr = buf.get_ptr();
  long bufLength = 0, rc;
  int msgID;
  int cachedErrorCode = SNMPv3_MP_OK;
  struct SecurityStateReference *securityStateReference = NULL;
  int isRequestMessage = 0;

  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
      (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
      (pdu->command == TRP2_REQ_MSG))
    isRequestMessage = 1;

  if (isRequestMessage) {
    if (securityEngineID.len() == 0) {
      // First Contact => use user  noAuthNoPriv and USM
      securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      securityModel = SNMP_SECURITY_MODEL_USM;
    }

    cur_msg_id_lock.lock();
    msgID = cur_msg_id;
    cur_msg_id++;
    if (cur_msg_id >= MAX_MPMSGID)
      cur_msg_id = 1;
    cur_msg_id_lock.unlock();

#ifdef INVALID_MSGID
    LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
    LOG("*** WARNING: Using constant MessageID! ***");
    LOG_END;

    msgID = 0xdead;
#endif

    if (securityEngineID.len() == 0) {
      // length==0 => SecurityLevel == noAuthNoPriv
      //  => we do not send any management information
      //  => delete VariableBinding
      clear_pdu(pdu);
    }
  }
  else {
    // it is a response => search for request
    debugprintf(3, "Looking up cache");
    msgID = pdu->msgid;
    rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
                         &cachedErrorCode, &securityStateReference);

    if (rc != SNMPv3_MP_OK) {

      debugprintf(0, "mp: Cache lookup error");
      return SNMPv3_MP_MATCH_ERROR;
    }
  }

  LOG_BEGIN(loggerModuleName, DEBUG_LOG | 5);
  LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
  LOG(securityEngineID.get_printable());
  LOG(securityName.get_printable());
  LOG(securityLevel);
  LOG(contextEngineID.get_printable());
  LOG(contextName.get_printable());
  LOG_END;

  // encode vb in buf
  scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
  if (!scopedPDUPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding vbs into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }
  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());

  //build dataPDU in buf
  maxLen = *out_length;
  scopedPDUPtr = scopedPDU.get_ptr();
  bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);

  if (!bufPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding data pdu into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }

  bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());

  //  serialize scopedPDU
  maxLen = *out_length;
  scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
				       contextEngineID.data(),
				       contextEngineID.len(),
				       contextName.data(), contextName.len(),
				       buf.get_ptr(), bufLength);

  if (!scopedPDUPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding scoped pdu into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }

  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());

  // build msgGlobalData
  unsigned char *globalDataPtr = (unsigned char *)&globalData;
  unsigned char msgFlags;
  switch (securityLevel) {
    case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
      { msgFlags = 0 ; break;}
    case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
      { msgFlags = SNMPv3_AUTHFLAG; break;}
    case SNMP_SECURITY_LEVEL_AUTH_PRIV:
      { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
    default:
    {
      LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
      LOG("v3MP: Unknown security level requested, will use authPriv");
      LOG(securityLevel);
      LOG_END;

      msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
    }
  }

  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
      (pdu->command == INFORM_REQ_MSG))
    msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;

  globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
					 msgID, *out_length,  // maxMessageSize
					 msgFlags, securityModel);
  if (!globalDataPtr)
  {
    LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
    LOG("v3MP: Error building header data");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }
  globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);

  switch (securityModel) {
    case SNMP_SECURITY_MODEL_USM: {
      int use_own_engine_id = 0;
      if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
          (pdu->command == REPORT_MSG)  || (pdu->command == TRP2_REQ_MSG)) {
        use_own_engine_id = 1;
      }

      rc = usm->generate_msg(globalData, globalDataLength, *out_length,
                             (use_own_engine_id ?
                                        own_engine_id_oct : securityEngineID),
                             securityName, securityLevel,
                             scopedPDU.get_ptr(), scopedPDULength,
                             securityStateReference, packet, out_length);

      if ( rc == SNMPv3_USM_OK ) {
        // build cache
        if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
              (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
          cache.add_entry(msgID, pdu->reqid, securityEngineID,
                          securityModel, securityName, securityLevel,
                          contextEngineID, contextName, securityStateReference,
                          SNMPv3_MP_OK, CACHE_LOCAL_REQ);

	LOG_BEGIN(loggerModuleName, INFO_LOG | 3);
	LOG("v3MP: Message built OK");
	LOG_END;

        return SNMPv3_MP_OK;
      }
      else
      {
	LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
	LOG("v3MP: Returning error for building message");
	LOG(rc);
	LOG_END;

        return rc;
      }
    }
    default:
    {
      LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
      LOG("v3MP: Should build message with unsupported securityModel");
      LOG(securityModel);
      LOG_END;

      return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
    }
  }
}
Ejemplo n.º 7
0
int CNotifyEventQueue::AddEntry(Snmp *snmp,
                                const OidCollection &trapids,
                                const TargetCollection &targets)
{
  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()

  if (snmp != m_snmpSession)
  {
    debugprintf(0, "WARNING: Adding notification event for other Snmp object");
  }

  if (!m_msgCount)
  {
    m_notify_addr = snmp->get_listen_address();
    m_notify_addr.set_port(m_listen_port);

    int status = SNMP_CLASS_SUCCESS;

    // This is the first request to receive notifications
    // Set up the socket for the snmp trap port (162) or the
    // specified port through set_listen_port()
    bool is_v4_address = (m_notify_addr.get_ip_version() == Address::version_ipv4);
    if (is_v4_address)
    {
      struct sockaddr_in mgr_addr;

      // open a socket to be used for the session
      if ((m_notify_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (WSAEHOSTDOWN == werr)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#else
        if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (EHOSTDOWN == errno)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
        cleanup();
        return status;
      }

      // set up the manager socket attributes
      unsigned long inaddr = inet_addr(IpAddress(m_notify_addr).get_printable());
      memset(&mgr_addr, 0, sizeof(mgr_addr));
      mgr_addr.sin_family = AF_INET;
      mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
      mgr_addr.sin_port = htons(m_notify_addr.get_port());
#ifdef CYGPKG_NET_OPENBSD_STACK
      mgr_addr.sin_len = sizeof(mgr_addr);
#endif

      // bind the socket
      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
               sizeof(mgr_addr)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (WSAEADDRINUSE  == werr)
          status = SNMP_CLASS_TL_IN_USE;
        else if (WSAENOBUFS == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (werr == WSAEAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (werr == WSAENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (werr == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
          status = SNMP_CLASS_INTERNAL_ERROR;
#else
        if (EADDRINUSE  == errno)
          status = SNMP_CLASS_TL_IN_USE;
        else if (ENOBUFS == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (errno == EAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (errno == ENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (errno == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
        {
          debugprintf(0, "Uncatched errno value %d, returning internal error.",
                      errno);
          status = SNMP_CLASS_INTERNAL_ERROR;
        }
#endif
        debugprintf(0, "Fatal: could not bind to %s",
                    m_notify_addr.get_printable());
        cleanup();
        return status;
      }

      debugprintf(3, "Bind to %s for notifications, fd %d.",
                  m_notify_addr.get_printable(), m_notify_fd);
    } // is_v4_address
    else
    {
      // not is_v4_address
#ifdef SNMP_PP_IPv6
      // open a socket to be used for the session
      if ((m_notify_fd = socket(AF_INET6, SOCK_DGRAM,0)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (WSAEHOSTDOWN == werr)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#else
        if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (EHOSTDOWN == errno)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
        cleanup();
        return status;
      }

#ifdef NOTIFY_SET_IPV6_V6ONLY
      int on = 1;
      if (setsockopt(m_notify_fd, IPPROTO_IPV6, IPV6_V6ONLY,
		     (char *)&on, sizeof(on)) == -1)
      {
        LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
        LOG("Could not set option IPV6_V6ONLY on notify socket (errno)");
        LOG(errno);
        LOG_END;
      }
      else
      {
        LOG_BEGIN(loggerModuleName, INFO_LOG | 3);
        LOG("Have set IPV6_V6ONLY option on notify socket");
        LOG_END;
      }
#endif

      // set up the manager socket attributes
      struct sockaddr_in6 mgr_addr;
      memset(&mgr_addr, 0, sizeof(mgr_addr));

      unsigned int scope = 0;

      OctetStr addrstr = ((IpAddress &)m_notify_addr).IpAddress::get_printable();

      if (m_notify_addr.has_ipv6_scope())
      {
        scope = m_notify_addr.get_scope();

        int y = addrstr.len() - 1;
        while ((y>0) && (addrstr[y] != '%'))
        {
          addrstr.set_len(addrstr.len() - 1);
          y--;
        }
        if (addrstr[y] == '%')
          addrstr.set_len(addrstr.len() - 1);
      }

      if (inet_pton(AF_INET6, addrstr.get_printable(),
                    &mgr_addr.sin6_addr) < 0)
      {
	LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
        LOG("Notify transport: inet_pton returns (errno) (str)");
        LOG(errno);
        LOG(strerror(errno));
        LOG_END;
        cleanup();
        return SNMP_CLASS_INVALID_ADDRESS;
      }

      mgr_addr.sin6_family = AF_INET6;
      mgr_addr.sin6_port = htons(m_notify_addr.get_port());
      mgr_addr.sin6_scope_id = scope;

      // bind the socket
      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
               sizeof(mgr_addr)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (WSAEADDRINUSE  == werr)
          status = SNMP_CLASS_TL_IN_USE;
        else if (WSAENOBUFS == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (werr == WSAEAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (werr == WSAENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (werr == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
          status = SNMP_CLASS_INTERNAL_ERROR;
#else
        if (EADDRINUSE  == errno)
          status = SNMP_CLASS_TL_IN_USE;
        else if (ENOBUFS == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (errno == EAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (errno == ENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (errno == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
        {
          debugprintf(0, "Uncatched errno value %d, returning internal error.",
                      errno);
          status = SNMP_CLASS_INTERNAL_ERROR;
        }
#endif
        debugprintf(0, "Fatal: could not bind to %s",
                    m_notify_addr.get_printable());
        cleanup();
        return status;
      }
      debugprintf(3, "Bind to %s for notifications, fd %d.",
                  m_notify_addr.get_printable(), m_notify_fd);
#else
      debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
      cleanup();
      return SNMP_CLASS_TL_UNSUPPORTED;
#endif
    } // not is_v4_address
  }

  CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets);

  /*---------------------------------------------------------*/
  /* Insert entry at head of list, done automagically by the */
  /* constructor function, so don't use the return value.    */
  /*---------------------------------------------------------*/
  (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
  m_msgCount++;

  return SNMP_CLASS_SUCCESS;
}
Ejemplo n.º 8
0
// Store the bootCounter of the given engineID in the given file.
int saveBootCounter(const char *fileName,
                    const OctetStr &engineId, const unsigned int boot)
{
  char line[MAX_LINE_LEN];
  char tmpFileName[MAXLENGTH_FILENAME];
  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
  int found = FALSE;
  int len = engineId.len();
  FILE *file_in, *file_out;

  tmpFileName[0] = 0;
  sprintf(tmpFileName, "%s.tmp",fileName);
  if (len > MAXLENGTH_ENGINEID)
  {
    LOG_BEGIN(ERROR_LOG | 3);
    LOG("saveBootCounter: engine id too long, ignoring last bytes (len) (max)");
    LOG(len);
    LOG(MAXLENGTH_ENGINEID);
    LOG_END;

    len = MAXLENGTH_ENGINEID;
  }

  file_in = fopen(fileName, "r");
  if (!file_in)
  {
    file_in = fopen(fileName, "w");
    if (!file_in)
    {
      LOG_BEGIN(ERROR_LOG | 3);
      LOG("saveBootCounter: could not create new file (file)");
      LOG(fileName);
      LOG_END;

      return SNMPv3_FILECREATE_ERROR;
    }

    LOG_BEGIN(INFO_LOG | 3);
    LOG("saveBootCounter: created new file (file)");
    LOG(fileName);
    LOG_END;

    fputs("# \n",file_in);
    fputs("# This file was created by an SNMP++v3 application,\n", file_in);
    fputs("# it is used to store the snmpEngineBoots counters.\n", file_in);
    fputs("# \n",file_in);
    fputs("# Lines starting with '#' are comments.\n", file_in);
    fputs("# The snmpEngineBoots counters are stored as\n", file_in);
    fputs("# <encoded snmpEngineId> <bootCounter>\n", file_in);
    fputs("# \n", file_in);
    fclose(file_in);
    file_in = fopen(fileName, "r");
  }

  file_out = fopen(tmpFileName, "w");

  if ((file_in) && (file_out))
  {
    encodeString(engineId.data(), len, encoded);
    encoded[len*2] = ' ';
    encoded[len*2 + 1] = 0;

    while (fgets(line, MAX_LINE_LEN, file_in))
    {
      line[MAX_LINE_LEN - 1] = 0;
      if (!strncmp(encoded, line, len*2 + 1))
      {
        if (found)
        {
          LOG_BEGIN(WARNING_LOG | 3);
          LOG("saveBootCounter: Removing doubled entry (file) (line)");
          LOG(fileName);
          LOG(line);
          LOG_END;

          continue;
        }
        sprintf(line,"%s%i\n", encoded, boot);
        fputs(line, file_out);
        found = TRUE;
        continue;
      }
      fputs(line, file_out);
    }
    if (!found)
    {
      sprintf(line, "%s%i\n", encoded, boot);
      fputs(line, file_out);
    }
    fclose(file_in);
    fclose(file_out);
#ifdef WIN32
    _unlink(fileName);
#endif
    if (rename(tmpFileName, fileName))
    {
      LOG_BEGIN(ERROR_LOG | 1);
      LOG("saveBootCounter: Failed to rename temporary file (tmp file) (file)");
      LOG(tmpFileName);
      LOG(fileName);
      LOG_END;

      return SNMPv3_FILERENAME_ERROR;
    }

    LOG_BEGIN(INFO_LOG | 5);
    LOG("saveBootCounter: Saved counter (file) (engine id) (boot)");
    LOG(fileName);
    LOG(engineId.get_printable());
    LOG(boot);
    LOG_END;

    return SNMPv3_OK;
  }

  LOG_BEGIN(ERROR_LOG | 1);
  LOG("saveBootCounter: Failed to open both files (file) (tmp file)");
  LOG(fileName);
  LOG(tmpFileName);
  LOG_END;

  return SNMPv3_FILEOPEN_ERROR;
}
Ejemplo n.º 9
0
// Read the bootCounter of the given engineID stored in the given file.
int getBootCounter(const char *fileName,
                   const OctetStr &engineId, unsigned int &boot)
{
  char line[MAX_LINE_LEN];
  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
  int len = engineId.len();

  FILE *file;

  boot = 0;
  file = fopen(fileName, "r");

  if (!file)
  {
    LOG_BEGIN(ERROR_LOG | 1);
    LOG("getBootCounter: Could not open (file)");
    LOG(fileName);
    LOG_END;

    return SNMPv3_FILEOPEN_ERROR;
  }

  if (len > MAXLENGTH_ENGINEID)
  {
    LOG_BEGIN(ERROR_LOG | 3);
    LOG("getBootCounter: engine id too long, ignoring last bytes (len) (max)");
    LOG(len);
    LOG(MAXLENGTH_ENGINEID);
    LOG_END;

    len = MAXLENGTH_ENGINEID;
  }

  encodeString(engineId.data(), len, encoded);
  encoded[2*len]=' ';
  encoded[2*len + 1] = 0;

  while (fgets(line, MAX_LINE_LEN, file))
  {
    line[MAX_LINE_LEN - 1] = 0;
    /* ignore comments */
    if (line[0]=='#')
      continue;

    if (!strncmp(encoded, line, len*2 + 1))
    {
      /* line starts with engineId */
      char* ptr = line;
      /* skip until first space */
      while (*ptr != 0 && *ptr != ' ')
        ptr++;

      if (*ptr == 0)
      {
        fclose(file);

        LOG_BEGIN(ERROR_LOG | 3);
        LOG("getBootCounter: Illegal line: (file) (line)");
        LOG(fileName);
        LOG(line);
        LOG_END;

        return SNMPv3_FILE_ERROR;
      }
      boot = atoi(ptr);
      fclose(file);

      LOG_BEGIN(DEBUG_LOG | 3);
      LOG("getBootCounter: found entry (file) (engine id) (boot counter)");
      LOG(fileName);
      LOG(engineId.get_printable());
      LOG(boot);
      LOG_END;

      return SNMPv3_OK;
    }
  }
  fclose(file);

  LOG_BEGIN(WARNING_LOG | 3);
  LOG("getBootCounter: No entry found (file) (engine id)");
  LOG(fileName);
  LOG(engineId.get_printable());
  LOG_END;

  return SNMPv3_NO_ENTRY_ERROR;
}
Ejemplo n.º 10
0
void* runable(void *data) {
  //--------[ build up SNMP++ object needed ]-------------------------------
  ssync.lock();
  printf("HELLO:%s\n", community.get_printable());
  int t = *((int*)data);
  Pdu pdu;                              // construct a Pdu object
  Vb vb;                                // construct a Vb object
  vb.set_oid("1");                     // set the Oid portion of the Vb
  pdu += vb;                            // add the vb to the Pdu
  CTarget ctarget(address[t]);            // make a target using the address
#ifdef _SNMPv3
  UTarget utarget(address[t]);

  if (version == version3) {
    utarget.set_version( version);          // set the SNMP version SNMPV1 or V2 or V3
    utarget.set_retry( retries);            // set the number of auto retries
    utarget.set_timeout( timeout);          // set timeout
    utarget.set_security_model( securityModel);
    utarget.set_security_name( securityName);
    pdu.set_security_level( securityLevel);
    pdu.set_context_name (contextName);
    pdu.set_context_engine_id(contextEngineID);
  }
  else {
#endif
    ctarget.set_version( version);          // set the SNMP version SNMPV1 or V2 or V3
    ctarget.set_retry( retries);            // set the number of auto retries
    ctarget.set_timeout( timeout);          // set timeout
    ctarget.set_readcommunity( community);  // set the read community to use
    ctarget.set_writecommunity( community);
#ifdef _SNMPv3
  }
#endif

  //-------[ issue the request, blocked mode ]-----------------------------
  cout << "(" << t << "): " 
       << "SNMP++ snmpWalk to " << address[t].get_printable() << " SNMPV" 
#ifdef _SNMPv3
       << ((version==version3) ? (version) : (version+1)) 
#else
       << (version+1) 
#endif
       << " Retries=" << retries
       << " Timeout=" << timeout <<"ms";
#ifdef _SNMPv3
  if (version == version3)
    cout << endl 
	 << "securityName= " << securityName.get_printable()
	 << ", securityLevel= " << securityLevel
	 << ", securityModel= " << securityModel << endl
	 << "contextName= " << contextName.get_printable()
	 << ", contextEngineID= " << contextEngineID.get_printable()
	 << endl;
  else
#endif
    cout << " Community=" << community.get_printable() << endl << flush;

  SnmpTarget *target;
#ifdef _SNMPv3
  if (version == version3)
    target = &utarget;
  else
#endif
    target = &ctarget;

  int status = 0;
  int requests = 0;
  int objects = 0;
  ssync.unlock();
  while (( status = snmp->get_bulk( pdu,*target,0,BULK_MAX))
	 == SNMP_CLASS_SUCCESS)
  {
    requests++;
    ssync.lock();
    for ( int z=0;z<pdu.get_vb_count(); z++) {
      pdu.get_vb( vb,z);
#ifdef _SNMPv3
      if (pdu.get_type() == REPORT_MSG) {
	Oid tmp;
	vb.get_oid(tmp);
	cout << "(" << t << "): " << "Received a reportPdu: "
	     << snmp->error_msg( tmp) 
	     << endl
	     << vb.get_printable_oid() << " = "
	     << vb.get_printable_value() << endl;
	ssync.unlock();
	return 0;
      }
#endif
      objects++;
      // look for var bind exception, applies to v2 only   
      if ( vb.get_syntax() != sNMP_SYNTAX_ENDOFMIBVIEW) {
	cout <<  "(" << t << "): " 
	     << vb.get_printable_oid() << " = ";
	cout << vb.get_printable_value() << "\n";
      }
      else {
	cout <<  "(" << t << "): " 
	     << "End of MIB Reached\n";
	cout <<  "(" << t << "): " 
	     << "Total # of Requests = " << requests << "\n";
	cout <<  "(" << t << "): "
	     << "Total # of Objects  = " << objects  << "\n";
	ssync.unlock();
	return 0;
      }
    }
    ssync.unlock();
    // last vb becomes seed of next rquest
    pdu.set_vblist(&vb, 1);
  }
  if ( status != SNMP_ERROR_NO_SUCH_NAME)
    cout <<  "(" << t << "): "
	 << "SNMP++ snmpWalk Error, " << snmp->error_msg( status) << "\n";
  cout <<  "(" << t << "): "
       << "Total # of Requests = " << requests << "\n";
  cout <<  "(" << t << "): "
       << "Total # of Objects  = " << objects  << "\n";
  return 0;
}  // end Walk 
Ejemplo n.º 11
0
int main_walkThreads_jun( int argc, char **argv)  {

  //---------[ check the arg count ]----------------------------------------
  if ( argc < 2) {
	  cout << "Usage:\n";
	  cout << "snmpWalkThreads host/port [host/port]... [options]\n";
	  cout << "StartOid: 1\n";
	  cout << "options: -v1 , use SNMPV1, default\n";
	  cout << "         -v2 , use SNMPV2\n";
#ifdef _SNMPv3
          cout << "         -v3 , use SNMPV3\n";
#endif
	  cout << "         -pPort , remote port to use\n";
	  cout << "         -CCommunity_name, specify community default is 'public' \n";
	  cout << "         -rN , retries default is N = 1 retry\n";
	  cout << "         -tN , timeout in hundredths of seconds; default is N = 100\n";
#ifdef _SNMPv3
          cout << "         -snSecurityName, " << endl;
          cout << "         -slN , securityLevel to use, default N = 3 = authPriv" << endl;
          cout << "         -smN , securityModel to use, only default N = 3 = USM possible\n";
          cout << "         -cnContextName, default """"" << endl;
          cout << "         -ceContextEngineID, default """"" << endl;
          cout << "         -md5 , use MD5 authentication protocol\n";
          cout << "         -sha , use SHA authentication protocol\n";
          cout << "         -des , use DES privacy protocol\n";
          cout << "         -idea, use IDEA privacy protocol\n";
          cout << "         -aes128, use AES128 privacy protocol\n";
          cout << "         -aes192, use AES192 privacy protocol\n";
          cout << "         -aes256, use AES256 privacy protocol\n";
          cout << "         -uaAuthPassword\n";
          cout << "         -upPrivPassword\n";
#endif
          return 0;
  }

  Snmp::socket_startup();  // Initialize socket subsystem

  //---------[ make a GenAddress and Oid object to retrieve ]---------------
  address[0] = UdpAddress(argv[1]);
  if ( !address[0].valid()) {           // check validity of address
    cout << "Invalid Address or DNS Name, " << argv[1] << "\n";
    return -1;
  }
  int x=2;
  while ((x<argc) && (x<100) && (strstr(argv[x],"-")==0)) {
    address[x-1] = UdpAddress(argv[x]);
    if ( !address[x-1].valid()) {           // check validity of address
      cout << "Invalid Address or DNS Name, " << argv[x] << "\n";
      return -1;
    }     
    x++;
  }
  int threads = x-1;

  cout << community.get_printable() << endl;

   //---------[ determine options to use ]-----------------------------------
   char *ptr;
   for(;x<argc;x++) {                           // parse for version
     if ( strstr( argv[x],"-v2")!= 0) {
       version = version2c;
       continue;
     }
     if ( strstr( argv[x],"-r")!= 0) {                 // parse for retries
       ptr = argv[x]; ptr++; ptr++;
       retries = atoi(ptr);
       if (( retries<0)|| (retries>5)) retries=1; 
       continue;
     }
     if ( strstr( argv[x], "-t")!=0) {                 // parse for timeout
       ptr = argv[x]; ptr++; ptr++;
       timeout = atoi( ptr);
       if (( timeout < 100)||( timeout>500)) timeout=100;
       continue;
     }
     if ( strstr( argv[x],"-C")!=0) {
       ptr = argv[x]; ptr++; ptr++;
       community = ptr;
       continue;
     }
     if ( strstr( argv[x],"-p")!=0) {
       ptr = argv[x]; ptr++; ptr++;
       sscanf(ptr, "%hu", &port);
       continue;
     }

#ifdef _SNMPv3
     if ( strstr( argv[x],"-v3")!= 0) {
       version = version3;
       continue;
     }
     if ( strstr( argv[x],"-idea") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       privProtocol = SNMPv3_usmIDEAPrivProtocol;
       continue;
     }
     if ( strstr( argv[x],"-aes128") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       privProtocol = SNMPv3_usmAES128PrivProtocol;
       continue;
     }
     if ( strstr( argv[x],"-aes192") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       privProtocol = SNMPv3_usmAES192PrivProtocol;
       continue;
     }
     if ( strstr( argv[x],"-aes256") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       privProtocol = SNMPv3_usmAES256PrivProtocol;
       continue;
     }
     if ( strstr( argv[x],"-sha") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       authProtocol = SNMPv3_usmHMACSHAAuthProtocol;
       continue;
     }
     if ( strstr( argv[x],"-des") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       privProtocol = SNMPv3_usmDESPrivProtocol;
       continue;
     }
     if ( strstr( argv[x],"-md5") != 0) {
       ptr = argv[x]; ptr++; ptr++;
       authProtocol = SNMPv3_usmHMACMD5AuthProtocol;
       continue;
     }
     if ( strstr( argv[x],"-sn")!=0) {
       ptr = argv[x]; ptr+=3;
       securityName = ptr;
       continue;
      }
     if ( strstr( argv[x], "-sl")!=0) {
       ptr = argv[x]; ptr+=3;
       securityLevel = atoi( ptr);
       if (( securityLevel < SecurityLevel_noAuthNoPriv) ||
           ( securityLevel > SecurityLevel_authPriv))
         securityLevel = SecurityLevel_authPriv;
       continue;
     }
     if ( strstr( argv[x], "-sm")!=0) {
       ptr = argv[x]; ptr+=3;
       securityModel = atoi( ptr);
       if (( securityModel < SecurityModel_v1) ||
           ( securityModel > SecurityModel_USM))
         securityModel = SecurityModel_USM;
       continue;
     }
     if ( strstr( argv[x],"-cn")!=0) {
       ptr = argv[x]; ptr+=3;
       contextName = ptr;
       continue;
     }
     if ( strstr( argv[x],"-ce")!=0) {
       ptr = argv[x]; ptr+=3;
       contextEngineID = ptr;
       continue;
     }
     if ( strstr( argv[x],"-ua")!=0) {
       ptr = argv[x]; ptr+=3;
       authPassword = ptr;
       continue;
     }
     if ( strstr( argv[x],"-up")!=0) {
       ptr = argv[x]; ptr+=3;
       privPassword = ptr;
       continue;
     }
#endif
   }

   //----------[ create a SNMP++ session ]-----------------------------------
   int status;
   // bind to any port and use IPv6 if enabled
#ifdef SNMP_PP_IPv6
   snmp = new Snmp(status, 0, true);
#else
   snmp = new Snmp(status);
#endif

   if ( status != SNMP_CLASS_SUCCESS) {
     cout << "SNMP++ Session Create Fail, " 
	  << snmp->error_msg(status) << "\n";
     return -3;
   }

#ifdef _SNMPv3
   //---------[ init SnmpV3 ]--------------------------------------------
   v3MP *v3_MP;
   if (version == version3) {
     char *engineId = "snmpWalk";
     char *filename = "snmpv3_boot_counter";
     unsigned int snmpEngineBoots = 0;
     int status;

     status = getBootCounter(filename, engineId, snmpEngineBoots);
     if ((status != SNMPv3_OK) && (status < SNMPv3_FILEOPEN_ERROR))
     {
       cout << "Error loading snmpEngineBoots counter: " << status << endl;
       return 1;
     }
     snmpEngineBoots++;
     status = saveBootCounter(filename, engineId, snmpEngineBoots);
     if (status != SNMPv3_OK)
     {
       cout << "Error saving snmpEngineBoots counter: " << status << endl;
       return 1;
     }

     int construct_status;
     v3_MP = new v3MP(engineId, snmpEngineBoots, construct_status);

     USM *usm = v3_MP->get_usm();
     usm->add_usm_user(securityName,
		       authProtocol, privProtocol,
		       authPassword, privPassword);
   }
   else
   {
     // MUST create a dummy v3MP object if _SNMPv3 is enabled!
     int construct_status;
     v3_MP = new v3MP("dummy", 0, construct_status);
   }
#endif

#ifdef _THREADS
  pthread_t thread[100];
  int started = threads;
#endif

  while (threads) {
#ifdef _THREADS
    if (!attr) {
      attr = new pthread_attr_t;
      pthread_attr_init(attr);
      pthread_attr_setdetachstate(attr, PTHREAD_CREATE_JOINABLE);
    }
    pthread_create(&thread[threads-1], 0, 
		   &runable,
		   (void*)new int(threads-1));
#else
    int n = threads - 1;
    runable(&n);
#endif
    threads--;
  }
#ifdef _THREADS
  // wait for threads to terminate
  for (int i=0; i<started; i++) {
    cout << "JOINING THREAD " << i << endl;
    pthread_join(thread[i], 0);
  }
#endif
  cout << "END" << endl;
  Snmp::socket_cleanup();  // Shut down socket subsystem
}