00001 /* 00002 * agent_trap.c 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 00013 */ 00020 #include <net-snmp/net-snmp-config.h> 00021 00022 #if HAVE_UNISTD_H 00023 #include <unistd.h> 00024 #endif 00025 #if HAVE_NETDB_H 00026 #include <netdb.h> 00027 #endif 00028 #if HAVE_STDLIB_H 00029 #include <stdlib.h> 00030 #endif 00031 #if HAVE_STRING_H 00032 #include <string.h> 00033 #else 00034 #include <strings.h> 00035 #endif 00036 #if TIME_WITH_SYS_TIME 00037 # ifdef WIN32 00038 # include <sys/timeb.h> 00039 # else 00040 # include <sys/time.h> 00041 # endif 00042 # include <time.h> 00043 #else 00044 # if HAVE_SYS_TIME_H 00045 # include <sys/time.h> 00046 # else 00047 # include <time.h> 00048 # endif 00049 #endif 00050 #if HAVE_SYS_SOCKET_H 00051 #include <sys/socket.h> 00052 #elif HAVE_WINSOCK_H 00053 #include <winsock.h> 00054 #endif 00055 #if HAVE_NETINET_IN_H 00056 #include <netinet/in.h> 00057 #endif 00058 #include <net-snmp/utilities.h> 00059 00060 #include <net-snmp/net-snmp-includes.h> 00061 #include <net-snmp/agent/net-snmp-agent-includes.h> 00062 #include <net-snmp/agent/agent_trap.h> 00063 #include <net-snmp/agent/snmp_agent.h> 00064 #include <net-snmp/agent/agent_callbacks.h> 00065 00066 #include <net-snmp/agent/agent_module_config.h> 00067 #include <net-snmp/agent/mib_module_config.h> 00068 00069 #ifdef USING_AGENTX_PROTOCOL_MODULE 00070 #include "agentx/protocol.h" 00071 #endif 00072 00073 struct trap_sink { 00074 netsnmp_session *sesp; 00075 struct trap_sink *next; 00076 int pdutype; 00077 int version; 00078 }; 00079 00080 struct trap_sink *sinks = NULL; 00081 00082 extern struct timeval starttime; 00083 00084 oid objid_enterprisetrap[] = { NETSNMP_NOTIFICATION_MIB }; 00085 oid trap_version_id[] = { NETSNMP_SYSTEM_MIB }; 00086 int enterprisetrap_len; 00087 int trap_version_id_len; 00088 00089 #define SNMPV2_TRAPS_PREFIX SNMP_OID_SNMPMODULES,1,1,5 00090 oid trap_prefix[] = { SNMPV2_TRAPS_PREFIX }; 00091 oid cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 }; /* SNMPv2-MIB */ 00092 oid warm_start_oid[] = { SNMPV2_TRAPS_PREFIX, 2 }; /* SNMPv2-MIB */ 00093 oid link_down_oid[] = { SNMPV2_TRAPS_PREFIX, 3 }; /* IF-MIB */ 00094 oid link_up_oid[] = { SNMPV2_TRAPS_PREFIX, 4 }; /* IF-MIB */ 00095 oid auth_fail_oid[] = { SNMPV2_TRAPS_PREFIX, 5 }; /* SNMPv2-MIB */ 00096 oid egp_xxx_oid[] = { SNMPV2_TRAPS_PREFIX, 99 }; /* ??? */ 00097 00098 #define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4 00099 oid snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 }; 00100 oid snmptrapenterprise_oid[] = 00101 { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 }; 00102 oid sysuptime_oid[] = { SNMP_OID_MIB2, 1, 3, 0 }; 00103 size_t snmptrap_oid_len; 00104 size_t snmptrapenterprise_oid_len; 00105 size_t sysuptime_oid_len; 00106 00107 #define SNMPV2_COMM_OBJS_PREFIX SNMP_OID_SNMPMODULES,18,1 00108 oid agentaddr_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 3, 0 }; 00109 size_t agentaddr_oid_len; 00110 oid community_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 4, 0 }; 00111 size_t community_oid_len; 00112 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 00113 char *snmp_trapcommunity = NULL; 00114 #endif 00115 00116 00117 #define SNMP_AUTHENTICATED_TRAPS_ENABLED 1 00118 #define SNMP_AUTHENTICATED_TRAPS_DISABLED 2 00119 00120 int snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED; 00121 int snmp_enableauthentrapsset = 0; 00122 00123 /* 00124 * Prototypes 00125 */ 00126 /* 00127 * static int create_v1_trap_session (const char *, u_short, const char *); 00128 * static int create_v2_trap_session (const char *, u_short, const char *); 00129 * static int create_v2_inform_session (const char *, u_short, const char *); 00130 * static void free_trap_session (struct trap_sink *sp); 00131 * static void send_v1_trap (netsnmp_session *, int, int); 00132 * static void send_v2_trap (netsnmp_session *, int, int, int); 00133 */ 00134 00135 00136 /******************* 00137 * 00138 * Trap session handling 00139 * 00140 *******************/ 00141 00142 void 00143 init_traps(void) 00144 { 00145 enterprisetrap_len = OID_LENGTH(objid_enterprisetrap); 00146 trap_version_id_len = OID_LENGTH(trap_version_id); 00147 snmptrap_oid_len = OID_LENGTH(snmptrap_oid); 00148 snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid); 00149 sysuptime_oid_len = OID_LENGTH(sysuptime_oid); 00150 agentaddr_oid_len = OID_LENGTH(agentaddr_oid); 00151 community_oid_len = OID_LENGTH(community_oid); 00152 } 00153 00154 static void 00155 free_trap_session(struct trap_sink *sp) 00156 { 00157 DEBUGMSGTL(("trap", "freeing callback trap session (%p, %p)\n", sp, sp->sesp)); 00158 snmp_close(sp->sesp); 00159 free(sp); 00160 } 00161 00162 int 00163 add_trap_session(netsnmp_session * ss, int pdutype, int confirm, 00164 int version) 00165 { 00166 if (snmp_callback_available(SNMP_CALLBACK_APPLICATION, 00167 SNMPD_CALLBACK_REGISTER_NOTIFICATIONS) == 00168 SNMPERR_SUCCESS) { 00169 /* 00170 * something else wants to handle notification registrations 00171 */ 00172 struct agent_add_trap_args args; 00173 DEBUGMSGTL(("trap", "adding callback trap sink (%p)\n", ss)); 00174 args.ss = ss; 00175 args.confirm = confirm; 00176 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00177 SNMPD_CALLBACK_REGISTER_NOTIFICATIONS, 00178 (void *) &args); 00179 } else { 00180 /* 00181 * no other support exists, handle it ourselves. 00182 */ 00183 struct trap_sink *new_sink; 00184 00185 DEBUGMSGTL(("trap", "adding internal trap sink\n")); 00186 new_sink = (struct trap_sink *) malloc(sizeof(*new_sink)); 00187 if (new_sink == NULL) 00188 return 0; 00189 00190 new_sink->sesp = ss; 00191 new_sink->pdutype = pdutype; 00192 new_sink->version = version; 00193 new_sink->next = sinks; 00194 sinks = new_sink; 00195 } 00196 return 1; 00197 } 00198 00199 int 00200 remove_trap_session(netsnmp_session * ss) 00201 { 00202 struct trap_sink *sp = sinks, *prev = NULL; 00203 00204 DEBUGMSGTL(("trap", "removing trap sessions\n")); 00205 while (sp) { 00206 if (sp->sesp == ss) { 00207 if (prev) { 00208 prev->next = sp->next; 00209 } else { 00210 sinks = sp->next; 00211 } 00212 /* 00213 * I don't believe you *really* want to close the session here; 00214 * it may still be in use for other purposes. In particular this 00215 * is awkward for AgentX, since we want to call this function 00216 * from the session's callback. Let's just free the trapsink 00217 * data structure. [jbpn] 00218 */ 00219 /* 00220 * free_trap_session(sp); 00221 */ 00222 DEBUGMSGTL(("trap", "removing trap session (%p, %p)\n", sp, sp->sesp)); 00223 free(sp); 00224 return 1; 00225 } 00226 prev = sp; 00227 sp = sp->next; 00228 } 00229 return 0; 00230 } 00231 00232 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 00233 static int 00234 create_trap_session2(const char *sink, const char* sinkport, 00235 char *com, int version, int pdutype) 00236 { 00237 netsnmp_transport *t; 00238 netsnmp_session session, *sesp; 00239 00240 memset(&session, 0, sizeof(netsnmp_session)); 00241 session.version = version; 00242 if (com) { 00243 session.community = (u_char *) com; 00244 session.community_len = strlen(com); 00245 } 00246 00247 /* 00248 * for informs, set retries to default 00249 */ 00250 if (SNMP_MSG_INFORM == pdutype) { 00251 session.timeout = SNMP_DEFAULT_TIMEOUT; 00252 session.retries = SNMP_DEFAULT_RETRIES; 00253 } 00254 00255 /* 00256 * if the sink is localhost, bind to localhost, to reduce open ports. 00257 */ 00258 if ((NULL == netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00259 NETSNMP_DS_LIB_CLIENT_ADDR)) && 00260 ((0 == strcmp("localhost",sink)) || (0 == strcmp("127.0.0.1",sink)))) 00261 session.localname = strdup("localhost"); 00262 00263 t = netsnmp_tdomain_transport_full("snmptrap", sink, 0, NULL, sinkport); 00264 if (t != NULL) { 00265 sesp = snmp_add(&session, t, NULL, NULL); 00266 00267 if (sesp) { 00268 return add_trap_session(sesp, pdutype, 00269 (pdutype == SNMP_MSG_INFORM), version); 00270 } 00271 } 00272 /* 00273 * diagnose snmp_open errors with the input netsnmp_session pointer 00274 */ 00275 snmp_sess_perror("snmpd: create_trap_session", &session); 00276 return 0; 00277 } 00278 00279 int 00280 create_trap_session(char *sink, u_short sinkport, 00281 char *com, int version, int pdutype) 00282 { 00283 char buf[sizeof(sinkport) * 3 + 2]; 00284 if (sinkport != 0) { 00285 sprintf(buf, ":%hu", sinkport); 00286 snmp_log(LOG_NOTICE, 00287 "Using a separate port number is deprecated, please correct " 00288 "the sink specification instead"); 00289 } 00290 return create_trap_session2(sink, sinkport ? buf : NULL, com, version, 00291 pdutype); 00292 } 00293 00294 #endif /* support for community based SNMP */ 00295 00296 #ifndef NETSNMP_DISABLE_SNMPV1 00297 static int 00298 create_v1_trap_session(char *sink, const char *sinkport, char *com) 00299 { 00300 return create_trap_session2(sink, sinkport, com, 00301 SNMP_VERSION_1, SNMP_MSG_TRAP); 00302 } 00303 #endif 00304 00305 #ifndef NETSNMP_DISABLE_SNMPV2C 00306 static int 00307 create_v2_trap_session(const char *sink, const char *sinkport, char *com) 00308 { 00309 return create_trap_session2(sink, sinkport, com, 00310 SNMP_VERSION_2c, SNMP_MSG_TRAP2); 00311 } 00312 00313 static int 00314 create_v2_inform_session(const char *sink, const char *sinkport, char *com) 00315 { 00316 return create_trap_session2(sink, sinkport, com, 00317 SNMP_VERSION_2c, SNMP_MSG_INFORM); 00318 } 00319 #endif 00320 00321 void 00322 snmpd_free_trapsinks(void) 00323 { 00324 struct trap_sink *sp = sinks; 00325 DEBUGMSGTL(("trap", "freeing trap sessions\n")); 00326 while (sp) { 00327 sinks = sinks->next; 00328 free_trap_session(sp); 00329 sp = sinks; 00330 } 00331 } 00332 00333 /******************* 00334 * 00335 * Trap handling 00336 * 00337 *******************/ 00338 00339 00340 netsnmp_pdu* 00341 convert_v2pdu_to_v1( netsnmp_pdu* template_v2pdu ) 00342 { 00343 netsnmp_pdu *template_v1pdu; 00344 netsnmp_variable_list *first_vb, *vblist; 00345 netsnmp_variable_list *var; 00346 00347 /* 00348 * Make a copy of the v2 Trap PDU 00349 * before starting to convert this 00350 * into a v1 Trap PDU. 00351 */ 00352 template_v1pdu = snmp_clone_pdu( template_v2pdu); 00353 if (!template_v1pdu) { 00354 snmp_log(LOG_WARNING, 00355 "send_trap: failed to copy v1 template PDU\n"); 00356 return NULL; 00357 } 00358 template_v1pdu->command = SNMP_MSG_TRAP; 00359 first_vb = template_v1pdu->variables; 00360 vblist = template_v1pdu->variables; 00361 00362 /* 00363 * The first varbind should be the system uptime. 00364 */ 00365 if (!vblist || 00366 snmp_oid_compare(vblist->name, vblist->name_length, 00367 sysuptime_oid, sysuptime_oid_len)) { 00368 snmp_log(LOG_WARNING, 00369 "send_trap: no v2 sysUptime varbind to set from\n"); 00370 snmp_free_pdu(template_v1pdu); 00371 return NULL; 00372 } 00373 template_v1pdu->time = *vblist->val.integer; 00374 vblist = vblist->next_variable; 00375 00376 /* 00377 * The second varbind should be the snmpTrapOID. 00378 */ 00379 if (!vblist || 00380 snmp_oid_compare(vblist->name, vblist->name_length, 00381 snmptrap_oid, snmptrap_oid_len)) { 00382 snmp_log(LOG_WARNING, 00383 "send_trap: no v2 trapOID varbind to set from\n"); 00384 snmp_free_pdu(template_v1pdu); 00385 return NULL; 00386 } 00387 00388 /* 00389 * Check the v2 varbind list for any varbinds 00390 * that are not valid in an SNMPv1 trap. 00391 * This basically means Counter64 values. 00392 * 00393 * RFC 2089 said to omit such varbinds from the list. 00394 * RFC 2576/3584 say to drop the trap completely. 00395 */ 00396 for (var = vblist->next_variable; var; var = var->next_variable) { 00397 if ( var->type == ASN_COUNTER64 ) { 00398 snmp_log(LOG_WARNING, 00399 "send_trap: v1 traps can't carry Counter64 varbinds\n"); 00400 snmp_free_pdu(template_v1pdu); 00401 return NULL; 00402 } 00403 } 00404 00405 /* 00406 * Set the generic & specific trap types, 00407 * and the enterprise field from the v2 varbind list. 00408 * If there's an agentIPAddress varbind, set the agent_addr too 00409 */ 00410 if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), 00411 trap_prefix, OID_LENGTH(trap_prefix))) { 00412 /* 00413 * For 'standard' traps, extract the generic trap type 00414 * from the snmpTrapOID value, and take the enterprise 00415 * value from the 'snmpEnterprise' varbind. 00416 */ 00417 template_v1pdu->trap_type = 00418 vblist->val.objid[OID_LENGTH(trap_prefix)] - 1; 00419 template_v1pdu->specific_type = 0; 00420 00421 var = find_varbind_in_list( vblist, 00422 snmptrapenterprise_oid, 00423 snmptrapenterprise_oid_len); 00424 if (var) { 00425 template_v1pdu->enterprise_length = var->val_len/sizeof(oid); 00426 template_v1pdu->enterprise = 00427 snmp_duplicate_objid(var->val.objid, 00428 template_v1pdu->enterprise_length); 00429 } else { 00430 template_v1pdu->enterprise = NULL; 00431 template_v1pdu->enterprise_length = 0; /* XXX ??? */ 00432 } 00433 } else { 00434 /* 00435 * For enterprise-specific traps, split the snmpTrapOID value 00436 * into enterprise and specific trap 00437 */ 00438 size_t len = vblist->val_len / sizeof(oid); 00439 if ( len <= 2 ) { 00440 snmp_log(LOG_WARNING, 00441 "send_trap: v2 trapOID too short (%d)\n", (int)len); 00442 snmp_free_pdu(template_v1pdu); 00443 return NULL; 00444 } 00445 template_v1pdu->trap_type = SNMP_TRAP_ENTERPRISESPECIFIC; 00446 template_v1pdu->specific_type = vblist->val.objid[len - 1]; 00447 len--; 00448 if (vblist->val.objid[len-1] == 0) 00449 len--; 00450 SNMP_FREE(template_v1pdu->enterprise); 00451 template_v1pdu->enterprise = 00452 snmp_duplicate_objid(vblist->val.objid, len); 00453 template_v1pdu->enterprise_length = len; 00454 } 00455 var = find_varbind_in_list( vblist, agentaddr_oid, 00456 agentaddr_oid_len); 00457 if (var) { 00458 memcpy(template_v1pdu->agent_addr, 00459 var->val.string, 4); 00460 } 00461 00462 /* 00463 * The remainder of the v2 varbind list is kept 00464 * as the v2 varbind list. Update the PDU and 00465 * free the two redundant varbinds. 00466 */ 00467 template_v1pdu->variables = vblist->next_variable; 00468 vblist->next_variable = NULL; 00469 snmp_free_varbind( first_vb ); 00470 00471 return template_v1pdu; 00472 } 00473 00474 netsnmp_pdu* 00475 convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu ) 00476 { 00477 netsnmp_pdu *template_v2pdu; 00478 netsnmp_variable_list *first_vb; 00479 netsnmp_variable_list *var; 00480 oid enterprise[MAX_OID_LEN]; 00481 size_t enterprise_len; 00482 00483 /* 00484 * Make a copy of the v1 Trap PDU 00485 * before starting to convert this 00486 * into a v2 Trap PDU. 00487 */ 00488 template_v2pdu = snmp_clone_pdu( template_v1pdu); 00489 if (!template_v2pdu) { 00490 snmp_log(LOG_WARNING, 00491 "send_trap: failed to copy v2 template PDU\n"); 00492 return NULL; 00493 } 00494 template_v2pdu->command = SNMP_MSG_TRAP2; 00495 first_vb = template_v2pdu->variables; 00496 00497 /* 00498 * Insert an snmpTrapOID varbind before the original v1 varbind list 00499 * either using one of the standard defined trap OIDs, 00500 * or constructing this from the PDU enterprise & specific trap fields 00501 */ 00502 if (template_v1pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) { 00503 memcpy(enterprise, template_v1pdu->enterprise, 00504 template_v1pdu->enterprise_length*sizeof(oid)); 00505 enterprise_len = template_v1pdu->enterprise_length; 00506 enterprise[enterprise_len++] = 0; 00507 enterprise[enterprise_len++] = template_v1pdu->specific_type; 00508 } else { 00509 memcpy(enterprise, cold_start_oid, sizeof(cold_start_oid)); 00510 enterprise[9] = template_v1pdu->trap_type+1; 00511 enterprise_len = sizeof(cold_start_oid)/sizeof(oid); 00512 } 00513 00514 var = NULL; 00515 if (!snmp_varlist_add_variable( &var, 00516 snmptrap_oid, snmptrap_oid_len, 00517 ASN_OBJECT_ID, 00518 (u_char*)enterprise, enterprise_len*sizeof(oid))) { 00519 snmp_log(LOG_WARNING, 00520 "send_trap: failed to insert copied snmpTrapOID varbind\n"); 00521 snmp_free_pdu(template_v2pdu); 00522 return NULL; 00523 } 00524 var->next_variable = template_v2pdu->variables; 00525 template_v2pdu->variables = var; 00526 00527 /* 00528 * Insert a sysUptime varbind at the head of the v2 varbind list 00529 */ 00530 var = NULL; 00531 if (!snmp_varlist_add_variable( &var, 00532 sysuptime_oid, sysuptime_oid_len, 00533 ASN_TIMETICKS, 00534 (u_char*)&(template_v1pdu->time), 00535 sizeof(template_v1pdu->time))) { 00536 snmp_log(LOG_WARNING, 00537 "send_trap: failed to insert copied sysUptime varbind\n"); 00538 snmp_free_pdu(template_v2pdu); 00539 return NULL; 00540 } 00541 var->next_variable = template_v2pdu->variables; 00542 template_v2pdu->variables = var; 00543 00544 /* 00545 * Append the other three conversion varbinds, 00546 * (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise) 00547 * if they're not already present. 00548 * But don't bomb out completely if there are problems. 00549 */ 00550 var = find_varbind_in_list( template_v2pdu->variables, 00551 agentaddr_oid, agentaddr_oid_len); 00552 if (!var && (template_v1pdu->agent_addr[0] 00553 || template_v1pdu->agent_addr[1] 00554 || template_v1pdu->agent_addr[2] 00555 || template_v1pdu->agent_addr[3])) { 00556 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00557 agentaddr_oid, agentaddr_oid_len, 00558 ASN_IPADDRESS, 00559 (u_char*)&(template_v1pdu->agent_addr), 00560 sizeof(template_v1pdu->agent_addr))) 00561 snmp_log(LOG_WARNING, 00562 "send_trap: failed to append snmpTrapAddr varbind\n"); 00563 } 00564 var = find_varbind_in_list( template_v2pdu->variables, 00565 community_oid, community_oid_len); 00566 if (!var && template_v1pdu->community) { 00567 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00568 community_oid, community_oid_len, 00569 ASN_OCTET_STR, 00570 template_v1pdu->community, 00571 template_v1pdu->community_len)) 00572 snmp_log(LOG_WARNING, 00573 "send_trap: failed to append snmpTrapCommunity varbind\n"); 00574 } 00575 var = find_varbind_in_list( template_v2pdu->variables, 00576 snmptrapenterprise_oid, 00577 snmptrapenterprise_oid_len); 00578 if (!var) { 00579 if (!snmp_varlist_add_variable( &(template_v2pdu->variables), 00580 snmptrapenterprise_oid, snmptrapenterprise_oid_len, 00581 ASN_OBJECT_ID, 00582 (u_char*)template_v1pdu->enterprise, 00583 template_v1pdu->enterprise_length*sizeof(oid))) 00584 snmp_log(LOG_WARNING, 00585 "send_trap: failed to append snmpEnterprise varbind\n"); 00586 } 00587 return template_v2pdu; 00588 } 00589 00633 int 00634 netsnmp_send_traps(int trap, int specific, 00635 oid * enterprise, int enterprise_length, 00636 netsnmp_variable_list * vars, 00637 char * context, int flags) 00638 { 00639 netsnmp_pdu *template_v1pdu; 00640 netsnmp_pdu *template_v2pdu; 00641 netsnmp_variable_list *vblist = NULL; 00642 netsnmp_variable_list *trap_vb; 00643 netsnmp_variable_list *var; 00644 in_addr_t *pdu_in_addr_t; 00645 u_long uptime; 00646 struct trap_sink *sink; 00647 const char *v1trapaddress; 00648 int res; 00649 00650 DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific)); 00651 DEBUGMSGOID(("trap", enterprise, enterprise_length)); 00652 DEBUGMSG(( "trap", "\n")); 00653 00654 if (vars) { 00655 vblist = snmp_clone_varbind( vars ); 00656 if (!vblist) { 00657 snmp_log(LOG_WARNING, 00658 "send_trap: failed to clone varbind list\n"); 00659 return -1; 00660 } 00661 } 00662 00663 if ( trap == -1 ) { 00664 /* 00665 * Construct the SNMPv2-style notification PDU 00666 */ 00667 if (!vblist) { 00668 snmp_log(LOG_WARNING, 00669 "send_trap: called with NULL v2 information\n"); 00670 return -1; 00671 } 00672 template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2); 00673 if (!template_v2pdu) { 00674 snmp_log(LOG_WARNING, 00675 "send_trap: failed to construct v2 template PDU\n"); 00676 snmp_free_varbind(vblist); 00677 return -1; 00678 } 00679 00680 /* 00681 * Check the varbind list we've been given. 00682 * If it starts with a 'sysUptime.0' varbind, then use that. 00683 * Otherwise, prepend a suitable 'sysUptime.0' varbind. 00684 */ 00685 if (!snmp_oid_compare( vblist->name, vblist->name_length, 00686 sysuptime_oid, sysuptime_oid_len )) { 00687 template_v2pdu->variables = vblist; 00688 trap_vb = vblist->next_variable; 00689 } else { 00690 uptime = netsnmp_get_agent_uptime(); 00691 var = NULL; 00692 snmp_varlist_add_variable( &var, 00693 sysuptime_oid, sysuptime_oid_len, 00694 ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime)); 00695 if (!var) { 00696 snmp_log(LOG_WARNING, 00697 "send_trap: failed to insert sysUptime varbind\n"); 00698 snmp_free_pdu(template_v2pdu); 00699 snmp_free_varbind(vblist); 00700 return -1; 00701 } 00702 template_v2pdu->variables = var; 00703 var->next_variable = vblist; 00704 trap_vb = vblist; 00705 } 00706 00707 /* 00708 * 'trap_vb' should point to the snmpTrapOID.0 varbind, 00709 * identifying the requested trap. If not then bomb out. 00710 * If it's a 'standard' trap, then we need to append an 00711 * snmpEnterprise varbind (if there isn't already one). 00712 */ 00713 if (!trap_vb || 00714 snmp_oid_compare(trap_vb->name, trap_vb->name_length, 00715 snmptrap_oid, snmptrap_oid_len)) { 00716 snmp_log(LOG_WARNING, 00717 "send_trap: no v2 trapOID varbind provided\n"); 00718 snmp_free_pdu(template_v2pdu); 00719 return -1; 00720 } 00721 if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix), 00722 trap_prefix, OID_LENGTH(trap_prefix))) { 00723 var = find_varbind_in_list( template_v2pdu->variables, 00724 snmptrapenterprise_oid, 00725 snmptrapenterprise_oid_len); 00726 if (!var && 00727 !snmp_varlist_add_variable( &(template_v2pdu->variables), 00728 snmptrapenterprise_oid, snmptrapenterprise_oid_len, 00729 ASN_OBJECT_ID, 00730 (char*)enterprise, enterprise_length*sizeof(oid))) { 00731 snmp_log(LOG_WARNING, 00732 "send_trap: failed to add snmpEnterprise to v2 trap\n"); 00733 snmp_free_pdu(template_v2pdu); 00734 return -1; 00735 } 00736 } 00737 00738 00739 /* 00740 * If everything's OK, convert the v2 template into an SNMPv1 trap PDU. 00741 */ 00742 template_v1pdu = convert_v2pdu_to_v1( template_v2pdu ); 00743 if (!template_v1pdu) { 00744 snmp_log(LOG_WARNING, 00745 "send_trap: failed to convert v2->v1 template PDU\n"); 00746 } 00747 00748 } else { 00749 /* 00750 * Construct the SNMPv1 trap PDU.... 00751 */ 00752 template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP); 00753 if (!template_v1pdu) { 00754 snmp_log(LOG_WARNING, 00755 "send_trap: failed to construct v1 template PDU\n"); 00756 snmp_free_varbind(vblist); 00757 return -1; 00758 } 00759 template_v1pdu->trap_type = trap; 00760 template_v1pdu->specific_type = specific; 00761 template_v1pdu->time = netsnmp_get_agent_uptime(); 00762 00763 if (snmp_clone_mem((void **) &template_v1pdu->enterprise, 00764 enterprise, enterprise_length * sizeof(oid))) { 00765 snmp_log(LOG_WARNING, 00766 "send_trap: failed to set v1 enterprise OID\n"); 00767 snmp_free_varbind(vblist); 00768 snmp_free_pdu(template_v1pdu); 00769 return -1; 00770 } 00771 template_v1pdu->enterprise_length = enterprise_length; 00772 00773 template_v1pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY; 00774 template_v1pdu->variables = vblist; 00775 00776 /* 00777 * ... and convert it into an SNMPv2-style notification PDU. 00778 */ 00779 00780 template_v2pdu = convert_v1pdu_to_v2( template_v1pdu ); 00781 if (!template_v2pdu) { 00782 snmp_log(LOG_WARNING, 00783 "send_trap: failed to convert v1->v2 template PDU\n"); 00784 } 00785 } 00786 00787 /* 00788 * Check whether we're ignoring authFail traps 00789 */ 00790 if (template_v1pdu) { 00791 if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL && 00792 snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) { 00793 snmp_free_pdu(template_v1pdu); 00794 snmp_free_pdu(template_v2pdu); 00795 return 0; 00796 } 00797 00798 /* 00799 * Ensure that the v1 trap PDU includes the local IP address 00800 */ 00801 pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr; 00802 v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 00803 NETSNMP_DS_AGENT_TRAP_ADDR); 00804 if (v1trapaddress != NULL) { 00805 /* "v1trapaddress" was specified in config, try to resolve it */ 00806 res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t); 00807 } 00808 if (v1trapaddress == NULL || res < 0) { 00809 /* "v1trapaddress" was not specified in config or the resolution failed, 00810 * try any local address */ 00811 *pdu_in_addr_t = get_myaddr(); 00812 } 00813 00814 } 00815 00816 /* A context name was provided, so copy it and its length to the v2 pdu 00817 * template. */ 00818 if (context != NULL) 00819 { 00820 template_v2pdu->contextName = strdup(context); 00821 template_v2pdu->contextNameLen = strlen(context); 00822 } 00823 00824 /* 00825 * Now loop through the list of trap sinks 00826 * and call the trap callback routines, 00827 * providing an appropriately formatted PDU in each case 00828 */ 00829 for (sink = sinks; sink; sink = sink->next) { 00830 #ifndef NETSNMP_DISABLE_SNMPV1 00831 if (sink->version == SNMP_VERSION_1) { 00832 if (template_v1pdu) { 00833 send_trap_to_sess(sink->sesp, template_v1pdu); 00834 } 00835 } else { 00836 #endif 00837 if (template_v2pdu) { 00838 template_v2pdu->command = sink->pdutype; 00839 send_trap_to_sess(sink->sesp, template_v2pdu); 00840 } 00841 #ifndef NETSNMP_DISABLE_SNMPV1 00842 } 00843 #endif 00844 } 00845 if (template_v1pdu) 00846 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00847 SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu); 00848 if (template_v2pdu) 00849 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00850 SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu); 00851 snmp_free_pdu(template_v1pdu); 00852 snmp_free_pdu(template_v2pdu); 00853 return 0; 00854 } 00855 00856 00857 void 00858 send_enterprise_trap_vars(int trap, 00859 int specific, 00860 oid * enterprise, int enterprise_length, 00861 netsnmp_variable_list * vars) 00862 { 00863 netsnmp_send_traps(trap, specific, 00864 enterprise, enterprise_length, 00865 vars, NULL, 0); 00866 return; 00867 } 00868 00874 int 00875 handle_inform_response(int op, netsnmp_session * session, 00876 int reqid, netsnmp_pdu *pdu, 00877 void *magic) 00878 { 00879 /* XXX: possibly stats update */ 00880 switch (op) { 00881 00882 case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: 00883 snmp_increment_statistic(STAT_SNMPINPKTS); 00884 DEBUGMSGTL(("trap", "received the inform response for reqid=%d\n", 00885 reqid)); 00886 break; 00887 00888 case NETSNMP_CALLBACK_OP_TIMED_OUT: 00889 DEBUGMSGTL(("trap", 00890 "received a timeout sending an inform for reqid=%d\n", 00891 reqid)); 00892 break; 00893 00894 case NETSNMP_CALLBACK_OP_SEND_FAILED: 00895 DEBUGMSGTL(("trap", 00896 "failed to send an inform for reqid=%d\n", 00897 reqid)); 00898 break; 00899 00900 default: 00901 DEBUGMSGTL(("trap", "received op=%d for reqid=%d when trying to send an inform\n", op, reqid)); 00902 } 00903 00904 return 1; 00905 } 00906 00907 00908 /* 00909 * send_trap_to_sess: sends a trap to a session but assumes that the 00910 * pdu is constructed correctly for the session type. 00911 */ 00912 void 00913 send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu) 00914 { 00915 netsnmp_pdu *pdu; 00916 int result; 00917 char tmp[SPRINT_MAX_LEN]; 00918 int len; 00919 00920 00921 if (!sess || !template_pdu) 00922 return; 00923 00924 DEBUGMSGTL(("trap", "sending trap type=%d, version=%ld\n", 00925 template_pdu->command, sess->version)); 00926 00927 #ifndef NETSNMP_DISABLE_SNMPV1 00928 if (sess->version == SNMP_VERSION_1 && 00929 (template_pdu->command != SNMP_MSG_TRAP)) 00930 return; /* Skip v1 sinks for v2 only traps */ 00931 if (sess->version != SNMP_VERSION_1 && 00932 (template_pdu->command == SNMP_MSG_TRAP)) 00933 return; /* Skip v2+ sinks for v1 only traps */ 00934 #endif 00935 template_pdu->version = sess->version; 00936 pdu = snmp_clone_pdu(template_pdu); 00937 pdu->sessid = sess->sessid; /* AgentX only ? */ 00938 00939 if ( template_pdu->command == SNMP_MSG_INFORM 00940 #ifdef USING_AGENTX_PROTOCOL_MODULE 00941 || template_pdu->command == AGENTX_MSG_NOTIFY 00942 #endif 00943 ) { 00944 result = 00945 snmp_async_send(sess, pdu, &handle_inform_response, NULL); 00946 00947 } else { 00948 if ((sess->version == SNMP_VERSION_3) && 00949 (pdu->command == SNMP_MSG_TRAP2) && 00950 (pdu->securityEngineIDLen == 0)) { 00951 len = snmpv3_get_engineID(tmp, sizeof(tmp)); 00952 memdup(&pdu->securityEngineID, tmp, len); 00953 pdu->securityEngineIDLen = len; 00954 } 00955 00956 result = snmp_send(sess, pdu); 00957 } 00958 00959 if (result == 0) { 00960 snmp_sess_perror("snmpd: send_trap", sess); 00961 snmp_free_pdu(pdu); 00962 } else { 00963 snmp_increment_statistic(STAT_SNMPOUTTRAPS); 00964 snmp_increment_statistic(STAT_SNMPOUTPKTS); 00965 } 00966 } 00967 00968 void 00969 send_trap_vars(int trap, int specific, netsnmp_variable_list * vars) 00970 { 00971 if (trap == SNMP_TRAP_ENTERPRISESPECIFIC) 00972 send_enterprise_trap_vars(trap, specific, objid_enterprisetrap, 00973 OID_LENGTH(objid_enterprisetrap), vars); 00974 else 00975 send_enterprise_trap_vars(trap, specific, trap_version_id, 00976 OID_LENGTH(trap_version_id), vars); 00977 } 00978 00979 /* Send a trap under a context */ 00980 void send_trap_vars_with_context(int trap, int specific, 00981 netsnmp_variable_list *vars, char *context) 00982 { 00983 if (trap == SNMP_TRAP_ENTERPRISESPECIFIC) 00984 netsnmp_send_traps(trap, specific, objid_enterprisetrap, 00985 OID_LENGTH(objid_enterprisetrap), vars, 00986 context, 0); 00987 else 00988 netsnmp_send_traps(trap, specific, trap_version_id, 00989 OID_LENGTH(trap_version_id), vars, 00990 context, 0); 00991 00992 } 00993 01017 void 01018 send_easy_trap(int trap, int specific) 01019 { 01020 send_trap_vars(trap, specific, NULL); 01021 } 01022 01046 void 01047 send_v2trap(netsnmp_variable_list * vars) 01048 { 01049 send_trap_vars(-1, -1, vars); 01050 } 01051 01064 void send_v3trap(netsnmp_variable_list *vars, char *context) 01065 { 01066 netsnmp_send_traps(-1, -1, 01067 trap_version_id, OID_LENGTH(trap_version_id), 01068 vars, context, 0); 01069 } 01070 01071 void 01072 send_trap_pdu(netsnmp_pdu *pdu) 01073 { 01074 send_trap_vars(-1, -1, pdu->variables); 01075 } 01076 01077 01078 01079 /******************* 01080 * 01081 * Config file handling 01082 * 01083 *******************/ 01084 01085 void 01086 snmpd_parse_config_authtrap(const char *token, char *cptr) 01087 { 01088 int i; 01089 01090 i = atoi(cptr); 01091 if (i == 0) { 01092 if (strcmp(cptr, "enable") == 0) { 01093 i = SNMP_AUTHENTICATED_TRAPS_ENABLED; 01094 } else if (strcmp(cptr, "disable") == 0) { 01095 i = SNMP_AUTHENTICATED_TRAPS_DISABLED; 01096 } 01097 } 01098 if (i < 1 || i > 2) { 01099 config_perror("authtrapenable must be 1 or 2"); 01100 } else { 01101 if (strcmp(token, "pauthtrapenable") == 0) { 01102 if (snmp_enableauthentrapsset < 0) { 01103 /* 01104 * This is bogus (and shouldn't happen anyway) -- the value 01105 * of snmpEnableAuthenTraps.0 is already configured 01106 * read-only. 01107 */ 01108 snmp_log(LOG_WARNING, 01109 "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n"); 01110 return; 01111 } else { 01112 snmp_enableauthentrapsset++; 01113 } 01114 } else { 01115 if (snmp_enableauthentrapsset > 0) { 01116 /* 01117 * This is bogus (and shouldn't happen anyway) -- we already 01118 * read a persistent value of snmpEnableAuthenTraps.0, which 01119 * we should ignore in favour of this one. 01120 */ 01121 snmp_log(LOG_WARNING, 01122 "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n"); 01123 /* 01124 * Fall through and copy in this value. 01125 */ 01126 } 01127 snmp_enableauthentrapsset = -1; 01128 } 01129 snmp_enableauthentraps = i; 01130 } 01131 } 01132 01133 #ifndef NETSNMP_DISABLE_SNMPV1 01134 void 01135 snmpd_parse_config_trapsink(const char *token, char *cptr) 01136 { 01137 char *sp, *cp, *pp = NULL; 01138 char *st; 01139 01140 if (!snmp_trapcommunity) 01141 snmp_trapcommunity = strdup("public"); 01142 sp = strtok_r(cptr, " \t\n", &st); 01143 cp = strtok_r(NULL, " \t\n", &st); 01144 if (cp) 01145 pp = strtok_r(NULL, " \t\n", &st); 01146 if (pp) 01147 config_pwarn("The separate port argument to trapsink is deprecated"); 01148 if (create_v1_trap_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01149 netsnmp_config_error("cannot create trapsink: %s", cptr); 01150 } 01151 } 01152 #endif 01153 01154 #ifndef NETSNMP_DISABLE_SNMPV2C 01155 void 01156 snmpd_parse_config_trap2sink(const char *word, char *cptr) 01157 { 01158 char *st, *sp, *cp, *pp = NULL; 01159 01160 if (!snmp_trapcommunity) 01161 snmp_trapcommunity = strdup("public"); 01162 sp = strtok_r(cptr, " \t\n", &st); 01163 cp = strtok_r(NULL, " \t\n", &st); 01164 if (cp) 01165 pp = strtok_r(NULL, " \t\n", &st); 01166 if (pp) 01167 config_pwarn("The separate port argument to trapsink2 is deprecated"); 01168 if (create_v2_trap_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01169 netsnmp_config_error("cannot create trap2sink: %s", cptr); 01170 } 01171 } 01172 01173 void 01174 snmpd_parse_config_informsink(const char *word, char *cptr) 01175 { 01176 char *st, *sp, *cp, *pp = NULL; 01177 01178 if (!snmp_trapcommunity) 01179 snmp_trapcommunity = strdup("public"); 01180 sp = strtok_r(cptr, " \t\n", &st); 01181 cp = strtok_r(NULL, " \t\n", &st); 01182 if (cp) 01183 pp = strtok_r(NULL, " \t\n", &st); 01184 if (pp) 01185 config_pwarn("The separate port argument to informsink is deprecated"); 01186 if (create_v2_inform_session(sp, pp, cp ? cp : snmp_trapcommunity) == 0) { 01187 netsnmp_config_error("cannot create informsink: %s", cptr); 01188 } 01189 } 01190 #endif 01191 01192 /* 01193 * this must be standardized somewhere, right? 01194 */ 01195 #define MAX_ARGS 128 01196 01197 static int traptype; 01198 01199 static void 01200 trapOptProc(int argc, char *const *argv, int opt) 01201 { 01202 switch (opt) { 01203 case 'C': 01204 while (*optarg) { 01205 switch (*optarg++) { 01206 case 'i': 01207 traptype = SNMP_MSG_INFORM; 01208 break; 01209 default: 01210 config_perror("unknown argument passed to -C"); 01211 break; 01212 } 01213 } 01214 break; 01215 } 01216 } 01217 01218 01219 void 01220 snmpd_parse_config_trapsess(const char *word, char *cptr) 01221 { 01222 char *argv[MAX_ARGS], *cp = cptr, tmp[SPRINT_MAX_LEN]; 01223 int argn, arg; 01224 netsnmp_session session, *ss; 01225 size_t len; 01226 01227 /* 01228 * inform or trap? default to trap 01229 */ 01230 traptype = SNMP_MSG_TRAP2; 01231 01232 /* 01233 * create the argv[] like array 01234 */ 01235 argv[0] = strdup("snmpd-trapsess"); /* bogus entry for getopt() */ 01236 for (argn = 1; cp && argn < MAX_ARGS; argn++) { 01237 cp = copy_nword(cp, tmp, SPRINT_MAX_LEN); 01238 argv[argn] = strdup(tmp); 01239 } 01240 01241 arg = snmp_parse_args(argn, argv, &session, "C:", trapOptProc); 01242 01243 ss = snmp_add(&session, 01244 netsnmp_transport_open_client("snmptrap", session.peername), 01245 NULL, NULL); 01246 for (; argn > 0; argn--) { 01247 free(argv[argn - 1]); 01248 } 01249 01250 if (!ss) { 01251 config_perror 01252 ("snmpd: failed to parse this line or the remote trap receiver is down. Possible cause:"); 01253 snmp_sess_perror("snmpd: snmpd_parse_config_trapsess()", &session); 01254 return; 01255 } 01256 01257 /* 01258 * If this is an SNMPv3 TRAP session, then the agent is 01259 * the authoritative engine, so set the engineID accordingly 01260 */ 01261 if (ss->version == SNMP_VERSION_3 && 01262 traptype != SNMP_MSG_INFORM && 01263 ss->securityEngineIDLen == 0) { 01264 len = snmpv3_get_engineID( tmp, sizeof(tmp)); 01265 memdup(&ss->securityEngineID, tmp, len); 01266 ss->securityEngineIDLen = len; 01267 } 01268 01269 #ifndef NETSNMP_DISABLE_SNMPV1 01270 if (ss->version == SNMP_VERSION_1) { 01271 add_trap_session(ss, SNMP_MSG_TRAP, 0, SNMP_VERSION_1); 01272 } else { 01273 #endif 01274 add_trap_session(ss, traptype, (traptype == SNMP_MSG_INFORM), 01275 ss->version); 01276 #ifndef NETSNMP_DISABLE_SNMPV1 01277 } 01278 #endif 01279 } 01280 01281 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01282 void 01283 snmpd_parse_config_trapcommunity(const char *word, char *cptr) 01284 { 01285 if (snmp_trapcommunity != NULL) { 01286 free(snmp_trapcommunity); 01287 } 01288 snmp_trapcommunity = (char *) malloc(strlen(cptr) + 1); 01289 if (snmp_trapcommunity != NULL) { 01290 copy_nword(cptr, snmp_trapcommunity, strlen(cptr) + 1); 01291 } 01292 } 01293 01294 void 01295 snmpd_free_trapcommunity(void) 01296 { 01297 if (snmp_trapcommunity) { 01298 free(snmp_trapcommunity); 01299 snmp_trapcommunity = NULL; 01300 } 01301 } 01302 #endif 01303
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.