summaryrefslogtreecommitdiff
path: root/usr.sbin/snmpd
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2008-01-16 19:36:07 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2008-01-16 19:36:07 +0000
commit30a6a57434dccbe1344c874f0241339612913209 (patch)
tree0be5644d3f6a32ee5a930aba2b1f7981d1bccbb0 /usr.sbin/snmpd
parent2c9cd77dfb76942480fde4b9025e1691b097919a (diff)
implementation of the SNMP trap sender interface
Diffstat (limited to 'usr.sbin/snmpd')
-rw-r--r--usr.sbin/snmpd/control.c4
-rw-r--r--usr.sbin/snmpd/parse.y39
-rw-r--r--usr.sbin/snmpd/snmpd.c27
-rw-r--r--usr.sbin/snmpd/snmpd.h32
-rw-r--r--usr.sbin/snmpd/snmpe.c41
-rw-r--r--usr.sbin/snmpd/trap.c99
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);
+}