int main (int argc, char *argv[]) { netsnmp_session session, *ss; netsnmp_pdu *pdu, *response; oid name[MAX_OID_LEN]; size_t name_length; int arg; int status; char *trap = NULL; char *prognam; int exitval = 0; #ifndef NETSNMP_DISABLE_SNMPV1 char *specific = NULL, *description = NULL, *agent = NULL; in_addr_t *pdu_in_addr_t; #endif prognam = strrchr (argv[0], '/'); if (prognam) prognam++; else prognam = argv[0]; putenv (strdup ("POSIXLY_CORRECT=1")); if (strcmp (prognam, "snmpinform") == 0) inform = 1; switch (arg = snmp_parse_args (argc, argv, &session, "C:", optProc)) { case NETSNMP_PARSE_ARGS_ERROR: exit (1); case NETSNMP_PARSE_ARGS_SUCCESS_EXIT: exit (0); case NETSNMP_PARSE_ARGS_ERROR_USAGE: usage (); exit (1); default: break; } SOCK_STARTUP; session.callback = snmp_input; session.callback_magic = NULL; /* * setup the local engineID which may be for either or both of the * contextEngineID and/or the securityEngineID. */ setup_engineID (NULL, NULL); /* if we don't have a contextEngineID set via command line arguments, use our internal engineID as the context. */ if (session.contextEngineIDLen == 0 || session.contextEngineID == NULL) { session.contextEngineID = snmpv3_generate_engineID (&session.contextEngineIDLen); } if (session.version == SNMP_VERSION_3 && !inform) { /* * for traps, we use ourselves as the authoritative engine * which is really stupid since command line apps don't have a * notion of a persistent engine. Hence, our boots and time * values are probably always really wacked with respect to what * a manager would like to see. * * The following should be enough to: * * 1) prevent the library from doing discovery for engineid & time. * 2) use our engineid instead of the remote engineid for * authoritative & privacy related operations. * 3) The remote engine must be configured with users for our engineID. * * -- Wes */ /* * pick our own engineID */ if (session.securityEngineIDLen == 0 || session.securityEngineID == NULL) { session.securityEngineID = snmpv3_generate_engineID (&session.securityEngineIDLen); } /* * set boots and time, which will cause problems if this * machine ever reboots and a remote trap receiver has cached our * boots and time... I'll cause a not-in-time-window report to * be sent back to this machine. */ if (session.engineBoots == 0) session.engineBoots = 1; if (session.engineTime == 0) /* not really correct, */ session.engineTime = get_uptime (); /* but it'll work. Sort of. */ } ss = snmp_add (&session, netsnmp_transport_open_client ("snmptrap", session.peername), NULL, NULL); if (ss == NULL) { /* * diagnose netsnmp_transport_open_client and snmp_add errors with * the input netsnmp_session pointer */ snmp_sess_perror ("snmptrap", &session); SOCK_CLEANUP; exit (1); } #ifndef NETSNMP_DISABLE_SNMPV1 if (session.version == SNMP_VERSION_1) { if (inform) { fprintf (stderr, "Cannot send INFORM as SNMPv1 PDU\n"); SOCK_CLEANUP; exit (1); } pdu = snmp_pdu_create (SNMP_MSG_TRAP); if (!pdu) { fprintf (stderr, "Failed to create trap PDU\n"); SOCK_CLEANUP; exit (1); } pdu_in_addr_t = (in_addr_t *) pdu->agent_addr; if (arg == argc) { fprintf (stderr, "No enterprise oid\n"); usage (); SOCK_CLEANUP; exit (1); } if (argv[arg][0] == 0) { pdu->enterprise = (oid *) malloc (sizeof (objid_enterprise)); memcpy (pdu->enterprise, objid_enterprise, sizeof (objid_enterprise)); pdu->enterprise_length = sizeof (objid_enterprise) / sizeof (oid); } else { name_length = MAX_OID_LEN; if (!snmp_parse_oid (argv[arg], name, &name_length)) { snmp_perror (argv[arg]); usage (); SOCK_CLEANUP; exit (1); } pdu->enterprise = (oid *) malloc (name_length * sizeof (oid)); memcpy (pdu->enterprise, name, name_length * sizeof (oid)); pdu->enterprise_length = name_length; } if (++arg >= argc) { fprintf (stderr, "Missing agent parameter\n"); usage (); SOCK_CLEANUP; exit (1); } agent = argv[arg]; if (agent != NULL && strlen (agent) != 0) { int ret = netsnmp_gethostbyname_v4 (agent, pdu_in_addr_t); if (ret < 0) { fprintf (stderr, "unknown host: %s\n", agent); exit (1); } } else { *pdu_in_addr_t = get_myaddr (); } if (++arg == argc) { fprintf (stderr, "Missing generic-trap parameter\n"); usage (); SOCK_CLEANUP; exit (1); } trap = argv[arg]; pdu->trap_type = atoi (trap); if (++arg == argc) { fprintf (stderr, "Missing specific-trap parameter\n"); usage (); SOCK_CLEANUP; exit (1); } specific = argv[arg]; pdu->specific_type = atoi (specific); if (++arg == argc) { fprintf (stderr, "Missing uptime parameter\n"); usage (); SOCK_CLEANUP; exit (1); } description = argv[arg]; if (description == NULL || *description == 0) pdu->time = get_uptime (); else pdu->time = atol (description); } else #endif { long sysuptime; char csysuptime[20]; pdu = snmp_pdu_create (inform ? SNMP_MSG_INFORM : SNMP_MSG_TRAP2); if (!pdu) { fprintf (stderr, "Failed to create notification PDU\n"); SOCK_CLEANUP; exit (1); } if (arg == argc) { fprintf (stderr, "Missing up-time parameter\n"); usage (); SOCK_CLEANUP; exit (1); } trap = argv[arg]; if (*trap == 0) { sysuptime = get_uptime (); sprintf (csysuptime, "%ld", sysuptime); trap = csysuptime; } snmp_add_var (pdu, objid_sysuptime, sizeof (objid_sysuptime) / sizeof (oid), 't', trap); if (++arg == argc) { fprintf (stderr, "Missing trap-oid parameter\n"); usage (); SOCK_CLEANUP; exit (1); } if (snmp_add_var (pdu, objid_snmptrap, sizeof (objid_snmptrap) / sizeof (oid), 'o', argv[arg]) != 0) { snmp_perror (argv[arg]); SOCK_CLEANUP; exit (1); } } arg++; while (arg < argc) { arg += 3; if (arg > argc) { fprintf (stderr, "%s: Missing type/value for variable\n", argv[arg - 3]); SOCK_CLEANUP; exit (1); } name_length = MAX_OID_LEN; if (!snmp_parse_oid (argv[arg - 3], name, &name_length)) { snmp_perror (argv[arg - 3]); SOCK_CLEANUP; exit (1); } if (snmp_add_var (pdu, name, name_length, argv[arg - 2][0], argv[arg - 1]) != 0) { snmp_perror (argv[arg - 3]); SOCK_CLEANUP; exit (1); } } if (inform) status = snmp_synch_response (ss, pdu, &response); else status = snmp_send (ss, pdu) == 0; if (status) { snmp_sess_perror (inform ? "snmpinform" : "snmptrap", ss); if (!inform) snmp_free_pdu (pdu); exitval = 1; } else if (inform) snmp_free_pdu (response); snmp_close (ss); snmp_shutdown ("snmpapp"); SOCK_CLEANUP; return exitval; }
int netsnmp_sockaddr_in2(struct sockaddr_in *addr, const char *inpeername, const char *default_target) { int ret; if (addr == NULL) { return 0; } DEBUGMSGTL(("netsnmp_sockaddr_in", "addr %p, inpeername \"%s\", default_target \"%s\"\n", addr, inpeername ? inpeername : "[NIL]", default_target ? default_target : "[NIL]")); memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_addr.s_addr = htonl(INADDR_ANY); addr->sin_family = AF_INET; addr->sin_port = htons((u_short)SNMP_PORT); { int port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT); if (port != 0) { addr->sin_port = htons((u_short)port); } else if (default_target != NULL) netsnmp_sockaddr_in2(addr, default_target, NULL); } if (inpeername != NULL && *inpeername != '\0') { const char *host, *port; char *peername = NULL; char *cp; /* * Duplicate the peername because we might want to mank around with * it. */ peername = strdup(inpeername); if (peername == NULL) { return 0; } /* * Try and extract an appended port number. */ cp = strchr(peername, ':'); if (cp != NULL) { *cp = '\0'; port = cp + 1; host = peername; } else { host = NULL; port = peername; } /* * Try to convert the user port specifier */ if (port && *port == '\0') port = NULL; if (port != NULL) { long int l; char* ep; DEBUGMSGTL(("netsnmp_sockaddr_in", "check user service %s\n", port)); l = strtol(port, &ep, 10); if (ep != port && *ep == '\0' && 0 <= l && l <= 0x0ffff) addr->sin_port = htons((u_short)l); else { if (host == NULL) { DEBUGMSGTL(("netsnmp_sockaddr_in", "servname not numeric, " "check if it really is a destination)\n")); host = port; port = NULL; } else { DEBUGMSGTL(("netsnmp_sockaddr_in", "servname not numeric\n")); free(peername); return 0; } } } /* * Try to convert the user host specifier */ if (host && *host == '\0') host = NULL; if (host != NULL) { DEBUGMSGTL(("netsnmp_sockaddr_in", "check destination %s\n", host)); if (strcmp(peername, "255.255.255.255") == 0 ) { /* * The explicit broadcast address hack */ DEBUGMSGTL(("netsnmp_sockaddr_in", "Explicit UDP broadcast\n")); addr->sin_addr.s_addr = INADDR_NONE; } else { ret = netsnmp_gethostbyname_v4(peername, &addr->sin_addr.s_addr); if (ret < 0) { DEBUGMSGTL(("netsnmp_sockaddr_in", "couldn't resolve hostname\n")); free(peername); return 0; } DEBUGMSGTL(("netsnmp_sockaddr_in", "hostname (resolved okay)\n")); } } free(peername); } /* * Finished */ DEBUGMSGTL(("netsnmp_sockaddr_in", "return { AF_INET, %s:%hu }\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port))); return 1; }
/** * This function allows you to make a distinction between generic * traps from different classes of equipment. For example, you may want * to handle a SNMP_TRAP_LINKDOWN trap for a particular device in a * different manner to a generic system SNMP_TRAP_LINKDOWN trap. * * * @param trap is the generic trap type. The trap types are: * - SNMP_TRAP_COLDSTART: * cold start * - SNMP_TRAP_WARMSTART: * warm start * - SNMP_TRAP_LINKDOWN: * link down * - SNMP_TRAP_LINKUP: * link up * - SNMP_TRAP_AUTHFAIL: * authentication failure * - SNMP_TRAP_EGPNEIGHBORLOSS: * egp neighbor loss * - SNMP_TRAP_ENTERPRISESPECIFIC: * enterprise specific * * @param specific is the specific trap value. * * @param enterprise is an enterprise oid in which you want to send specific * traps from. * * @param enterprise_length is the length of the enterprise oid, use macro, * OID_LENGTH, to compute length. * * @param vars is used to supply list of variable bindings to form an SNMPv2 * trap. * * @param context currently unused * * @param flags currently unused * * @return void * * @see send_easy_trap * @see send_v2trap */ int netsnmp_send_traps(int trap, int specific, const oid * enterprise, int enterprise_length, netsnmp_variable_list * vars, const char * context, int flags) { netsnmp_pdu *template_v1pdu; netsnmp_pdu *template_v2pdu; netsnmp_variable_list *vblist = NULL; netsnmp_variable_list *trap_vb; netsnmp_variable_list *var; in_addr_t *pdu_in_addr_t; u_long uptime; struct trap_sink *sink; const char *v1trapaddress; int res = 0; DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific)); DEBUGMSGOID(("trap", enterprise, enterprise_length)); DEBUGMSG(( "trap", "\n")); if (vars) { vblist = snmp_clone_varbind( vars ); if (!vblist) { snmp_log(LOG_WARNING, "send_trap: failed to clone varbind list\n"); return -1; } } if ( trap == -1 ) { /* * Construct the SNMPv2-style notification PDU */ if (!vblist) { snmp_log(LOG_WARNING, "send_trap: called with NULL v2 information\n"); return -1; } template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2); if (!template_v2pdu) { snmp_log(LOG_WARNING, "send_trap: failed to construct v2 template PDU\n"); snmp_free_varbind(vblist); return -1; } /* * Check the varbind list we've been given. * If it starts with a 'sysUptime.0' varbind, then use that. * Otherwise, prepend a suitable 'sysUptime.0' varbind. */ if (!snmp_oid_compare( vblist->name, vblist->name_length, sysuptime_oid, sysuptime_oid_len )) { template_v2pdu->variables = vblist; trap_vb = vblist->next_variable; } else { uptime = netsnmp_get_agent_uptime(); var = NULL; snmp_varlist_add_variable( &var, sysuptime_oid, sysuptime_oid_len, ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime)); if (!var) { snmp_log(LOG_WARNING, "send_trap: failed to insert sysUptime varbind\n"); snmp_free_pdu(template_v2pdu); snmp_free_varbind(vblist); return -1; } template_v2pdu->variables = var; var->next_variable = vblist; trap_vb = vblist; } /* * 'trap_vb' should point to the snmpTrapOID.0 varbind, * identifying the requested trap. If not then bomb out. * If it's a 'standard' trap, then we need to append an * snmpEnterprise varbind (if there isn't already one). */ if (!trap_vb || snmp_oid_compare(trap_vb->name, trap_vb->name_length, snmptrap_oid, snmptrap_oid_len)) { snmp_log(LOG_WARNING, "send_trap: no v2 trapOID varbind provided\n"); snmp_free_pdu(template_v2pdu); return -1; } if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), trap_prefix, OID_LENGTH(trap_prefix))) { var = find_varbind_in_list( template_v2pdu->variables, snmptrapenterprise_oid, snmptrapenterprise_oid_len); if (!var && !snmp_varlist_add_variable( &(template_v2pdu->variables), snmptrapenterprise_oid, snmptrapenterprise_oid_len, ASN_OBJECT_ID, enterprise, enterprise_length*sizeof(oid))) { snmp_log(LOG_WARNING, "send_trap: failed to add snmpEnterprise to v2 trap\n"); snmp_free_pdu(template_v2pdu); return -1; } } /* * If everything's OK, convert the v2 template into an SNMPv1 trap PDU. */ template_v1pdu = convert_v2pdu_to_v1( template_v2pdu ); if (!template_v1pdu) { snmp_log(LOG_WARNING, "send_trap: failed to convert v2->v1 template PDU\n"); } } else { /* * Construct the SNMPv1 trap PDU.... */ template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP); if (!template_v1pdu) { snmp_log(LOG_WARNING, "send_trap: failed to construct v1 template PDU\n"); snmp_free_varbind(vblist); return -1; } template_v1pdu->trap_type = trap; template_v1pdu->specific_type = specific; template_v1pdu->time = netsnmp_get_agent_uptime(); if (snmp_clone_mem((void **) &template_v1pdu->enterprise, enterprise, enterprise_length * sizeof(oid))) { snmp_log(LOG_WARNING, "send_trap: failed to set v1 enterprise OID\n"); snmp_free_varbind(vblist); snmp_free_pdu(template_v1pdu); return -1; } template_v1pdu->enterprise_length = enterprise_length; template_v1pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; template_v1pdu->variables = vblist; /* * ... and convert it into an SNMPv2-style notification PDU. */ template_v2pdu = convert_v1pdu_to_v2( template_v1pdu ); if (!template_v2pdu) { snmp_log(LOG_WARNING, "send_trap: failed to convert v1->v2 template PDU\n"); } } /* * Check whether we're ignoring authFail traps */ if (template_v1pdu) { if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL && snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) { snmp_free_pdu(template_v1pdu); snmp_free_pdu(template_v2pdu); return 0; } /* * Ensure that the v1 trap PDU includes the local IP address */ pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr; v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_TRAP_ADDR); if (v1trapaddress != NULL) { /* "v1trapaddress" was specified in config, try to resolve it */ res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t); } if (v1trapaddress == NULL || res < 0) { /* "v1trapaddress" was not specified in config or the resolution failed, * try any local address */ *pdu_in_addr_t = get_myaddr(); } } /* A context name was provided, so copy it and its length to the v2 pdu * template. */ if (context != NULL) { template_v2pdu->contextName = strdup(context); template_v2pdu->contextNameLen = strlen(context); } /* * Now loop through the list of trap sinks * and call the trap callback routines, * providing an appropriately formatted PDU in each case */ for (sink = sinks; sink; sink = sink->next) { #ifndef NETSNMP_DISABLE_SNMPV1 if (sink->version == SNMP_VERSION_1) { if (template_v1pdu) { send_trap_to_sess(sink->sesp, template_v1pdu); } } else { #endif if (template_v2pdu) { template_v2pdu->command = sink->pdutype; send_trap_to_sess(sink->sesp, template_v2pdu); } #ifndef NETSNMP_DISABLE_SNMPV1 } #endif } if (template_v1pdu) snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu); if (template_v2pdu) snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu); snmp_free_pdu(template_v1pdu); snmp_free_pdu(template_v2pdu); return 0; }