From 031fa3c3eee7859e08bdb17182579db193dfa644 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Wed, 16 Jan 2008 09:36:31 +0000 Subject: start working on an interface to send traps via snmpd.sock. userland applications will be able to send imsgs defining the trap to snmpd and the daemon will do the ASN.1/BER encoding before sending traps to the registered receivers. there are two advantages of this approach that a) the applications do not need to handle any ASN.1/BER encoding and b) snmpd will provide a central interface to define trap receivers. discussed with thib and others --- usr.sbin/snmpd/control.c | 12 +++- usr.sbin/snmpd/snmp.h | 52 +++++++++++++++- usr.sbin/snmpd/snmpd.h | 3 +- usr.sbin/snmpd/snmpe.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 217 insertions(+), 4 deletions(-) diff --git a/usr.sbin/snmpd/control.c b/usr.sbin/snmpd/control.c index 24023e798c5..a048f652fa5 100644 --- a/usr.sbin/snmpd/control.c +++ b/usr.sbin/snmpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.1 2007/12/05 09:22:44 reyk Exp $ */ +/* $OpenBSD: control.c,v 1.2 2008/01/16 09:36:30 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -230,6 +230,16 @@ control_dispatch_imsg(int fd, short event, void *arg) } c->flags |= CTL_CONN_NOTIFY; break; + case IMSG_SNMP_TRAP: + if (snmpe_trap(&c->ibuf, imsg.hdr.pid) == -1) { + log_debug("control_dispatch_imsg: " + "received invalid trap (pid %d)", + imsg.hdr.pid); + imsg_free(&imsg); + control_close(fd); + return; + } + break; default: log_debug("control_dispatch_imsg: " "error handling imsg %d", imsg.hdr.type); diff --git a/usr.sbin/snmpd/snmp.h b/usr.sbin/snmpd/snmp.h index 0ba2d24d287..7d67cb44252 100644 --- a/usr.sbin/snmpd/snmp.h +++ b/usr.sbin/snmpd/snmp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: snmp.h,v 1.2 2008/01/11 12:12:14 reyk Exp $ */ +/* $OpenBSD: snmp.h,v 1.3 2008/01/16 09:36:30 reyk Exp $ */ /* * Copyright (c) 2007 Reyk Floeter @@ -19,6 +19,54 @@ #ifndef SNMP_HEADER #define SNMP_HEADER +/* + * SNMP IMSG interface + */ + +#define SNMP_MAX_OID_LEN 128 /* max size of the OID _string_ */ +#define SNMP_SOCKET "/var/run/snmpd.sock" + +enum snmp_type { + SNMP_IPADDR = 0, + SNMP_COUNTER32 = 1, + SNMP_GAUGE32 = 2, + SNMP_UNSIGNED32 = 2, + SNMP_TIMETICKS = 3, + SNMP_OPAQUE = 4, + SNMP_NSAPADDR = 5, + SNMP_COUNTER64 = 6, + SNMP_UINTEGER32 = 7, + + SNMP_INTEGER32 = 100, + SNMP_BITSTRING = 101, + SNMP_OCTETSTRING = 102, + SNMP_NULL = 103, + SNMP_OBJECT = 104 +}; + +enum snmp_imsg_ctl { + IMSG_SNMP_TRAP = 1000, /* something that works everywhere */ + IMSG_SNMP_ELEMENT, + IMSG_SNMP_END +}; + +struct snmp_imsg_hdr { + u_int16_t imsg_type; + u_int16_t imsg_len; + u_int32_t imsg_peerid; + pid_t imsg_pid; +}; + +struct snmp_imsg { + char snmp_oid[SNMP_MAX_OID_LEN]; + u_int8_t snmp_type; + u_int16_t snmp_len; +}; + +/* + * SNMP BER types + */ + enum snmp_version { SNMP_V1 = 0, SNMP_V2 = 1, @@ -46,7 +94,9 @@ enum snmp_application { SNMP_T_UNSIGNED32 = 2, SNMP_T_TIMETICKS = 3, SNMP_T_OPAQUE = 4, + SNMP_T_NSAPADDR = 5, SNMP_T_COUNTER64 = 6, + SNMP_T_UINTEGER32 = 7 }; enum snmp_generic_trap { diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h index fc6418536b1..7499ea4231e 100644 --- a/usr.sbin/snmpd/snmpd.h +++ b/usr.sbin/snmpd/snmpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpd.h,v 1.10 2008/01/03 15:03:47 reyk Exp $ */ +/* $OpenBSD: snmpd.h,v 1.11 2008/01/16 09:36:30 reyk Exp $ */ /* * Copyright (c) 2007 Reyk Floeter @@ -387,6 +387,7 @@ struct kif_addr *kr_getnextaddr(struct in_addr *); /* snmpe.c */ pid_t snmpe(struct snmpd *, int [2]); +int snmpe_trap(struct imsgbuf *, pid_t); /* mps.c */ struct ber_element * diff --git a/usr.sbin/snmpd/snmpe.c b/usr.sbin/snmpd/snmpe.c index 4db07333c10..44960a0abf7 100644 --- a/usr.sbin/snmpd/snmpe.c +++ b/usr.sbin/snmpd/snmpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpe.c,v 1.10 2008/01/12 13:57:43 reyk Exp $ */ +/* $OpenBSD: snmpe.c,v 1.11 2008/01/16 09:36:30 reyk Exp $ */ /* * Copyright (c) 2007 Reyk Floeter @@ -804,3 +804,155 @@ snmpe_recvmsg(int fd, short sig, void *arg) if (resp != NULL) ber_free_elements(resp); } + +int +snmpe_trap(struct imsgbuf *ibuf, pid_t pid) +{ + 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_int8_t *c; + char o[SNMP_MAX_OID_LEN]; + struct ber_element *ber, *trap = NULL, *oid = NULL, *a; + size_t len; + + ber = trap = ber_add_sequence(NULL); + + while (!done) { + while (!done) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + goto done; + if (n == 0) + break; + switch (imsg.hdr.type) { + case IMSG_SNMP_ELEMENT: + if (imsg.hdr.len < (IMSG_HEADER_SIZE + + sizeof(struct snmp_imsg))) + goto imsgdone; + + sm = (struct snmp_imsg *)imsg.data; + + if (oid == NULL) { + /* First element must be the trap OID */ + if (sm->snmp_type != SNMP_NULL) + goto imsgdone; + ber = oid = ber_printf_elements(ber, + "{o0}", sm->snmp_oid); + break; + } + + ber = a = ber_add_sequence(ber); + a = ber_add_oidstring(a, sm->snmp_oid); + + switch (sm->snmp_type) { + case SNMP_OBJECT: + if (sm->snmp_len != sizeof(o)) + goto imsgdone; + bcopy(sm + 1, &o, sm->snmp_len); + a = ber_add_oidstring(a, o); + break; + case SNMP_BITSTRING: + case SNMP_OCTETSTRING: + if ((sm->snmp_len < 1) || + (sm->snmp_len >= SNMPD_MAXSTRLEN)) + goto imsgdone; + if ((c = + calloc(1, sm->snmp_len)) == NULL) + goto imsgdone; + bcopy(sm + 1, c, sm->snmp_len); + if (sm->snmp_type == SNMP_BITSTRING) + a = ber_add_bitstring(a, c, + sm->snmp_len); + else + a = ber_add_nstring(a, c, + sm->snmp_len); + a->be_free = 1; + break; + case SNMP_NULL: + a = ber_add_null(a); + break; + case SNMP_INTEGER32: + case SNMP_IPADDR: + case SNMP_COUNTER32: + case SNMP_GAUGE32: + case SNMP_TIMETICKS: + case SNMP_OPAQUE: + case SNMP_UINTEGER32: + if (sm->snmp_len != sizeof(d)) + goto imsgdone; + bcopy(sm + 1, &d, sm->snmp_len); + a = ber_add_integer(a, d); + break; + case SNMP_COUNTER64: + if (sm->snmp_len != sizeof(l)) + goto imsgdone; + bcopy(sm + 1, &l, sm->snmp_len); + a = ber_add_integer(a, d); + break; + default: + log_debug("snmpe_trap: illegal type %d", + sm->snmp_type); + imsg_free(&imsg); + goto imsgdone; + } + switch (sm->snmp_type) { + case SNMP_INTEGER32: + case SNMP_BITSTRING: + case SNMP_OCTETSTRING: + case SNMP_NULL: + case SNMP_OBJECT: + /* universal types */ + break; + case SNMP_IPADDR: + case SNMP_COUNTER32: + case SNMP_GAUGE32: + case SNMP_TIMETICKS: + case SNMP_OPAQUE: + case SNMP_NSAPADDR: + case SNMP_COUNTER64: + case SNMP_UINTEGER32: + /* application-specific types */ + ber_set_header(a, BER_CLASS_APPLICATION, + sm->snmp_type); + break; + } + x++; + break; + case IMSG_SNMP_END: + done = 1; + break; + default: + log_debug("snmpe_trap: illegal imsg %d", + imsg.hdr.type); + goto imsgdone; + } + imsg_free(&imsg); + } + if (done) + break; + if ((n = imsg_read(ibuf)) == -1) + goto done; + if (n == 0) + goto done; + } + + len = ber_calc_len(trap); + log_debug("snmpe_trap: %d bytes from pid %d", len, pid); + + /* XXX send trap to registered receivers */ + +#ifdef DEBUG + snmpe_debug_elements(trap); +#endif + + ret = 0; + imsgdone: + if (ret != 0) + imsg_free(&imsg); + done: + ber_free_elements(trap); + return (ret); +} -- cgit v1.2.3