2 * snmptrapd.c - receive and log snmp traps
5 /*****************************************************************
6 Copyright 1989, 1991, 1992 by Carnegie Mellon University
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
25 ******************************************************************/
26 #include <net-snmp/net-snmp-config.h>
39 #include <sys/types.h>
46 #include <sys/socket.h>
49 #include <sys/sockio.h>
52 #include <netinet/in.h>
56 # include <sys/time.h>
57 # if TIME_WITH_SYS_TIME
64 #include <sys/select.h>
67 #include <sys/param.h>
73 #include <sys/ioctl.h>
82 #include <arpa/inet.h>
87 #if HAVE_PROCESS_H /* Win32-getpid */
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"
102 int allow_severity
= LOG_INFO
;
103 int deny_severity
= LOG_WARNING
;
107 * #define NETSNMP_DS_APP_DONT_LOG 9 defined in notification_log.h
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)))
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.
145 #define LOG_CONS 0 /* Don't bother if not defined... */
148 #define LOG_PID 0 /* Don't bother if not defined... */
179 * Include an extra Facility variable to allow command line adjustment of
182 int Facility
= LOG_DAEMON
;
186 void trapd_update_config(void);
189 trap_description(int trap
)
192 case SNMP_TRAP_COLDSTART
:
194 case SNMP_TRAP_WARMSTART
:
196 case SNMP_TRAP_LINKDOWN
:
198 case SNMP_TRAP_LINKUP
:
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";
207 return "Unknown Type";
213 snmp_clone_pdu2(netsnmp_pdu
*pdu
, int command
)
215 netsnmp_pdu
*newpdu
= snmp_clone_pdu(pdu
);
217 newpdu
->command
= command
;
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 };
227 event_input(netsnmp_variable_list
* vp
)
230 oid variable
[MAX_OID_LEN
];
239 netsnmp_variable_list
*vp2
= vp
;
243 /* Make sure there are 5 variables. Otherwise, don't bother */
244 for (i
=1; i
<= 5; i
++) {
245 vp2
= vp2
->next_variable
;
254 vp
= vp
->next_variable
; /* skip sysUptime */
255 if (vp
->val_len
!= sizeof(risingAlarm
) ||
256 !memcmp(vp
->val
.objid
, risingAlarm
, sizeof(risingAlarm
)))
258 else if (vp
->val_len
!= sizeof(risingAlarm
) ||
259 !memcmp(vp
->val
.objid
, fallingAlarm
, sizeof(fallingAlarm
)))
261 else if (vp
->val_len
!= sizeof(risingAlarm
) ||
262 !memcmp(vp
->val
.objid
, unavailableAlarm
, sizeof(unavailableAlarm
)))
265 fprintf(stderr
, "unknown event\n");
269 vp
= vp
->next_variable
;
270 memmove(variable
, vp
->val
.objid
, vp
->val_len
* sizeof(oid
));
271 variablelen
= vp
->val_len
;
274 destip
|= (*op
++) << 24;
275 destip
|= (*op
++) << 16;
276 destip
|= (*op
++) << 8;
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
,
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
;
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
);
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
);
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
;
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
);
371 do_external(char *cmd
, struct hostent
*host
,
372 netsnmp_pdu
*pdu
, netsnmp_transport
*transport
)
375 int oldquick
, result
;
377 DEBUGMSGTL(("snmptrapd", "Running: %s\n", cmd
));
378 oldquick
= snmp_get_quick_print();
379 snmp_set_quick_print(1);
386 snmp_log_perror("pipe");
388 if ((pid
= fork()) == 0) {
393 if (dup(fd
[0]) != 0) {
394 snmp_log_perror("dup");
400 } else if (pid
> 0) {
401 file
= fdopen(fd
[1], "w");
402 send_handler_data(file
, host
, pdu
, transport
);
406 if (waitpid(pid
, &result
, 0) < 0) {
407 snmp_log_perror("waitpid");
410 snmp_log_perror("fork");
413 char command_buf
[128];
414 char file_buf
[L_tmpnam
];
417 file
= fopen(file_buf
, "w");
419 fprintf(stderr
, "fopen: %s: %s\n", file_buf
, strerror(errno
));
421 send_handler_data(file
, host
, pdu
, transport
);
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
);
428 fprintf(stderr
, "system: %s: %s\n", command_buf
,
431 fprintf(stderr
, "system: %s: %d\n", command_buf
, result
);
436 snmp_set_quick_print(oldquick
);
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
;
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
;
454 size_t r_len
= 64, o_len
= 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");
465 if (pdu
->command
== SNMP_MSG_TRAP
) {
466 oid trapOid
[MAX_OID_LEN
+ 2] = { 0 };
467 int trapOidLen
= pdu
->enterprise_length
;
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
||
486 if ((trap1_fmt_str
== NULL
) || (trap1_fmt_str
[0] == '\0')) {
487 trunc
= !realloc_format_plain_trap(&rbuf
, &r_len
, &o_len
,
490 trunc
= !realloc_format_trap(&rbuf
, &r_len
, &o_len
, 1,
494 snmp_log(LOG_INFO
, "%s%s", rbuf
, (trunc
?" [TRUNCATED]\n":""));
497 if (Syslog
&& (pdu
->trap_type
!= SNMP_TRAP_AUTHFAIL
||
499 memset(rbuf
, 0, o_len
);
504 for (vars
= pdu
->variables
; vars
;
505 vars
= vars
->next_variable
) {
506 trunc
= !sprint_realloc_variable(&rbuf
, &r_len
, &o_len
, 1,
508 vars
->name_length
, vars
);
511 * Add a trailing , ...
513 trunc
= !snmp_strcat(&rbuf
, &r_len
, &o_len
, 1, ", ");
520 if (o_len
> 0 && !trunc
) {
525 if (pdu
->trap_type
== SNMP_TRAP_ENTERPRISESPECIFIC
) {
526 u_char
*oidbuf
= NULL
;
527 size_t ob_len
= 64, oo_len
= 0;
530 if ((oidbuf
= (u_char
*) calloc(ob_len
, 1)) == NULL
) {
532 "couldn't display trap -- malloc failed\n");
537 otrunc
= !sprint_realloc_objid(&oidbuf
, &ob_len
, &oo_len
,
538 1, trapOid
, trapOidLen
);
540 cp
= strrchr((char *) oidbuf
, '.');
544 cp
= (char *) oidbuf
;
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" : ""));
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
),
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
);
568 trapoids
[9] = pdu
->trap_type
+ 1;
569 Command
= snmptrapd_get_traphandler(trapoids
, 10);
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
) {
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
)) {
590 if (transport
!= NULL
591 && transport
->domain
== netsnmpUDPDomain
) {
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
;
601 pdu
->transport_data_length
== sizeof(struct sockaddr_in
)) {
602 host
= gethostbyaddr((char *) &(addr
->sin_addr
),
603 sizeof(struct in_addr
), AF_INET
);
609 if (trap2_fmt_str
== NULL
|| trap2_fmt_str
[0] == '\0') {
610 trunc
= !realloc_format_trap(&rbuf
, &r_len
, &o_len
, 1,
614 trunc
= !realloc_format_trap(&rbuf
, &r_len
, &o_len
, 1,
618 snmp_log(LOG_INFO
, "%s%s", rbuf
, (trunc
?" [TRUNCATED]":""));
622 memset(rbuf
, 0, o_len
);
624 for (vars
= pdu
->variables
; vars
;
625 vars
= vars
->next_variable
) {
626 trunc
= !sprint_realloc_variable(&rbuf
, &r_len
, &o_len
, 1,
628 vars
->name_length
, vars
);
630 trunc
= !snmp_strcat(&rbuf
, &r_len
, &o_len
, 1, ", ");
637 if (o_len
> 0 && !trunc
) {
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
)) {
655 if (transport
!= NULL
656 && transport
->domain
== netsnmpUDPDomain
) {
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
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
,
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]" : ""));
683 snmp_log(LOG_WARNING
, "<UNKNOWN>: Trap %s%s", rbuf
,
684 (trunc
? "[TRUNCATED]\n" : ""));
689 event_input(pdu
->variables
);
692 for (vars
= pdu
->variables
; (vars
!= NULL
) &&
693 snmp_oid_compare(vars
->name
, vars
->name_length
,
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
));
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
){
711 "couldn't clone PDU for INFORM response\n");
715 if (!snmp_send(session
, reply
)) {
716 snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
718 snmp_free_pdu(reply
);
727 } else if (op
== NETSNMP_CALLBACK_OP_TIMED_OUT
) {
728 fprintf(stderr
, "Timeout: This shouldn't happen!\n");
735 parse_trap1_fmt(const char *token
, char *line
)
737 trap1_fmt_str
= strdup(line
);
744 if (trap1_fmt_str
&& trap1_fmt_str
!= trap1_std_str
)
745 free((char *) trap1_fmt_str
);
746 trap1_fmt_str
= NULL
;
751 parse_trap2_fmt(const char *token
, char *line
)
753 trap2_fmt_str
= strdup(line
);
760 if (trap2_fmt_str
&& trap2_fmt_str
!= trap2_std_str
)
761 free((char *) trap2_fmt_str
);
762 trap2_fmt_str
= NULL
;
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");
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");
781 " -e\t\t\tprint event # (rising/falling alarm, etc.)\n");
782 fprintf(stderr
, " -f\t\t\tdo not fork from the shell\n");
784 " -F FORMAT\t\tuse specified format for logging to standard error\n");
785 fprintf(stderr
, " -h, --help\t\tdisplay this usage message\n");
787 " -H\t\t\tdisplay configuration file directives understood\n");
789 " -m MIBLIST\t\tuse MIBLIST instead of the default MIB list\n");
791 " -M DIRLIST\t\tuse DIRLIST as the list of locations\n\t\t\t to look for MIBs\n");
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");
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");
800 fprintf(stderr
, " -u FILE\t\tstore process id in FILE\n");
802 fprintf(stderr
, " -v, --version\t\tdisplay version information\n");
804 " -O <OUTOPTS>\t\ttoggle options controlling output display\n");
805 snmp_out_toggle_options_usage("\t\t\t", stderr
);
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");
818 term_handler(int sig
)
828 signal(SIGHUP
, hup_handler
);
833 pre_parse(netsnmp_session
* session
, netsnmp_transport
*transport
,
834 void *transport_data
, int transport_data_length
)
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) {
858 if (hosts_ctl("snmptrapd", STRING_UNKNOWN
,
859 STRING_UNKNOWN
, STRING_UNKNOWN
) == 0) {
863 #endif/* USE_LIBWRAP */
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
);
885 snmp_sess_perror("snmptrapd", session
);
891 snmptrapd_close_sessions(netsnmp_session
* sess_list
)
893 netsnmp_session
*s
= NULL
, *next
= NULL
;
895 for (s
= sess_list
; s
!= NULL
; s
= next
) {
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
;
908 int count
, numfds
, block
;
910 struct timeval timeout
, *tvp
;
912 char *cp
, *listen_ports
= NULL
;
913 char *trap1_fmt_str_remember
= NULL
;
914 int agentx_subagent
= 1, depmsg
= 0;
917 char *pid_file
= NULL
;
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
);
943 setvbuf(stdout
, NULL
, _IONBF
, BUFSIZ
);
945 setvbuf(stdout
, NULL
, _IOLBF
, BUFSIZ
);
949 * Add some options if they are available.
952 strcat(options
, "u:");
956 * Now process options normally.
959 while ((arg
= getopt(argc
, argv
, options
)) != EOF
) {
962 if (strcasecmp(optarg
, "help") == 0) {
966 if (strcasecmp(optarg
, "version") == 0) {
971 handle_long_opt(optarg
);
979 if (optarg
!= NULL
) {
980 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID
,
981 NETSNMP_DS_LIB_OPTIONALCONFIG
, optarg
);
989 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID
,
990 NETSNMP_DS_LIB_DONT_READ_CONFIGS
, 1);
994 snmp_set_dump_packet(1);
998 debug_register_tokens(optarg
);
999 snmp_set_do_debugging(1);
1011 if (optarg
!= NULL
) {
1012 trap1_fmt_str_remember
= optarg
;
1024 init_notification_log();
1025 init_snmp("snmptrapd");
1026 fprintf(stderr
, "Configuration directives understood:\n");
1027 read_config_print_usage(" ");
1032 "Warning: -l option is deprecated; use -S instead\n");
1035 if (optarg
!= NULL
) {
1039 Facility
= LOG_DAEMON
;
1043 Facility
= LOG_INFO
;
1046 Facility
= LOG_LOCAL0
;
1049 Facility
= LOG_LOCAL1
;
1052 Facility
= LOG_LOCAL2
;
1055 Facility
= LOG_LOCAL3
;
1058 Facility
= LOG_LOCAL4
;
1061 Facility
= LOG_LOCAL5
;
1064 Facility
= LOG_LOCAL6
;
1067 Facility
= LOG_LOCAL7
;
1070 fprintf(stderr
, "invalid syslog facility: -S%c\n",*optarg
);
1075 fprintf(stderr
, "no syslog facility specified\n");
1082 if (optarg
!= NULL
) {
1083 setenv("MIBS", optarg
, 1);
1091 if (optarg
!= NULL
) {
1092 setenv("MIBDIRS", optarg
, 1);
1100 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID
,
1101 NETSNMP_DS_APP_NUMERIC_IP
, 1);
1106 if (optarg
!= NULL
) {
1108 snmp_enable_filelog(optarg
, 0);
1116 cp
= snmp_out_toggle_options(optarg
);
1118 fprintf(stderr
, "Unknown output option passed to -O: %c\n",
1126 snmp_enable_stderrlog();
1136 if (optarg
!= NULL
) {
1152 fprintf(stderr
, "invalid option: -%c\n", arg
);
1159 if (optind
< argc
) {
1161 * There are optional transport addresses on the command line.
1163 for (i
= optind
; i
< argc
; i
++) {
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
);
1171 sprintf(astring
, "%s,%s", listen_ports
, argv
[i
]);
1173 listen_ports
= astring
;
1175 listen_ports
= strdup(argv
[i
]);
1176 if (listen_ports
== NULL
) {
1177 fprintf(stderr
, "malloc failure processing argv[%d]\n", i
);
1183 listen_ports
= default_port
;
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);
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
1225 init_notification_log();
1229 * Initialize the world. Create initial user
1231 init_snmp("snmptrapd");
1232 if (trap1_fmt_str_remember
) {
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.
1249 * fork the process to the background if we are not printing to stderr
1251 if (dofork
&& running
) {
1256 fprintf(stderr
, "bad fork - %s\n", strerror(errno
));
1261 * become process group leader
1263 if (setsid() == -1) {
1264 fprintf(stderr
, "bad setsid - %s\n", strerror(errno
));
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
);
1284 if (pid_file
!= NULL
) {
1285 if ((PID
= fopen(pid_file
, "w")) == NULL
) {
1286 snmp_log_perror(pid_file
);
1289 fprintf(PID
, "%d\n", (int) getpid());
1295 snmp_enable_syslog_ident("snmptrapd", Facility
);
1296 snmp_log(LOG_INFO
, "Starting snmptrapd %s\n", netsnmp_get_version());
1298 snmp_log(LOG_WARNING
, "-l option is deprecated; use -S instead\n");
1305 tm
= localtime(&timer
);
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());
1317 while (cp
!= NULL
) {
1318 char *sep
= strchr(cp
, ',');
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
);
1331 ss
= snmptrapd_add_session(transport
);
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
);
1340 snmp_log(LOG_ERR
, "couldn't open snmp - %m");
1345 ss
->next
= sess_list
;
1351 * Process next listen address, if there is one.
1362 signal(SIGTERM
, term_handler
);
1364 signal(SIGHUP
, hup_handler
);
1366 signal(SIGINT
, term_handler
);
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.
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());
1393 snmp_log(LOG_INFO
, "Snmptrapd reconfiguring");
1394 trapd_update_config();
1395 if (trap1_fmt_str_remember
) {
1397 trap1_fmt_str
= strdup(trap1_fmt_str_remember
);
1407 snmp_select_info(&numfds
, &fdset
, tvp
, &block
);
1409 tvp
= NULL
; /* block without timeout */
1410 count
= select(numfds
, &fdset
, 0, 0, tvp
);
1411 gettimeofday(&Now
, 0);
1422 snmp_log_perror("select");
1426 fprintf(stderr
, "select returned %d\n", count
);
1435 tm
= localtime(&timer
);
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());
1442 snmp_log(LOG_INFO
, "Stopping snmptrapd");
1445 snmptrapd_close_sessions(sess_list
);
1446 snmp_shutdown("snmptrapd");
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.
1459 trapd_update_config(void)
1466 #if !defined(HAVE_GETDTABLESIZE) && !defined(WIN32)
1467 #include <sys/resource.h>
1472 getrlimit(RLIMIT_NOFILE
, &rl
);
1473 return (rl
.rlim_cur
);