dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / snmp / apps / snmptrapd.c
blob0c2a84bdd0168ece33a8842d6fd2ba9e724c48fb
1 /*
2 * snmptrapd.c - receive and log snmp traps
4 */
5 /*****************************************************************
6 Copyright 1989, 1991, 1992 by Carnegie Mellon University
8 All Rights Reserved
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted,
12 provided that the above copyright notice appear in all copies and that
13 both that copyright notice and this permission notice appear in
14 supporting documentation, and that the name of CMU not be
15 used in advertising or publicity pertaining to distribution of the
16 software without specific, written prior permission.
18 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
19 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
21 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
23 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 SOFTWARE.
25 ******************************************************************/
26 #include <net-snmp/net-snmp-config.h>
28 #if HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #if HAVE_STRING_H
35 #include <string.h>
36 #else
37 #include <strings.h>
38 #endif
39 #include <sys/types.h>
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
43 #if HAVE_WINSOCK_H
44 #include <winsock.h>
45 #else
46 #include <sys/socket.h>
47 #endif
48 #if HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif
51 #if HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54 #include <stdio.h>
55 #if HAVE_SYS_TIME_H
56 # include <sys/time.h>
57 # if TIME_WITH_SYS_TIME
58 # include <time.h>
59 # endif
60 #else
61 # include <time.h>
62 #endif
63 #if HAVE_SYS_SELECT_H
64 #include <sys/select.h>
65 #endif
66 #if HAVE_SYS_PARAM_H
67 #include <sys/param.h>
68 #endif
69 #if HAVE_SYSLOG_H
70 #include <syslog.h>
71 #endif
72 #if HAVE_SYS_IOCTL_H
73 #include <sys/ioctl.h>
74 #endif
75 #if HAVE_NET_IF_H
76 #include <net/if.h>
77 #endif
78 #if HAVE_NETDB_H
79 #include <netdb.h>
80 #endif
81 #if HAVE_ARPA_INET_H
82 #include <arpa/inet.h>
83 #endif
84 #if HAVE_FCNTL_H
85 #include <fcntl.h>
86 #endif
87 #if HAVE_PROCESS_H /* Win32-getpid */
88 #include <process.h>
89 #endif
90 #include <signal.h>
91 #include <errno.h>
93 #include <net-snmp/net-snmp-includes.h>
94 #include <net-snmp/agent/net-snmp-agent-includes.h>
95 #include "snmptrapd_handlers.h"
96 #include "snmptrapd_log.h"
97 #include "notification_log.h"
99 #if USE_LIBWRAP
100 #include <tcpd.h>
102 int allow_severity = LOG_INFO;
103 int deny_severity = LOG_WARNING;
104 #endif
107 * #define NETSNMP_DS_APP_DONT_LOG 9 defined in notification_log.h
110 #ifndef BSD4_3
111 #define BSD4_2
112 #endif
114 #ifndef FD_SET
116 typedef long fd_mask;
117 #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
119 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
120 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
121 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
122 #define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
123 #endif
125 char *logfile = 0;
126 int Print = 0;
127 int Syslog = 0;
128 int Event = 0;
129 int dropauth = 0;
130 int running = 1;
131 int reconfig = 0;
132 u_long num_received = 0;
133 char default_port[] = "udp:162";
135 const char *trap1_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b] (via %A [%a]): %N\n\t%W Trap (%q) Uptime: %#T\n%v\n";
136 const char *trap2_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n";
138 /* how to format logging to stderr */
139 char *trap1_fmt_str = NULL, *trap2_fmt_str = NULL;
142 * These definitions handle 4.2 systems without additional syslog facilities.
144 #ifndef LOG_CONS
145 #define LOG_CONS 0 /* Don't bother if not defined... */
146 #endif
147 #ifndef LOG_PID
148 #define LOG_PID 0 /* Don't bother if not defined... */
149 #endif
150 #ifndef LOG_LOCAL0
151 #define LOG_LOCAL0 0
152 #endif
153 #ifndef LOG_LOCAL1
154 #define LOG_LOCAL1 0
155 #endif
156 #ifndef LOG_LOCAL2
157 #define LOG_LOCAL2 0
158 #endif
159 #ifndef LOG_LOCAL3
160 #define LOG_LOCAL3 0
161 #endif
162 #ifndef LOG_LOCAL4
163 #define LOG_LOCAL4 0
164 #endif
165 #ifndef LOG_LOCAL5
166 #define LOG_LOCAL5 0
167 #endif
168 #ifndef LOG_LOCAL6
169 #define LOG_LOCAL6 0
170 #endif
171 #ifndef LOG_LOCAL7
172 #define LOG_LOCAL7 0
173 #endif
174 #ifndef LOG_DAEMON
175 #define LOG_DAEMON 0
176 #endif
179 * Include an extra Facility variable to allow command line adjustment of
180 * syslog destination
182 int Facility = LOG_DAEMON;
184 struct timeval Now;
186 void trapd_update_config(void);
188 const char *
189 trap_description(int trap)
191 switch (trap) {
192 case SNMP_TRAP_COLDSTART:
193 return "Cold Start";
194 case SNMP_TRAP_WARMSTART:
195 return "Warm Start";
196 case SNMP_TRAP_LINKDOWN:
197 return "Link Down";
198 case SNMP_TRAP_LINKUP:
199 return "Link Up";
200 case SNMP_TRAP_AUTHFAIL:
201 return "Authentication Failure";
202 case SNMP_TRAP_EGPNEIGHBORLOSS:
203 return "EGP Neighbor Loss";
204 case SNMP_TRAP_ENTERPRISESPECIFIC:
205 return "Enterprise Specific";
206 default:
207 return "Unknown Type";
212 netsnmp_pdu *
213 snmp_clone_pdu2(netsnmp_pdu *pdu, int command)
215 netsnmp_pdu *newpdu = snmp_clone_pdu(pdu);
216 if (newpdu) {
217 newpdu->command = command;
219 return newpdu;
222 static oid risingAlarm[] = { 1, 3, 6, 1, 6, 3, 2, 1, 1, 3, 1 };
223 static oid fallingAlarm[] = { 1, 3, 6, 1, 6, 3, 2, 1, 1, 3, 2 };
224 static oid unavailableAlarm[] = { 1, 3, 6, 1, 6, 3, 2, 1, 1, 3, 3 };
226 void
227 event_input(netsnmp_variable_list * vp)
229 int eventid = 0;
230 oid variable[MAX_OID_LEN];
231 int variablelen = 0;
232 u_long destip = 0;
233 int sampletype = 0;
234 int value = 0;
235 int threshold = 0;
236 int i;
237 int nvars = 0;
239 netsnmp_variable_list *vp2 = vp;
241 oid *op = NULL;
243 /* Make sure there are 5 variables. Otherwise, don't bother */
244 for (i=1; i <= 5; i++) {
245 vp2 = vp2->next_variable;
246 if (!vp2) {
247 nvars = -1;
248 break;
252 if (nvars != -1)
254 vp = vp->next_variable; /* skip sysUptime */
255 if (vp->val_len != sizeof(risingAlarm) ||
256 !memcmp(vp->val.objid, risingAlarm, sizeof(risingAlarm)))
257 eventid = 1;
258 else if (vp->val_len != sizeof(risingAlarm) ||
259 !memcmp(vp->val.objid, fallingAlarm, sizeof(fallingAlarm)))
260 eventid = 2;
261 else if (vp->val_len != sizeof(risingAlarm) ||
262 !memcmp(vp->val.objid, unavailableAlarm, sizeof(unavailableAlarm)))
263 eventid = 3;
264 else {
265 fprintf(stderr, "unknown event\n");
266 eventid = 0;
269 vp = vp->next_variable;
270 memmove(variable, vp->val.objid, vp->val_len * sizeof(oid));
271 variablelen = vp->val_len;
272 op = vp->name + 22;
273 destip = 0;
274 destip |= (*op++) << 24;
275 destip |= (*op++) << 16;
276 destip |= (*op++) << 8;
277 destip |= *op++;
279 vp = vp->next_variable;
280 sampletype = *vp->val.integer;
282 vp = vp->next_variable;
283 value = *vp->val.integer;
285 vp = vp->next_variable;
286 threshold = *vp->val.integer;
288 printf("%d: 0x%02lX %d %d %d\n", eventid, destip, sampletype, value,
289 threshold);
292 void
293 send_handler_data(FILE * file, struct hostent *host,
294 netsnmp_pdu *pdu, netsnmp_transport *transport)
296 netsnmp_variable_list tmpvar, *vars;
297 static oid trapoids[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5, 0 };
298 static oid snmpsysuptime[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
299 static oid snmptrapoid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
300 static oid snmptrapent[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 3, 0 };
301 static oid snmptrapaddr[] = { 1, 3, 6, 1, 6, 3, 18, 1, 3, 0 };
302 static oid snmptrapcom[] = { 1, 3, 6, 1, 6, 3, 18, 1, 4, 0 };
303 oid enttrapoid[MAX_OID_LEN];
304 int enttraplen = pdu->enterprise_length;
305 char *tstr = NULL;
307 if (transport != NULL && transport->f_fmtaddr != NULL) {
308 tstr = transport->f_fmtaddr(transport, pdu->transport_data,
309 pdu->transport_data_length);
310 fprintf(file, "%s\n%s\n", host ? host->h_name : tstr, tstr);
311 free(tstr);
312 } else {
313 fprintf(file, "%s\n<UNKNOWN>\n", host ? host->h_name : "<UNKNOWN>");
315 if (pdu->command == SNMP_MSG_TRAP) {
317 * convert a v1 trap to a v2 variable binding list:
318 * The uptime and trapOID go first in the list.
320 tmpvar.val.integer = (long *) &pdu->time;
321 tmpvar.val_len = sizeof(pdu->time);
322 tmpvar.type = ASN_TIMETICKS;
323 fprint_variable(file, snmpsysuptime,
324 sizeof(snmpsysuptime) / sizeof(oid), &tmpvar);
325 tmpvar.type = ASN_OBJECT_ID;
326 if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
327 memcpy(enttrapoid, pdu->enterprise, sizeof(oid) * enttraplen);
328 if (enttrapoid[enttraplen - 1] != 0)
329 enttrapoid[enttraplen++] = 0;
330 enttrapoid[enttraplen++] = pdu->specific_type;
331 tmpvar.val.objid = enttrapoid;
332 tmpvar.val_len = enttraplen * sizeof(oid);
333 } else {
334 trapoids[9] = pdu->trap_type + 1;
335 tmpvar.val.objid = trapoids;
336 tmpvar.val_len = 10 * sizeof(oid);
338 fprint_variable(file, snmptrapoid,
339 sizeof(snmptrapoid) / sizeof(oid), &tmpvar);
342 * do the variables in the pdu
344 for (vars = pdu->variables; vars; vars = vars->next_variable) {
345 fprint_variable(file, vars->name, vars->name_length, vars);
347 if (pdu->command == SNMP_MSG_TRAP) {
349 * convert a v1 trap to a v2 variable binding list:
350 * The enterprise goes last.
352 tmpvar.val.string = pdu->agent_addr;
353 tmpvar.val_len = 4;
354 tmpvar.type = ASN_IPADDRESS;
355 fprint_variable(file, snmptrapaddr,
356 sizeof(snmptrapaddr) / sizeof(oid), &tmpvar);
357 tmpvar.val.string = pdu->community;
358 tmpvar.val_len = pdu->community_len;
359 tmpvar.type = ASN_OCTET_STR;
360 fprint_variable(file, snmptrapcom,
361 sizeof(snmptrapcom) / sizeof(oid), &tmpvar);
362 tmpvar.val.objid = pdu->enterprise;
363 tmpvar.val_len = pdu->enterprise_length * sizeof(oid);
364 tmpvar.type = ASN_OBJECT_ID;
365 fprint_variable(file, snmptrapent,
366 sizeof(snmptrapent) / sizeof(oid), &tmpvar);
370 void
371 do_external(char *cmd, struct hostent *host,
372 netsnmp_pdu *pdu, netsnmp_transport *transport)
374 FILE *file;
375 int oldquick, result;
377 DEBUGMSGTL(("snmptrapd", "Running: %s\n", cmd));
378 oldquick = snmp_get_quick_print();
379 snmp_set_quick_print(1);
380 if (cmd) {
381 #ifndef WIN32
382 int fd[2];
383 int pid;
385 if (pipe(fd)) {
386 snmp_log_perror("pipe");
388 if ((pid = fork()) == 0) {
390 * child
392 close(0);
393 if (dup(fd[0]) != 0) {
394 snmp_log_perror("dup");
396 close(fd[1]);
397 close(fd[0]);
398 system(cmd);
399 exit(0);
400 } else if (pid > 0) {
401 file = fdopen(fd[1], "w");
402 send_handler_data(file, host, pdu, transport);
403 fclose(file);
404 close(fd[0]);
405 close(fd[1]);
406 if (waitpid(pid, &result, 0) < 0) {
407 snmp_log_perror("waitpid");
409 } else {
410 snmp_log_perror("fork");
412 #else
413 char command_buf[128];
414 char file_buf[L_tmpnam];
416 tmpnam(file_buf);
417 file = fopen(file_buf, "w");
418 if (!file) {
419 fprintf(stderr, "fopen: %s: %s\n", file_buf, strerror(errno));
420 } else {
421 send_handler_data(file, host, pdu, transport);
422 fclose(file);
423 snprintf(command_buf, sizeof(command_buf),
424 "%s < %s", cmd, file_buf);
425 command_buf[ sizeof(command_buf)-1 ] = 0;
426 result = system(command_buf);
427 if (result == -1)
428 fprintf(stderr, "system: %s: %s\n", command_buf,
429 strerror(errno));
430 else if (result)
431 fprintf(stderr, "system: %s: %d\n", command_buf, result);
432 remove(file_buf);
434 #endif /* WIN32 */
436 snmp_set_quick_print(oldquick);
440 snmp_input(int op,
441 netsnmp_session * session,
442 int reqid, netsnmp_pdu *pdu, void *magic)
444 netsnmp_variable_list *vars = NULL;
445 netsnmp_transport *transport = (netsnmp_transport *) magic;
446 char buf[64], *cp;
447 netsnmp_pdu *reply;
448 struct hostent *host = NULL;
449 static oid trapoids[10] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
450 static oid snmptrapoid2[11] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
451 netsnmp_variable_list tmpvar;
452 char *Command = NULL, *tstr = NULL;
453 u_char *rbuf = NULL;
454 size_t r_len = 64, o_len = 0;
455 int trunc = 0;
457 tmpvar.type = ASN_OBJECT_ID;
459 if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
460 if ((rbuf = (u_char *) calloc(r_len, 1)) == NULL) {
461 snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
462 return 1;
465 if (pdu->command == SNMP_MSG_TRAP) {
466 oid trapOid[MAX_OID_LEN + 2] = { 0 };
467 int trapOidLen = pdu->enterprise_length;
469 num_received++;
471 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
472 NETSNMP_DS_APP_NUMERIC_IP)) {
473 host = gethostbyaddr((char *) pdu->agent_addr, 4, AF_INET);
476 if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
477 memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen);
478 if (trapOid[trapOidLen - 1] != 0) {
479 trapOid[trapOidLen++] = 0;
481 trapOid[trapOidLen++] = pdu->specific_type;
484 if (Print && (pdu->trap_type != SNMP_TRAP_AUTHFAIL ||
485 dropauth == 0)) {
486 if ((trap1_fmt_str == NULL) || (trap1_fmt_str[0] == '\0')) {
487 trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len,
488 1, pdu, transport);
489 } else {
490 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
491 trap1_fmt_str, pdu,
492 transport);
494 snmp_log(LOG_INFO, "%s%s", rbuf, (trunc?" [TRUNCATED]\n":""));
497 if (Syslog && (pdu->trap_type != SNMP_TRAP_AUTHFAIL ||
498 dropauth == 0)) {
499 memset(rbuf, 0, o_len);
500 o_len = 0;
501 rbuf[o_len++] = ',';
502 rbuf[o_len++] = ' ';
504 for (vars = pdu->variables; vars;
505 vars = vars->next_variable) {
506 trunc = !sprint_realloc_variable(&rbuf, &r_len, &o_len, 1,
507 vars->name,
508 vars->name_length, vars);
509 if (!trunc) {
511 * Add a trailing , ...
513 trunc = !snmp_strcat(&rbuf, &r_len, &o_len, 1, ", ");
515 if (trunc) {
516 break;
520 if (o_len > 0 && !trunc) {
521 o_len -= 2;
522 rbuf[o_len] = '\0';
525 if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
526 u_char *oidbuf = NULL;
527 size_t ob_len = 64, oo_len = 0;
528 int otrunc = 0;
530 if ((oidbuf = (u_char *) calloc(ob_len, 1)) == NULL) {
531 snmp_log(LOG_ERR,
532 "couldn't display trap -- malloc failed\n");
533 free(rbuf);
534 return 1;
537 otrunc = !sprint_realloc_objid(&oidbuf, &ob_len, &oo_len,
538 1, trapOid, trapOidLen);
539 if (!otrunc) {
540 cp = strrchr((char *) oidbuf, '.');
541 if (cp != NULL) {
542 cp++;
543 } else {
544 cp = (char *) oidbuf;
546 } else {
547 cp = (char *) oidbuf;
549 snmp_log(LOG_WARNING, "%s: %s Trap (%s%s) Uptime: %s%s%s",
550 inet_ntoa(*((struct in_addr *) pdu-> agent_addr)),
551 trap_description(pdu->trap_type), cp,
552 (otrunc ? " [TRUNCATED]" : ""),
553 uptime_string(pdu->time, buf), rbuf,
554 (trunc ? " [TRUNCATED]\n" : ""));
555 free(oidbuf);
556 } else {
557 snmp_log(LOG_WARNING, "%s: %s Trap (%ld) Uptime: %s%s%s",
558 inet_ntoa(*((struct in_addr *) pdu->agent_addr)),
559 trap_description(pdu->trap_type),
560 pdu->specific_type,
561 uptime_string(pdu->time, buf), rbuf,
562 (trunc ? " [TRUNCATED]\n" : ""));
565 if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
566 Command = snmptrapd_get_traphandler(trapOid, trapOidLen);
567 } else {
568 trapoids[9] = pdu->trap_type + 1;
569 Command = snmptrapd_get_traphandler(trapoids, 10);
571 if (Command) {
572 do_external(Command, host, pdu, transport);
574 log_notification(host, pdu, transport);
575 } else if (pdu->command == SNMP_MSG_TRAP2 ||
576 pdu->command == SNMP_MSG_INFORM) {
577 num_received++;
578 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
579 NETSNMP_DS_APP_NUMERIC_IP)) {
581 * Right, apparently a name lookup is wanted. This is only
582 * reasonable for the UDP and TCP transport domains (we
583 * don't want to try to be too clever here).
585 #ifdef SNMP_TRANSPORT_TCP_DOMAIN
586 if (transport != NULL
587 && (transport->domain == netsnmpUDPDomain
588 || transport->domain == netsnmp_snmpTCPDomain)) {
589 #else
590 if (transport != NULL
591 && transport->domain == netsnmpUDPDomain) {
592 #endif
594 * This is kind of bletcherous -- it breaks the opacity of
595 * transport_data but never mind -- the alternative is a
596 * lot of munging strings from f_fmtaddr.
598 struct sockaddr_in *addr =
599 (struct sockaddr_in *) pdu->transport_data;
600 if (addr != NULL &&
601 pdu->transport_data_length == sizeof(struct sockaddr_in)) {
602 host = gethostbyaddr((char *) &(addr->sin_addr),
603 sizeof(struct in_addr), AF_INET);
608 if (Print) {
609 if (trap2_fmt_str == NULL || trap2_fmt_str[0] == '\0') {
610 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
611 trap2_std_str, pdu,
612 transport);
613 } else {
614 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
615 trap2_fmt_str, pdu,
616 transport);
618 snmp_log(LOG_INFO, "%s%s", rbuf, (trunc?" [TRUNCATED]":""));
621 if (Syslog) {
622 memset(rbuf, 0, o_len);
623 o_len = 0;
624 for (vars = pdu->variables; vars;
625 vars = vars->next_variable) {
626 trunc = !sprint_realloc_variable(&rbuf, &r_len, &o_len, 1,
627 vars->name,
628 vars->name_length, vars);
629 if (!trunc) {
630 trunc = !snmp_strcat(&rbuf, &r_len, &o_len, 1, ", ");
632 if (trunc) {
633 break;
637 if (o_len > 0 && !trunc) {
638 o_len -= 2;
639 rbuf[o_len] = '\0';
642 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
643 NETSNMP_DS_APP_NUMERIC_IP)) {
645 * Right, apparently a name lookup is wanted. This is only
646 * reasonable for the UDP and TCP transport domains (we
647 * don't want to try to be too clever here).
649 #ifdef SNMP_TRANSPORT_TCP_DOMAIN
650 if (transport != NULL
651 && (transport->domain == netsnmpUDPDomain
652 || transport->domain ==
653 netsnmp_snmpTCPDomain)) {
654 #else
655 if (transport != NULL
656 && transport->domain == netsnmpUDPDomain) {
657 #endif
659 * This is kind of bletcherous -- it breaks the
660 * opacity of transport_data but never mind -- the
661 * alternative is a lot of munging strings from
662 * f_fmtaddr.
664 struct sockaddr_in *addr =
665 (struct sockaddr_in *) pdu->transport_data;
666 if (addr != NULL && pdu->transport_data_length ==
667 sizeof(struct sockaddr_in)) {
668 host = gethostbyaddr((char *)&(addr->sin_addr),
669 sizeof(struct in_addr), AF_INET);
674 if (transport != NULL && transport->f_fmtaddr != NULL) {
675 tstr = transport->f_fmtaddr(transport,
676 pdu->transport_data,
677 pdu->transport_data_length);
678 snmp_log(LOG_WARNING, "%s [%s]: Trap %s%s\n",
679 host ? host->h_name : tstr, tstr, rbuf,
680 (trunc ? "[TRUNCATED]" : ""));
681 free(tstr);
682 } else {
683 snmp_log(LOG_WARNING, "<UNKNOWN>: Trap %s%s", rbuf,
684 (trunc ? "[TRUNCATED]\n" : ""));
688 if (Event) {
689 event_input(pdu->variables);
692 for (vars = pdu->variables; (vars != NULL) &&
693 snmp_oid_compare(vars->name, vars->name_length,
694 snmptrapoid2,
695 sizeof(snmptrapoid2)/sizeof(oid));
696 vars = vars->next_variable);
698 if (vars && vars->type == ASN_OBJECT_ID) {
699 Command = snmptrapd_get_traphandler(vars->val.objid,
700 vars->val_len/sizeof(oid));
701 if (Command) {
702 do_external(Command, host, pdu, transport);
706 log_notification(host, pdu, transport);
708 if (pdu->command == SNMP_MSG_INFORM) {
709 if ((reply = snmp_clone_pdu2(pdu, SNMP_MSG_RESPONSE)) == NULL){
710 snmp_log(LOG_ERR,
711 "couldn't clone PDU for INFORM response\n");
712 } else {
713 reply->errstat = 0;
714 reply->errindex = 0;
715 if (!snmp_send(session, reply)) {
716 snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
717 session);
718 snmp_free_pdu(reply);
724 if (rbuf != NULL) {
725 free(rbuf);
727 } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
728 fprintf(stderr, "Timeout: This shouldn't happen!\n");
730 return 1;
734 static void
735 parse_trap1_fmt(const char *token, char *line)
737 trap1_fmt_str = strdup(line);
741 static void
742 free_trap1_fmt(void)
744 if (trap1_fmt_str && trap1_fmt_str != trap1_std_str)
745 free((char *) trap1_fmt_str);
746 trap1_fmt_str = NULL;
750 static void
751 parse_trap2_fmt(const char *token, char *line)
753 trap2_fmt_str = strdup(line);
757 static void
758 free_trap2_fmt(void)
760 if (trap2_fmt_str && trap2_fmt_str != trap2_std_str)
761 free((char *) trap2_fmt_str);
762 trap2_fmt_str = NULL;
766 void
767 usage(void)
769 fprintf(stderr, "Usage: snmptrapd [OPTIONS] [LISTENING ADDRESSES]\n");
770 fprintf(stderr, "\n\tNET-SNMP Version: %s\n", netsnmp_get_version());
771 fprintf(stderr, "\tWeb: http://www.net-snmp.org/\n");
772 fprintf(stderr, "\tEmail: net-snmp-coders@lists.sourceforge.net\n");
773 fprintf(stderr, "\n");
774 fprintf(stderr, " -a\t\t\tignore authentication failture traps\n");
775 fprintf(stderr, " -c FILE\t\tread FILE as a configuration file\n");
776 fprintf(stderr,
777 " -C\t\t\tdo not read the default configuration files\n");
778 fprintf(stderr, " -d\t\t\tdump sent and received SNMP packets\n");
779 fprintf(stderr, " -D\t\t\tturn on debugging output\n");
780 fprintf(stderr,
781 " -e\t\t\tprint event # (rising/falling alarm, etc.)\n");
782 fprintf(stderr, " -f\t\t\tdo not fork from the shell\n");
783 fprintf(stderr,
784 " -F FORMAT\t\tuse specified format for logging to standard error\n");
785 fprintf(stderr, " -h, --help\t\tdisplay this usage message\n");
786 fprintf(stderr,
787 " -H\t\t\tdisplay configuration file directives understood\n");
788 fprintf(stderr,
789 " -m MIBLIST\t\tuse MIBLIST instead of the default MIB list\n");
790 fprintf(stderr,
791 " -M DIRLIST\t\tuse DIRLIST as the list of locations\n\t\t\t to look for MIBs\n");
792 fprintf(stderr,
793 " -n\t\t\tuse numeric addresses instead of attempting\n\t\t\t hostname lookups (no DNS)\n");
794 fprintf(stderr, " -o FILE\t\toutput to FILE\n");
795 fprintf(stderr, " -P\t\t\tprint to standard error\n");
796 fprintf(stderr, " -s\t\t\tlog to syslog\n");
797 fprintf(stderr,
798 " -S d|i|0-7\t\tset syslog facility to LOG_DAEMON (d), LOG_INFO (i)\n\t\t\t or LOG_LOCAL[0-7] (default LOG_DAEMON)\n");
799 #if HAVE_GETPID
800 fprintf(stderr, " -u FILE\t\tstore process id in FILE\n");
801 #endif
802 fprintf(stderr, " -v, --version\t\tdisplay version information\n");
803 fprintf(stderr,
804 " -O <OUTOPTS>\t\ttoggle options controlling output display\n");
805 snmp_out_toggle_options_usage("\t\t\t", stderr);
808 static void
809 version(void)
811 printf("\nNET-SNMP Version: %s\n", netsnmp_get_version());
812 printf("Web: http://www.net-snmp.org/\n");
813 printf("Email: net-snmp-coders@lists.sourceforge.net\n\n");
814 exit(0);
817 RETSIGTYPE
818 term_handler(int sig)
820 running = 0;
823 #ifdef SIGHUP
824 RETSIGTYPE
825 hup_handler(int sig)
827 reconfig = 1;
828 signal(SIGHUP, hup_handler);
830 #endif
832 static int
833 pre_parse(netsnmp_session * session, netsnmp_transport *transport,
834 void *transport_data, int transport_data_length)
836 #if USE_LIBWRAP
837 char *addr_string = NULL;
839 if (transport != NULL && transport->f_fmtaddr != NULL) {
841 * Okay I do know how to format this address for logging.
843 addr_string = transport->f_fmtaddr(transport, transport_data,
844 transport_data_length);
846 * Don't forget to free() it.
850 if (addr_string != NULL) {
851 if (hosts_ctl("snmptrapd", STRING_UNKNOWN,
852 addr_string, STRING_UNKNOWN) == 0) {
853 free(addr_string);
854 return 0;
856 free(addr_string);
857 } else {
858 if (hosts_ctl("snmptrapd", STRING_UNKNOWN,
859 STRING_UNKNOWN, STRING_UNKNOWN) == 0) {
860 return 0;
863 #endif/* USE_LIBWRAP */
864 return 1;
867 static netsnmp_session *
868 snmptrapd_add_session(netsnmp_transport *t)
870 netsnmp_session sess, *session = &sess, *rc = NULL;
872 snmp_sess_init(session);
873 session->peername = SNMP_DEFAULT_PEERNAME; /* Original code had NULL here */
874 session->version = SNMP_DEFAULT_VERSION;
875 session->community_len = SNMP_DEFAULT_COMMUNITY_LEN;
876 session->retries = SNMP_DEFAULT_RETRIES;
877 session->timeout = SNMP_DEFAULT_TIMEOUT;
878 session->callback = snmp_input;
879 session->callback_magic = (void *) t;
880 session->authenticator = NULL;
881 sess.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
883 rc = snmp_add(session, t, pre_parse, NULL);
884 if (rc == NULL) {
885 snmp_sess_perror("snmptrapd", session);
887 return rc;
890 static void
891 snmptrapd_close_sessions(netsnmp_session * sess_list)
893 netsnmp_session *s = NULL, *next = NULL;
895 for (s = sess_list; s != NULL; s = next) {
896 next = s->next;
897 snmp_close(s);
902 main(int argc, char *argv[])
904 char options[128] = "ac:CdD::efF:hHl:m:M:no:PqsS:vO:-:";
905 netsnmp_session *sess_list = NULL, *ss = NULL;
906 netsnmp_transport *transport = NULL;
907 int arg, i = 0;
908 int count, numfds, block;
909 fd_set fdset;
910 struct timeval timeout, *tvp;
911 int dofork = 1;
912 char *cp, *listen_ports = NULL;
913 char *trap1_fmt_str_remember = NULL;
914 int agentx_subagent = 1, depmsg = 0;
915 #if HAVE_GETPID
916 FILE *PID;
917 char *pid_file = NULL;
918 #endif
921 * register our configuration handlers now so -H properly displays them
923 register_config_handler("snmptrapd", "traphandle",
924 snmptrapd_traphandle, NULL,
925 "oid|\"default\" program [args ...] ");
926 register_config_handler("snmptrapd", "createUser",
927 usm_parse_create_usmUser, NULL,
928 "username (MD5|SHA) passphrase [DES [passphrase]]");
929 register_config_handler("snmptrapd", "usmUser",
930 usm_parse_config_usmUser, NULL, NULL);
931 register_config_handler("snmptrapd", "format1",
932 parse_trap1_fmt, free_trap1_fmt, "format");
933 register_config_handler("snmptrapd", "format2",
934 parse_trap2_fmt, free_trap2_fmt, "format");
937 * we need to be called back later
939 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
940 usm_store_users, NULL);
942 #ifdef WIN32
943 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
944 #else
945 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
946 #endif
949 * Add some options if they are available.
951 #if HAVE_GETPID
952 strcat(options, "u:");
953 #endif
956 * Now process options normally.
959 while ((arg = getopt(argc, argv, options)) != EOF) {
960 switch (arg) {
961 case '-':
962 if (strcasecmp(optarg, "help") == 0) {
963 usage();
964 exit(0);
966 if (strcasecmp(optarg, "version") == 0) {
967 version();
968 exit(0);
971 handle_long_opt(optarg);
972 break;
974 case 'a':
975 dropauth = 1;
976 break;
978 case 'c':
979 if (optarg != NULL) {
980 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
981 NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
982 } else {
983 usage();
984 exit(1);
986 break;
988 case 'C':
989 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
990 NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
991 break;
993 case 'd':
994 snmp_set_dump_packet(1);
995 break;
997 case 'D':
998 debug_register_tokens(optarg);
999 snmp_set_do_debugging(1);
1000 break;
1002 case 'e':
1003 Event++;
1004 break;
1006 case 'f':
1007 dofork = 0;
1008 break;
1010 case 'F':
1011 if (optarg != NULL) {
1012 trap1_fmt_str_remember = optarg;
1013 } else {
1014 usage();
1015 exit(1);
1017 break;
1019 case 'h':
1020 usage();
1021 exit(0);
1023 case 'H':
1024 init_notification_log();
1025 init_snmp("snmptrapd");
1026 fprintf(stderr, "Configuration directives understood:\n");
1027 read_config_print_usage(" ");
1028 exit(0);
1030 case 'l':
1031 fprintf(stderr,
1032 "Warning: -l option is deprecated; use -S instead\n");
1033 depmsg = 1;
1034 case 'S':
1035 if (optarg != NULL) {
1036 switch (*optarg) {
1037 case 'd':
1038 case 'D':
1039 Facility = LOG_DAEMON;
1040 break;
1041 case 'i':
1042 case 'I':
1043 Facility = LOG_INFO;
1044 break;
1045 case '0':
1046 Facility = LOG_LOCAL0;
1047 break;
1048 case '1':
1049 Facility = LOG_LOCAL1;
1050 break;
1051 case '2':
1052 Facility = LOG_LOCAL2;
1053 break;
1054 case '3':
1055 Facility = LOG_LOCAL3;
1056 break;
1057 case '4':
1058 Facility = LOG_LOCAL4;
1059 break;
1060 case '5':
1061 Facility = LOG_LOCAL5;
1062 break;
1063 case '6':
1064 Facility = LOG_LOCAL6;
1065 break;
1066 case '7':
1067 Facility = LOG_LOCAL7;
1068 break;
1069 default:
1070 fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
1071 usage();
1072 exit(1);
1074 } else {
1075 fprintf(stderr, "no syslog facility specified\n");
1076 usage();
1077 exit(1);
1079 break;
1081 case 'm':
1082 if (optarg != NULL) {
1083 setenv("MIBS", optarg, 1);
1084 } else {
1085 usage();
1086 exit(1);
1088 break;
1090 case 'M':
1091 if (optarg != NULL) {
1092 setenv("MIBDIRS", optarg, 1);
1093 } else {
1094 usage();
1095 exit(1);
1097 break;
1099 case 'n':
1100 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
1101 NETSNMP_DS_APP_NUMERIC_IP, 1);
1102 break;
1104 case 'o':
1105 Print++;
1106 if (optarg != NULL) {
1107 logfile = optarg;
1108 snmp_enable_filelog(optarg, 0);
1109 } else {
1110 usage();
1111 exit(1);
1113 break;
1115 case 'O':
1116 cp = snmp_out_toggle_options(optarg);
1117 if (cp != NULL) {
1118 fprintf(stderr, "Unknown output option passed to -O: %c\n",
1119 *cp);
1120 usage();
1121 exit(1);
1123 break;
1124 case 'P':
1125 dofork = 0;
1126 snmp_enable_stderrlog();
1127 Print++;
1128 break;
1130 case 's':
1131 Syslog++;
1132 break;
1134 #if HAVE_GETPID
1135 case 'u':
1136 if (optarg != NULL) {
1137 pid_file = optarg;
1138 } else {
1139 usage();
1140 exit(1);
1142 break;
1143 #endif
1144 break;
1146 case 'v':
1147 version();
1148 exit(0);
1149 break;
1151 default:
1152 fprintf(stderr, "invalid option: -%c\n", arg);
1153 usage();
1154 exit(1);
1155 break;
1159 if (optind < argc) {
1161 * There are optional transport addresses on the command line.
1163 for (i = optind; i < argc; i++) {
1164 char *astring;
1165 if (listen_ports != NULL) {
1166 astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i]));
1167 if (astring == NULL) {
1168 fprintf(stderr, "malloc failure processing argv[%d]\n", i);
1169 exit(1);
1171 sprintf(astring, "%s,%s", listen_ports, argv[i]);
1172 free(listen_ports);
1173 listen_ports = astring;
1174 } else {
1175 listen_ports = strdup(argv[i]);
1176 if (listen_ports == NULL) {
1177 fprintf(stderr, "malloc failure processing argv[%d]\n", i);
1178 exit(1);
1182 } else {
1183 listen_ports = default_port;
1186 if (!Print) {
1187 Syslog = 1;
1189 #ifdef USING_AGENTX_SUBAGENT_MODULE
1191 * we're an agentx subagent?
1193 if (agentx_subagent) {
1195 * make us a agentx client.
1197 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
1198 NETSNMP_DS_AGENT_ROLE, 1);
1200 #endif
1203 * don't fail if we can't do agentx (ie, socket not there, or not root)
1205 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
1206 NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
1208 * ignore any warning messages.
1210 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
1211 NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS);
1214 * initialize the agent library
1216 init_agent("snmptrapd");
1219 * initialize local modules
1221 if (agentx_subagent) {
1222 #ifdef USING_AGENTX_SUBAGENT_MODULE
1223 init_subagent();
1224 #endif
1225 init_notification_log();
1229 * Initialize the world. Create initial user
1231 init_snmp("snmptrapd");
1232 if (trap1_fmt_str_remember) {
1233 free_trap1_fmt();
1234 free_trap2_fmt();
1235 trap1_fmt_str = strdup(trap1_fmt_str_remember);
1236 trap2_fmt_str = strdup(trap1_fmt_str_remember);
1239 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1240 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) {
1242 * just starting up to process specific configuration and then
1243 * shutting down immediately.
1245 running = 0;
1247 #ifndef WIN32
1249 * fork the process to the background if we are not printing to stderr
1251 if (dofork && running) {
1252 int fd;
1254 switch (fork()) {
1255 case -1:
1256 fprintf(stderr, "bad fork - %s\n", strerror(errno));
1257 _exit(1);
1259 case 0:
1261 * become process group leader
1263 if (setsid() == -1) {
1264 fprintf(stderr, "bad setsid - %s\n", strerror(errno));
1265 _exit(1);
1269 * if we are forked, we don't want to print out to stdout or stderr
1271 fd = open("/dev/null", O_RDWR);
1272 dup2(fd, STDIN_FILENO);
1273 dup2(fd, STDOUT_FILENO);
1274 dup2(fd, STDERR_FILENO);
1275 close(fd);
1276 break;
1278 default:
1279 _exit(0);
1282 #endif /* WIN32 */
1283 #if HAVE_GETPID
1284 if (pid_file != NULL) {
1285 if ((PID = fopen(pid_file, "w")) == NULL) {
1286 snmp_log_perror(pid_file);
1287 exit(1);
1289 fprintf(PID, "%d\n", (int) getpid());
1290 fclose(PID);
1292 #endif
1294 if (Syslog) {
1295 snmp_enable_syslog_ident("snmptrapd", Facility);
1296 snmp_log(LOG_INFO, "Starting snmptrapd %s\n", netsnmp_get_version());
1297 if (depmsg) {
1298 snmp_log(LOG_WARNING, "-l option is deprecated; use -S instead\n");
1301 if (Print) {
1302 struct tm *tm;
1303 time_t timer;
1304 time(&timer);
1305 tm = localtime(&timer);
1306 snmp_log(LOG_INFO,
1307 "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Started.\n",
1308 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1309 tm->tm_hour, tm->tm_min, tm->tm_sec,
1310 netsnmp_get_version());
1313 SOCK_STARTUP;
1315 cp = listen_ports;
1317 while (cp != NULL) {
1318 char *sep = strchr(cp, ',');
1319 if (sep != NULL) {
1320 *sep = 0;
1323 transport = netsnmp_tdomain_transport(cp, 1, "udp");
1324 if (transport == NULL) {
1325 snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n",
1326 cp, errno, strerror(errno));
1327 snmptrapd_close_sessions(sess_list);
1328 SOCK_CLEANUP;
1329 exit(1);
1330 } else {
1331 ss = snmptrapd_add_session(transport);
1332 if (ss == NULL) {
1334 * Shouldn't happen? We have already opened the transport
1335 * successfully so what could have gone wrong?
1337 snmptrapd_close_sessions(sess_list);
1338 netsnmp_transport_free(transport);
1339 if (Syslog) {
1340 snmp_log(LOG_ERR, "couldn't open snmp - %m");
1342 SOCK_CLEANUP;
1343 exit(1);
1344 } else {
1345 ss->next = sess_list;
1346 sess_list = ss;
1351 * Process next listen address, if there is one.
1354 if (sep != NULL) {
1355 *sep = ',';
1356 cp = sep + 1;
1357 } else {
1358 cp = NULL;
1362 signal(SIGTERM, term_handler);
1363 #ifdef SIGHUP
1364 signal(SIGHUP, hup_handler);
1365 #endif
1366 signal(SIGINT, term_handler);
1368 while (running) {
1369 if (reconfig) {
1370 if (Print) {
1371 struct tm *tm;
1372 time_t timer;
1373 time(&timer);
1374 tm = localtime(&timer);
1377 * If we are logging to a file, receipt of SIGHUP also
1378 * indicates the the log file should be closed and re-opened.
1379 * This is useful for users that want to rotate logs in a more
1380 * predictable manner.
1382 if (logfile) {
1383 snmp_enable_filelog(logfile, 1);
1385 snmp_log(LOG_INFO,"%.4d-%.2d-%.2d %.2d:%.2d:%.2d "
1386 "NET-SNMP version %s Reconfigured.\n",
1387 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
1388 tm->tm_hour, tm->tm_min, tm->tm_sec,
1389 netsnmp_get_version());
1392 if (Syslog)
1393 snmp_log(LOG_INFO, "Snmptrapd reconfiguring");
1394 trapd_update_config();
1395 if (trap1_fmt_str_remember) {
1396 free_trap1_fmt();
1397 trap1_fmt_str = strdup(trap1_fmt_str_remember);
1399 reconfig = 0;
1401 numfds = 0;
1402 FD_ZERO(&fdset);
1403 block = 0;
1404 tvp = &timeout;
1405 timerclear(tvp);
1406 tvp->tv_sec = 5;
1407 snmp_select_info(&numfds, &fdset, tvp, &block);
1408 if (block == 1)
1409 tvp = NULL; /* block without timeout */
1410 count = select(numfds, &fdset, 0, 0, tvp);
1411 gettimeofday(&Now, 0);
1412 if (count > 0) {
1413 snmp_read(&fdset);
1414 } else
1415 switch (count) {
1416 case 0:
1417 snmp_timeout();
1418 break;
1419 case -1:
1420 if (errno == EINTR)
1421 continue;
1422 snmp_log_perror("select");
1423 running = 0;
1424 break;
1425 default:
1426 fprintf(stderr, "select returned %d\n", count);
1427 running = 0;
1431 if (Print) {
1432 struct tm *tm;
1433 time_t timer;
1434 time(&timer);
1435 tm = localtime(&timer);
1436 snmp_log(LOG_INFO,
1437 "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n",
1438 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
1439 tm->tm_min, tm->tm_sec, netsnmp_get_version());
1441 if (Syslog) {
1442 snmp_log(LOG_INFO, "Stopping snmptrapd");
1445 snmptrapd_close_sessions(sess_list);
1446 snmp_shutdown("snmptrapd");
1447 snmp_disable_log();
1448 SOCK_CLEANUP;
1449 return 0;
1453 * Read the configuration files. Implemented as a signal handler so that
1454 * receipt of SIGHUP will cause configuration to be re-read when the
1455 * trap deamon is running detatched from the console.
1458 void
1459 trapd_update_config(void)
1461 free_config();
1462 read_configs();
1466 #if !defined(HAVE_GETDTABLESIZE) && !defined(WIN32)
1467 #include <sys/resource.h>
1469 getdtablesize(void)
1471 struct rlimit rl;
1472 getrlimit(RLIMIT_NOFILE, &rl);
1473 return (rl.rlim_cur);
1475 #endif