diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-01-16 19:36:07 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-01-16 19:36:07 +0000 |
commit | 30a6a57434dccbe1344c874f0241339612913209 (patch) | |
tree | 0be5644d3f6a32ee5a930aba2b1f7981d1bccbb0 /usr.sbin/snmpd | |
parent | 2c9cd77dfb76942480fde4b9025e1691b097919a (diff) |
implementation of the SNMP trap sender interface
Diffstat (limited to 'usr.sbin/snmpd')
-rw-r--r-- | usr.sbin/snmpd/control.c | 4 | ||||
-rw-r--r-- | usr.sbin/snmpd/parse.y | 39 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpd.c | 27 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpd.h | 32 | ||||
-rw-r--r-- | usr.sbin/snmpd/snmpe.c | 41 | ||||
-rw-r--r-- | usr.sbin/snmpd/trap.c | 99 |
6 files changed, 173 insertions, 69 deletions
diff --git a/usr.sbin/snmpd/control.c b/usr.sbin/snmpd/control.c index 8ee5be5d1b7..333f6ad2000 100644 --- a/usr.sbin/snmpd/control.c +++ b/usr.sbin/snmpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.3 2008/01/16 09:42:29 reyk Exp $ */ +/* $OpenBSD: control.c,v 1.4 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -231,7 +231,7 @@ control_dispatch_imsg(int fd, short event, void *arg) c->flags |= CTL_CONN_NOTIFY; break; case IMSG_SNMP_TRAP: - if (trap_request(&c->ibuf, imsg.hdr.pid) == -1) { + if (trap_imsg(&c->ibuf, imsg.hdr.pid) == -1) { log_debug("control_dispatch_imsg: " "received invalid trap (pid %d)", imsg.hdr.pid); diff --git a/usr.sbin/snmpd/parse.y b/usr.sbin/snmpd/parse.y index a160f368861..9af9ee54ee9 100644 --- a/usr.sbin/snmpd/parse.y +++ b/usr.sbin/snmpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.8 2008/01/16 09:51:15 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.9 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> @@ -81,8 +81,9 @@ struct sym { int symset(const char *, const char *, int); char *symget(const char *); -struct snmpd *conf = NULL; -static int errors = 0; +struct snmpd *conf = NULL; +static int errors = 0; +static struct addresslist *hlist; struct address *host_v4(const char *); struct address *host_v6(const char *); @@ -112,7 +113,7 @@ typedef struct { %token INCLUDE %token LISTEN ON %token SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES -%token READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP +%token READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER %token ERROR %token <v.string> STRING %token <v.number> NUMBER @@ -199,6 +200,11 @@ main : LISTEN ON STRING { } free($3); } + | TRAP RECEIVER { + hlist = &conf->sc_trapreceivers; + } host { + hlist = NULL; + } ; system : SYSTEM sysmib @@ -299,6 +305,29 @@ oid : STRING { } ; +hostdef : STRING { + if (host($1, hlist, 1, + SNMPD_TRAPPORT, NULL) <= 0) { + yyerror("invalid host: %s", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +hostlist : /* empty */ + | hostlist comma hostdef + ; + +host : hostdef + | '{' hostlist '}' + ; + +comma : /* empty */ + | ',' + ; + %% struct keywords { @@ -343,6 +372,7 @@ lookup(char *s) { "on", ON }, { "read-only", READONLY }, { "read-write", READWRITE }, + { "receiver", RECEIVER }, { "services", SERVICES }, { "string", OCTETSTRING }, { "system", SYSTEM }, @@ -684,6 +714,7 @@ parse_config(const char *filename, u_int flags) strlcpy(conf->sc_rdcommunity, "public", SNMPD_MAXCOMMUNITYLEN); strlcpy(conf->sc_rwcommunity, "private", SNMPD_MAXCOMMUNITYLEN); strlcpy(conf->sc_trcommunity, "public", SNMPD_MAXCOMMUNITYLEN); + TAILQ_INIT(&conf->sc_trapreceivers); if ((file = pushfile(filename, 0)) == NULL) { free(conf); diff --git a/usr.sbin/snmpd/snmpd.c b/usr.sbin/snmpd/snmpd.c index 06783dd8141..1d61bc7f7d0 100644 --- a/usr.sbin/snmpd/snmpd.c +++ b/usr.sbin/snmpd/snmpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpd.c,v 1.3 2008/01/16 09:51:15 reyk Exp $ */ +/* $OpenBSD: snmpd.c,v 1.4 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> @@ -293,3 +293,28 @@ snmpd_dispatch_snmpe(int fd, short event, void * ptr) } imsg_event_add(ibuf); } + +int +snmpd_socket_af(struct sockaddr_storage *ss, in_port_t port) +{ + int s; + + switch (ss->ss_family) { + case AF_INET: + ((struct sockaddr_in *)ss)->sin_port = port; + ((struct sockaddr_in *)ss)->sin_len = + sizeof(struct sockaddr_in); + break; + case AF_INET6: + ((struct sockaddr_in6 *)ss)->sin6_port = port; + ((struct sockaddr_in6 *)ss)->sin6_len = + sizeof(struct sockaddr_in6); + break; + default: + return (-1); + } + + s = socket(ss->ss_family, SOCK_DGRAM, IPPROTO_UDP); + return (s); +} + diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h index e47c9b2c2ef..942ad05d5a6 100644 --- a/usr.sbin/snmpd/snmpd.h +++ b/usr.sbin/snmpd/snmpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpd.h,v 1.13 2008/01/16 09:51:15 reyk Exp $ */ +/* $OpenBSD: snmpd.h,v 1.14 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> @@ -47,14 +47,6 @@ #define RT_BUF_SIZE 16384 #define MAX_RTSOCK_BUF (128 * 1024) -struct address { - struct sockaddr_storage ss; - in_port_t port; - char ifname[IFNAMSIZ]; - TAILQ_ENTRY(address) entry; -}; -TAILQ_HEAD(addresslist, address); - /* * imsg framework and privsep */ @@ -306,6 +298,19 @@ struct snmp_stats { u_int32_t snmp_proxydrops; }; +struct address { + struct sockaddr_storage ss; + in_port_t port; + char ifname[IFNAMSIZ]; + + TAILQ_ENTRY(address) entry; + + /* For SNMP trap receivers etc. */ + char *sa_community; + struct ber_oid *sa_oid; +}; +TAILQ_HEAD(addresslist, address); + struct snmpd { u_int8_t sc_flags; #define SNMPD_F_VERBOSE 0x01 @@ -322,6 +327,8 @@ struct snmpd { char sc_trcommunity[SNMPD_MAXCOMMUNITYLEN]; struct snmp_stats sc_stats; + + struct addresslist sc_trapreceivers; }; /* control.c */ @@ -387,9 +394,11 @@ struct kif_addr *kr_getnextaddr(struct in_addr *); /* snmpe.c */ pid_t snmpe(struct snmpd *, int [2]); +void snmpe_debug_elements(struct ber_element *); /* trap.c */ -int trap_request(struct imsgbuf *, pid_t); +int trap_imsg(struct imsgbuf *, pid_t); +int trap_send(struct ber_element *, struct ber_oid *); /* mps.c */ struct ber_element * @@ -424,4 +433,7 @@ void smi_delete(struct oid *); void smi_insert(struct oid *); int smi_oid_cmp(struct oid *, struct oid *); +/* snmpd.c */ +int snmpd_socket_af(struct sockaddr_storage *, in_port_t); + #endif /* _SNMPD_H */ diff --git a/usr.sbin/snmpd/snmpe.c b/usr.sbin/snmpd/snmpe.c index 9e45bca3bf1..fb122720d3a 100644 --- a/usr.sbin/snmpd/snmpe.c +++ b/usr.sbin/snmpd/snmpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpe.c,v 1.13 2008/01/16 09:51:15 reyk Exp $ */ +/* $OpenBSD: snmpe.c,v 1.14 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> @@ -46,7 +46,6 @@ unsigned long void snmpe_sig_handler(int sig, short, void *); void snmpe_shutdown(void); void snmpe_dispatch_parent(int, short, void *); -int snmpe_socket_af(struct sockaddr_storage *, in_port_t); int snmpe_bind(struct address *); void snmpe_recvmsg(int fd, short, void *); @@ -217,37 +216,13 @@ snmpe_dispatch_parent(int fd, short event, void * ptr) } int -snmpe_socket_af(struct sockaddr_storage *ss, in_port_t port) -{ - switch (ss->ss_family) { - case AF_INET: - ((struct sockaddr_in *)ss)->sin_port = port; - ((struct sockaddr_in *)ss)->sin_len = - sizeof(struct sockaddr_in); - break; - case AF_INET6: - ((struct sockaddr_in6 *)ss)->sin6_port = port; - ((struct sockaddr_in6 *)ss)->sin6_len = - sizeof(struct sockaddr_in6); - break; - default: - return (-1); - } - - return (0); -} - -int snmpe_bind(struct address *addr) { char buf[512]; - int s = -1; + int s; - if (snmpe_socket_af(&addr->ss, htons(addr->port)) == -1) - goto bad; - - if ((s = socket(addr->ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) - goto bad; + if ((s = snmpd_socket_af(&addr->ss, htons(addr->port))) == -1) + return (-1); /* * Socket options @@ -266,13 +241,12 @@ snmpe_bind(struct address *addr) return (s); bad: - if (s != -1) - close(s); + close(s); return (-1); } #ifdef DEBUG -static void +void snmpe_debug_elements(struct ber_element *root) { static int indent = 0; @@ -738,10 +712,11 @@ snmpe_recvmsg(int fd, short sig, void *arg) stats->snmp_inpkts++; + bzero(&ber, sizeof(ber)); ber.fd = -1; ber_set_application(&ber, snmpe_application); - ber_set_readbuf(&ber, buf, len); + req = ber_read_elements(&ber, NULL); if (req == NULL) { diff --git a/usr.sbin/snmpd/trap.c b/usr.sbin/snmpd/trap.c index 4ea84b9d282..513ad313c1f 100644 --- a/usr.sbin/snmpd/trap.c +++ b/usr.sbin/snmpd/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.2 2008/01/16 09:45:17 reyk Exp $ */ +/* $OpenBSD: trap.c,v 1.3 2008/01/16 19:36:06 reyk Exp $ */ /* * Copyright (c) 2008 Reyk Floeter <reyk@vantronix.net> @@ -38,22 +38,32 @@ #include <pwd.h> #include "snmpd.h" +#include "mib.h" + +extern struct snmpd *env; int -trap_request(struct imsgbuf *ibuf, pid_t pid) +trap_imsg(struct imsgbuf *ibuf, pid_t pid) { - struct imsg imsg; - int ret = -1, n, x = 0; - int done = 0; + struct imsg imsg; + int ret = -1, n, x = 0; + int done = 0; struct snmp_imsg *sm; - u_int32_t d; - u_int64_t l; + u_int32_t d; + u_int64_t l; u_int8_t *c; - char o[SNMP_MAX_OID_LEN]; + char ostr[SNMP_MAX_OID_LEN]; struct ber_element *ber, *trap = NULL, *oid = NULL, *a; size_t len; + struct ber_oid o; + struct ber_oid uptime = OID(MIB_sysUpTime); + struct ber_oid trapoid = OID(MIB_snmpTrapOID); - ber = trap = ber_add_sequence(NULL); + bzero(&o, sizeof(o)); + smi_oidlen(&uptime); + ber = trap = ber_printf_elements(NULL, "{{Oit}", + &uptime, smi_getticks(), + BER_CLASS_APPLICATION, SNMP_T_TIMETICKS); while (!done) { while (!done) { @@ -73,8 +83,10 @@ trap_request(struct imsgbuf *ibuf, pid_t pid) /* First element must be the trap OID */ if (sm->snmp_type != SNMP_NULL) goto imsgdone; + ber_string2oid(sm->snmp_oid, &o); + smi_oidlen(&trapoid); ber = oid = ber_printf_elements(ber, - "{o0}", sm->snmp_oid); + "{OO}", &trapoid, &o); break; } @@ -83,10 +95,10 @@ trap_request(struct imsgbuf *ibuf, pid_t pid) switch (sm->snmp_type) { case SNMP_OBJECT: - if (sm->snmp_len != sizeof(o)) + if (sm->snmp_len != sizeof(ostr)) goto imsgdone; - bcopy(sm + 1, &o, sm->snmp_len); - a = ber_add_oidstring(a, o); + bcopy(sm + 1, &ostr, sm->snmp_len); + a = ber_add_oidstring(a, ostr); break; case SNMP_BITSTRING: case SNMP_OCTETSTRING: @@ -167,13 +179,10 @@ trap_request(struct imsgbuf *ibuf, pid_t pid) } len = ber_calc_len(trap); - log_debug("snmpe_trap: %d bytes from pid %d", len, pid); - -#ifdef DEBUG - snmpe_debug_elements(trap); -#endif + smi_oidstring(&o, ostr, sizeof(ostr)); + log_debug("trap_imsg: %s, len %d, pid %d", ostr, len, pid); - /* XXX send trap to registered receivers */ + trap_send(trap, &o); ret = 0; imsgdone: @@ -183,3 +192,55 @@ trap_request(struct imsgbuf *ibuf, pid_t pid) ber_free_elements(trap); return (ret); } + +int +trap_send(struct ber_element *trap, struct ber_oid *oid) +{ + int ok = 0, s; + struct address *tr; + struct ber_element *root, *b; + struct ber ber; + char *c; + ssize_t len; + u_int8_t *ptr; + + if (TAILQ_EMPTY(&env->sc_trapreceivers)) + return (0); + + bzero(&ber, sizeof(ber)); + ber.fd = -1; + + TAILQ_FOREACH(tr, &env->sc_trapreceivers, entry) { + if (tr->sa_oid != NULL && tr->sa_oid->bo_n) + /* XXX only send if the OID is specified */; + + if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) + return (-1); + + c = tr->sa_community != NULL ? + tr->sa_community : env->sc_trcommunity; + + /* SNMP header */ + root = ber_add_sequence(NULL); + b = ber_printf_elements(root, "ds{tiii", + SNMP_V2, c, BER_CLASS_CONTEXT, SNMP_C_TRAPV2, + arc4random(), 0, 0); + ber_link_elements(b, trap); + +#ifdef DEBUG + snmpe_debug_elements(root); +#endif + + len = ber_write_elements(&ber, root); + if (ber_get_writebuf(&ber, (void *)&ptr) > 0 && + sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss, + tr->ss.ss_len) != -1) + env->sc_stats.snmp_outpkts++; + + close(s); + ber_unlink_elements(b); + ber_free_elements(root); + } + + return (ok); +} |