summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorBret Lambert <blambert@cvs.openbsd.org>2014-04-14 12:56:22 +0000
committerBret Lambert <blambert@cvs.openbsd.org>2014-04-14 12:56:22 +0000
commitcbab090e47298e2dd99f095c98722875d30c0c23 (patch)
treef3dafe43fe9b343e3e1c521b834840261f5c10fe /usr.sbin
parentde35535fa13c0a84b78e2258d19537ad5738e370 (diff)
Adapt snmpctl to use AgentX protocol to send traps
ok reyk@ benno@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/snmpctl/Makefile4
-rw-r--r--usr.sbin/snmpctl/parser.c118
-rw-r--r--usr.sbin/snmpctl/parser.h19
-rw-r--r--usr.sbin/snmpctl/snmpctl.c151
4 files changed, 203 insertions, 89 deletions
diff --git a/usr.sbin/snmpctl/Makefile b/usr.sbin/snmpctl/Makefile
index ea500477728..55cc688a3d0 100644
--- a/usr.sbin/snmpctl/Makefile
+++ b/usr.sbin/snmpctl/Makefile
@@ -1,9 +1,9 @@
-# $Id: Makefile,v 1.6 2014/01/18 05:54:52 martynas Exp $
+# $Id: Makefile,v 1.7 2014/04/14 12:56:21 blambert Exp $
.PATH: ${.CURDIR}/../snmpd
PROG= snmpctl
-SRCS= log.c ber.c smi.c snmpclient.c snmpctl.c parser.c
+SRCS= log.c ber.c smi.c snmpclient.c snmpctl.c parser.c agentx.c
MAN= snmpctl.8
diff --git a/usr.sbin/snmpctl/parser.c b/usr.sbin/snmpctl/parser.c
index c0144308efc..1cd549f8deb 100644
--- a/usr.sbin/snmpctl/parser.c
+++ b/usr.sbin/snmpctl/parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.c,v 1.14 2013/10/07 11:40:09 reyk Exp $ */
+/* $OpenBSD: parser.c,v 1.15 2014/04/14 12:56:21 blambert Exp $ */
/*
* Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
@@ -199,8 +199,6 @@ static const struct token t_string[] = {
};
static struct parse_result res;
-static struct imsgbuf *ibuf;
-static struct snmp_imsg sm;
const struct token *match_token(char *, const struct token []);
void show_valid_args(const struct token []);
@@ -214,6 +212,7 @@ parse(int argc, char *argv[])
bzero(&res, sizeof(res));
res.version = -1;
TAILQ_INIT(&res.oids);
+ TAILQ_INIT(&res.varbinds);
while (argc >= 0) {
if ((match = match_token(argv[0], table)) == NULL) {
@@ -245,16 +244,9 @@ match_token(char *word, const struct token table[])
u_int i, match = 0;
const struct token *t = NULL;
const char *errs = NULL;
- u_int32_t u;
- int32_t d;
- int64_t l;
- struct iovec iov[2];
- int iovcnt = 0;
- struct in_addr in4;
- struct in6_addr in6;
+ int terminal = 0;
struct parse_val *val;
-
- bzero(&iov, sizeof(iov));
+ struct parse_varbind *vb = NULL;
for (i = 0; table[i].type != ENDTOKEN; i++) {
switch (table[i].type) {
@@ -319,109 +311,99 @@ match_token(char *word, const struct token table[])
strlen(word)) == 0) {
match++;
t = &table[i];
- sm.snmp_type = t->value;
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ vb->sm.snmp_type = t->value;
if (t->value == SNMP_NULL)
- iovcnt = 1;
+ terminal = 1;
}
break;
case TRAPOID:
if (word == NULL || strlen(word) == 0)
break;
- if (ibuf == NULL &&
- (ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
+ if ((res.trapoid = strdup(word)) == NULL)
err(1, "malloc");
- res.ibuf = ibuf;
- imsg_init(ibuf, -1);
-
- /* Create a new trap */
- imsg_compose(ibuf, IMSG_SNMP_TRAP,
- 0, 0, -1, NULL, 0);
-
- /* First element must be the trap OID. */
- bzero(&sm, sizeof(sm));
- sm.snmp_type = SNMP_NULL;
- if (strlcpy(sm.snmp_oid, word,
- sizeof(sm.snmp_oid)) >= sizeof(sm.snmp_oid))
- errx(1, "trap oid too long");
- if (imsg_compose(ibuf, IMSG_SNMP_ELEMENT, 0, 0, -1,
- &sm, sizeof(sm)) == -1)
- errx(1, "imsg");
-
match++;
t = &table[i];
break;
case ELEMENTOBJECT:
if (word == NULL || strlen(word) == 0)
break;
- bzero(&sm, sizeof(sm));
- if (strlcpy(sm.snmp_oid, word,
- sizeof(sm.snmp_oid)) >= sizeof(sm.snmp_oid))
+ if ((vb = calloc(1, sizeof(*vb))) == NULL)
+ errx(1, "calloc");
+ if (strlcpy(vb->sm.snmp_oid, word,
+ sizeof(vb->sm.snmp_oid)) >= sizeof(vb->sm.snmp_oid))
errx(1, "oid too long");
+
+ TAILQ_INSERT_TAIL(&res.varbinds, vb, vb_entry);
match++;
t = &table[i];
break;
case IPADDRVAL:
if (word == NULL || strlen(word) == 0)
break;
- if (inet_pton(AF_INET, word, &in4) == -1) {
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ if (inet_pton(AF_INET, word, &vb->u.in4) == -1) {
/* XXX the SNMP_IPADDR type is IPv4-only? */
- if (inet_pton(AF_INET6, word, &in6) == -1)
+ if (inet_pton(AF_INET6, word, &vb->u.in6) == -1)
errx(1, "invalid IP address");
- iov[1].iov_len = sizeof(in6);
- iov[1].iov_base = &in6;
+ vb->sm.snmp_len = sizeof(vb->u.in6);
} else {
- iov[1].iov_len = sizeof(in4);
- iov[1].iov_base = &in4;
+ vb->sm.snmp_len = sizeof(vb->u.in4);
}
- iovcnt = 2;
+ terminal = 1;
break;
case INT32VAL:
if (word == NULL || strlen(word) == 0)
break;
- d = strtonum(word, INT_MIN, INT_MAX, &errs);
- iov[1].iov_len = sizeof(d);
- iov[1].iov_base = &d;
- iovcnt = 2;
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ vb->u.d = strtonum(word, INT_MIN, INT_MAX, &errs);
+ vb->sm.snmp_len = sizeof(vb->u.d);
+ terminal = 1;
break;
case UINT32VAL:
if (word == NULL || strlen(word) == 0)
break;
- u = strtonum(word, 0, UINT_MAX, &errs);
- iov[1].iov_len = sizeof(u);
- iov[1].iov_base = &u;
- iovcnt = 2;
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ vb->u.u = strtonum(word, 0, UINT_MAX, &errs);
+ vb->sm.snmp_len = sizeof(vb->u.u);
+ terminal = 1;
break;
case INT64VAL:
if (word == NULL || strlen(word) == 0)
break;
- l = strtonum(word, INT64_MIN, INT64_MAX, &errs);
- iov[1].iov_len = sizeof(l);
- iov[1].iov_base = &l;
- iovcnt = 2;
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ vb->u.l = strtonum(word, INT64_MIN, INT64_MAX, &errs);
+ vb->sm.snmp_len = sizeof(vb->u.l);
+ terminal = 1;
break;
case STRINGVAL:
if (word == NULL || strlen(word) == 0)
break;
- iov[1].iov_len = strlen(word);
- iov[1].iov_base = word;
- iovcnt = 2;
+ vb = TAILQ_LAST(&res.varbinds, parse_varbinds);
+ if (vb == NULL)
+ errx(1, "inconsistent varbind list");
+ vb->u.str = word;
+ vb->sm.snmp_len = strlen(word);
+ terminal = 1;
break;
case ENDTOKEN:
break;
}
- if (iovcnt)
+ if (terminal)
break;
}
- if (iovcnt) {
- /* Write trap varbind element */
- sm.snmp_len = iov[1].iov_len;
- iov[0].iov_len = sizeof(sm);
- iov[0].iov_base = &sm;
- if (imsg_composev(ibuf, IMSG_SNMP_ELEMENT, 0, 0, -1,
- iov, iovcnt) == -1)
- err(1, "imsg");
-
+ if (terminal) {
t = &table[i];
} else if (match != 1) {
if (word == NULL)
diff --git a/usr.sbin/snmpctl/parser.h b/usr.sbin/snmpctl/parser.h
index 3b41a4b6d99..d50a7ed96ca 100644
--- a/usr.sbin/snmpctl/parser.h
+++ b/usr.sbin/snmpctl/parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.h,v 1.8 2013/10/07 11:40:09 reyk Exp $ */
+/* $OpenBSD: parser.h,v 1.9 2014/04/14 12:56:21 blambert Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -32,11 +32,28 @@ struct parse_val {
};
TAILQ_HEAD(parse_vals, parse_val);
+struct parse_varbind {
+ struct snmp_imsg sm;
+ union {
+ uint32_t u;
+ int32_t d;
+ uint64_t l;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *str;
+ } u;
+
+ TAILQ_ENTRY(parse_varbind) vb_entry;
+};
+TAILQ_HEAD(parse_varbinds, parse_varbind);
+
struct parse_result {
enum actions action;
struct imsgbuf *ibuf;
char *host;
+ char *trapoid;
struct parse_vals oids;
+ struct parse_varbinds varbinds;
char *community;
int version;
};
diff --git a/usr.sbin/snmpctl/snmpctl.c b/usr.sbin/snmpctl/snmpctl.c
index ad24c2f2163..7a277e1fb60 100644
--- a/usr.sbin/snmpctl/snmpctl.c
+++ b/usr.sbin/snmpctl/snmpctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpctl.c,v 1.19 2013/11/14 20:48:52 deraadt Exp $ */
+/* $OpenBSD: snmpctl.c,v 1.20 2014/04/14 12:56:21 blambert Exp $ */
/*
* Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
@@ -24,6 +24,7 @@
#include <sys/queue.h>
#include <sys/un.h>
#include <sys/tree.h>
+#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -64,7 +65,9 @@ struct imsgname imsgunknown = {
-1, "<unknown>", NULL
};
-struct imsgbuf *ibuf;
+void snmpctl_trap(int, struct parse_result *);
+
+struct imsgbuf ibuf;
struct snmpd *env;
struct oid mib_tree[] = MIB_TREE;
@@ -153,20 +156,13 @@ main(int argc, char *argv[])
err(1, "connect: %s", sock);
}
- if (res->ibuf != NULL) {
- ibuf = res->ibuf;
- ibuf->fd = ibuf->w.fd = ctl_sock;
- } else {
- if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
- err(1, "malloc");
- imsg_init(ibuf, ctl_sock);
- }
+ imsg_init(&ibuf, ctl_sock);
done = 0;
/* process user request */
switch (res->action) {
case MONITOR:
- imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
+ imsg_compose(&ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
break;
case NONE:
case SHOW_MIB:
@@ -175,23 +171,23 @@ main(int argc, char *argv[])
case BULKWALK:
break;
case TRAP:
- imsg_compose(ibuf, IMSG_SNMP_END, 0, 0, -1, NULL, 0);
- done = 1;
+ /* explicitly downgrade the socket */
+ imsg_compose(&ibuf, IMSG_SNMP_AGENTX, 0, 0, -1, NULL, 0);
break;
}
- while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
+ while (ibuf.w.queued)
+ if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN)
err(1, "write error");
while (!done) {
- if ((n = imsg_read(ibuf)) == -1)
+ if ((n = imsg_read(&ibuf)) == -1)
errx(1, "imsg_read error");
if (n == 0)
errx(1, "pipe closed");
while (!done) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
+ if ((n = imsg_get(&ibuf, &imsg)) == -1)
errx(1, "imsg_get error");
if (n == 0)
break;
@@ -200,6 +196,11 @@ main(int argc, char *argv[])
done = monitor(&imsg);
break;
case TRAP:
+ if (imsg.hdr.type == IMSG_CTL_OK) {
+ snmpctl_trap(ctl_sock, res);
+ done = 1;
+ } else
+ errx(1, "snmpd refused connection");
break;
case NONE:
case SHOW_MIB:
@@ -212,7 +213,6 @@ main(int argc, char *argv[])
}
}
close(ctl_sock);
- free(ibuf);
return (0);
}
@@ -269,3 +269,118 @@ monitor(struct imsg *imsg)
return (done);
}
+
+void
+snmpctl_trap(int ctl_sock, struct parse_result *res)
+{
+ struct snmp_oid oid, oid1;
+ struct parse_varbind *vb;
+ struct agentx_handle *h;
+ struct agentx_pdu *pdu;
+ void *ptr;
+
+ if ((h = snmp_agentx_fdopen(ctl_sock, "snmpctl", NULL)) == NULL)
+ err(1, "agentx socket");
+
+ if (ber_string2oid(res->trapoid, (struct ber_oid *)&oid) == -1)
+ errx(1, "bad trap oid %s", res->trapoid);
+
+ if ((pdu = snmp_agentx_notify_pdu(&oid)) == NULL)
+ errx(1, "notify start");
+
+ while ((vb = TAILQ_FIRST(&res->varbinds)) != NULL) {
+
+ if (ber_string2oid(vb->sm.snmp_oid,
+ (struct ber_oid *)&oid) == -1)
+ errx(1, "bad oid %s", vb->sm.snmp_oid);
+
+ switch (vb->sm.snmp_type) {
+
+ /* SNMP_GAUGE32 is handled here */
+ case SNMP_INTEGER32:
+ case SNMP_NSAPADDR:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_INTEGER,
+ &vb->u.d, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_OPAQUE:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_OPAQUE,
+ &vb->u.d, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_COUNTER32:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER32,
+ &vb->u.d, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_TIMETICKS:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_TIME_TICKS,
+ &vb->u.d, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_UINTEGER32:
+ case SNMP_UNSIGNED32:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_INTEGER,
+ &vb->u.u, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_COUNTER64:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER64,
+ &vb->u.l, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_IPADDR:
+ if (vb->sm.snmp_len == sizeof(struct in6_addr))
+ ptr = &vb->u.in6;
+ else
+ ptr = &vb->u.in4;
+
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_OPAQUE,
+ ptr, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_OBJECT:
+ if (ber_string2oid(vb->u.str,
+ (struct ber_oid *)&oid1) == -1)
+ errx(1, "invalid OID %s", vb->u.str);
+
+ if (snmp_agentx_varbind(pdu, &oid,
+ AGENTX_OBJECT_IDENTIFIER, &oid1,
+ sizeof(oid1)) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_BITSTRING:
+ case SNMP_OCTETSTRING:
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_OCTET_STRING,
+ vb->u.str, vb->sm.snmp_len) == -1)
+ errx(1, "varbind");
+ break;
+
+ case SNMP_NULL:
+ /* no data beyond the OID itself */
+ if (snmp_agentx_varbind(pdu, &oid, AGENTX_NULL,
+ NULL, 0) == -1)
+ errx(1, "varbind");
+ break;
+ }
+
+ TAILQ_REMOVE(&res->varbinds, vb, vb_entry);
+ free(vb);
+ }
+
+ if ((pdu = snmp_agentx_request(h, pdu)) == NULL)
+ err(1, "request: %i", h->error);
+ if (snmp_agentx_response(h, pdu) == -1)
+ errx(1, "response: %i", h->error);
+ snmp_agentx_pdu_free(pdu);
+ if (snmp_agentx_close(h, AGENTX_CLOSE_SHUTDOWN) == -1)
+ err(1, "close");
+}