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