-/* $OpenBSD: parse.y,v 1.62 2020/10/30 07:43:48 martijn Exp $ */
+/* $OpenBSD: parse.y,v 1.63 2021/01/22 06:33:26 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
struct snmpd *conf = NULL;
static int errors = 0;
static struct usmuser *user = NULL;
-static char *snmpd_port = SNMPD_PORT;
int host(const char *, const char *, int,
struct sockaddr_storage *, int);
-int listen_add(struct sockaddr_storage *, int);
+int listen_add(struct sockaddr_storage *, int, int);
typedef struct {
union {
%}
%token INCLUDE
-%token LISTEN ON
+%token LISTEN ON READ WRITE NOTIFY
%token SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES RTFILTER
%token READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER
%token SECLEVEL NONE AUTH ENC USER AUTHKEY ENCKEY ERROR DISABLED
%token <v.number> NUMBER
%type <v.string> hostcmn
%type <v.string> srcaddr port
-%type <v.number> optwrite yesno seclevel
+%type <v.number> optwrite yesno seclevel listenopt listenopts
%type <v.data> objtype cmd
%type <v.oid> oid hostoid trapoid
%type <v.auth> auth
| TCP listen_tcp
| listen_udp
-listen_udp : STRING port {
+listenopts : /* empty */ { $$ = 0; }
+ | listenopts listenopt { $$ |= $2; }
+ ;
+
+listenopt : READ { $$ = ADDRESS_FLAG_READ; }
+ | WRITE { $$ = ADDRESS_FLAG_WRITE; }
+ | NOTIFY { $$ = ADDRESS_FLAG_NOTIFY; }
+ ;
+
+listen_udp : STRING port listenopts {
struct sockaddr_storage ss[16];
int nhosts, i;
+ char *port = $2;
- nhosts = host($1, $2, SOCK_DGRAM, ss, nitems(ss));
+ if (port == NULL) {
+ if ($3 == ADDRESS_FLAG_NOTIFY)
+ port = SNMPTRAP_PORT;
+ else
+ port = SNMP_PORT;
+ }
+
+ nhosts = host($1, port, SOCK_DGRAM, ss, nitems(ss));
if (nhosts < 1) {
yyerror("invalid address: %s", $1);
free($1);
- if ($2 != snmpd_port)
- free($2);
+ free($2);
YYERROR;
}
if (nhosts > (int)nitems(ss))
log_warn("%s:%s resolves to more than %zu hosts",
- $1, $2, nitems(ss));
+ $1, port, nitems(ss));
free($1);
- if ($2 != snmpd_port)
- free($2);
+ free($2);
for (i = 0; i < nhosts; i++) {
- if (listen_add(&(ss[i]), SOCK_DGRAM) == -1) {
+ if (listen_add(&(ss[i]), SOCK_DGRAM, $3) == -1) {
yyerror("calloc");
YYERROR;
}
}
}
-listen_tcp : STRING port {
+listen_tcp : STRING port listenopts {
struct sockaddr_storage ss[16];
int nhosts, i;
+ char *port = $2;
- nhosts = host($1, $2, SOCK_STREAM, ss, nitems(ss));
+ if (port == NULL) {
+ if ($3 == ADDRESS_FLAG_NOTIFY)
+ port = SNMPTRAP_PORT;
+ else
+ port = SNMP_PORT;
+ }
+ nhosts = host($1, port, SOCK_STREAM, ss, nitems(ss));
if (nhosts < 1) {
yyerror("invalid address: %s", $1);
free($1);
- if ($2 != snmpd_port)
- free($2);
+ free($2);
YYERROR;
}
if (nhosts > (int)nitems(ss))
log_warn("%s:%s resolves to more than %zu hosts",
- $1, $2, nitems(ss));
+ $1, port, nitems(ss));
free($1);
- if ($2 != snmpd_port)
- free($2);
+ free($2);
for (i = 0; i < nhosts; i++) {
- if (listen_add(&(ss[i]), SOCK_STREAM) == -1) {
+ if (listen_add(&(ss[i]), SOCK_STREAM, $3) == -1) {
yyerror("calloc");
YYERROR;
}
}
port : /* empty */ {
- $$ = snmpd_port;
+ $$ = NULL;
}
| PORT STRING {
$$ = $2;
YYERROR;
}
- if (host($1, SNMPD_TRAPPORT, SOCK_DGRAM, &ss, 1) <= 0) {
+ if (host($1, SNMPTRAP_PORT, SOCK_DGRAM, &ss, 1) <= 0) {
yyerror("invalid host: %s", $1);
free($1);
free($2);
{ "location", LOCATION },
{ "name", NAME },
{ "none", NONE },
+ { "notify", NOTIFY },
{ "oid", OBJECTID },
{ "on", ON },
{ "port", PORT },
+ { "read", READ },
{ "read-only", READONLY },
{ "read-write", READWRITE },
{ "receiver", RECEIVER },
{ "tcp", TCP },
{ "trap", TRAP },
{ "udp", UDP },
- { "user", USER }
+ { "user", USER },
+ { "write", WRITE }
};
const struct keywords *p;
/* Setup default listen addresses */
if (TAILQ_EMPTY(&conf->sc_addresses)) {
- if (host("0.0.0.0", SNMPD_PORT, SOCK_DGRAM, &ss, 1) != 1)
+ if (host("0.0.0.0", SNMP_PORT, SOCK_DGRAM, &ss, 1) != 1)
fatal("Unexpected resolving of 0.0.0.0");
- if (listen_add(&ss, SOCK_DGRAM) == -1)
+ if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
fatal("calloc");
- if (host("::", SNMPD_PORT, SOCK_DGRAM, &ss, 1) != 1)
+ if (host("::", SNMP_PORT, SOCK_DGRAM, &ss, 1) != 1)
fatal("Unexpected resolving of ::");
- if (listen_add(&ss, SOCK_DGRAM) == -1)
+ if (listen_add(&ss, SOCK_DGRAM, 0) == -1)
fatal("calloc");
}
- if (conf->sc_traphandler) {
- found = 0;
- TAILQ_FOREACH(h, &conf->sc_addresses, entry) {
- if (h->type == SOCK_DGRAM)
- found = 1;
- }
- if (!found) {
- log_warnx("trap handler needs at least one "
- "udp listen address");
- free(conf);
- return (NULL);
- }
+ found = 0;
+ TAILQ_FOREACH(h, &conf->sc_addresses, entry) {
+ if (h->flags & ADDRESS_FLAG_NOTIFY)
+ found = 1;
+ }
+ if (conf->sc_traphandler && !found) {
+ log_warnx("trap handler needs at least one notify listener");
+ free(conf);
+ return (NULL);
+ }
+ if (!conf->sc_traphandler && found) {
+ log_warnx("notify listener needs at least one trap handler");
+ free(conf);
+ return (NULL);
}
/* Free macros and check which have not been used. */
}
int
-listen_add(struct sockaddr_storage *ss, int type)
+listen_add(struct sockaddr_storage *ss, int type, int flags)
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
h->port = ntohs(sin6->sin6_port);
}
h->type = type;
+ if ((h->flags = flags) == 0) {
+ if (h->port == 162)
+ h->flags = ADDRESS_FLAG_NOTIFY;
+ else
+ h->flags = ADDRESS_FLAG_READ | ADDRESS_FLAG_WRITE;
+ }
TAILQ_INSERT_TAIL(&(conf->sc_addresses), h, entry);
return 0;
-/* $OpenBSD: snmpd.c,v 1.42 2020/09/06 15:51:28 martijn Exp $ */
+/* $OpenBSD: snmpd.c,v 1.43 2021/01/22 06:33:26 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
static struct privsep_proc procs[] = {
{ "snmpe", PROC_SNMPE, snmpd_dispatch_snmpe, snmpe, snmpe_shutdown },
- { "traphandler", PROC_TRAP, snmpd_dispatch_traphandler, traphandler,
- traphandler_shutdown }
};
void
snmpd_dispatch_snmpe(int fd, struct privsep_proc *p, struct imsg *imsg)
{
switch (imsg->hdr.type) {
+ case IMSG_TRAP_EXEC:
+ return (traphandler_priv_recvmsg(p, imsg));
case IMSG_CTL_RELOAD:
/* XXX notyet */
default:
-.\" $OpenBSD: snmpd.conf.5,v 1.45 2020/10/24 14:52:11 jmc Exp $
+.\" $OpenBSD: snmpd.conf.5,v 1.46 2021/01/22 06:33:26 martijn Exp $
.\"
.\" Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 24 2020 $
+.Dd $Mdocdate: January 22 2021 $
.Dt SNMPD.CONF 5
.Os
.Sh NAME
reduced during bulk updates.
The default is
.Ic no .
-.It Ic listen on Oo Ic tcp | udp Oc Ar address Op Ic port Ar port
+.It Ic listen on Oo Ic tcp | udp Oc Ar address Oo Ic port Ar port Oc Op Ic read | Ic write | Ic notify
Specify the local address
.Xr snmpd 8
should listen on for incoming SNMP messages.
+The
+.Ic read
+flag specifies if the listen statement accepts get, getnext and bulkget
+requests.
+The
+.Ic write
+flag specifies if the listen statement accepts set requests
+and
+.Ic notify
+flags specifes if the listen statements accepts trapv1 and trapv2 requests.
Multiple
.Ic listen on
-statements are supported, the default is UDP.
+statements are supported.
+The default protocol is
+.Ic udp.
+The default
+.Ar port
+is 161, unless the only listen flags contains
+.Ic notify
+which sets it to 162.
+If no flags are specified it defaults to
+.Dq Ic read Ic write ,
+or
+.Ic notify
+when
+.Ar port
+is 162.
.It Ic read-only community Ar string
Specify the name of the read-only community.
The default value is
-/* $OpenBSD: snmpd.h,v 1.90 2020/09/06 15:51:28 martijn Exp $ */
+/* $OpenBSD: snmpd.h,v 1.91 2021/01/22 06:33:26 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
#define CONF_FILE "/etc/snmpd.conf"
#define SNMPD_SOCKET "/var/run/snmpd.sock"
#define SNMPD_USER "_snmpd"
-#define SNMPD_PORT "161"
-#define SNMPD_TRAPPORT "162"
+#define SNMP_PORT "161"
+#define SNMPTRAP_PORT "162"
#define SNMPD_MAXSTRLEN 484
#define SNMPD_MAXCOMMUNITYLEN SNMPD_MAXSTRLEN
IMSG_CTL_VERBOSE,
IMSG_CTL_RELOAD,
IMSG_CTL_PROCFD,
- IMSG_ALERT
+ IMSG_TRAP_EXEC
};
struct imsgev {
enum privsep_procid {
PROC_PARENT, /* Parent process and application interface */
PROC_SNMPE, /* SNMP engine */
- PROC_TRAP, /* SNMP trap receiver */
PROC_MAX
};
struct sockaddr_storage sm_ss;
socklen_t sm_slen;
int sm_sock_tcp;
+ int sm_aflags;
+ int sm_type;
struct event sm_sockev;
char sm_host[HOST_NAME_MAX+1];
+ in_port_t sm_port;
struct sockaddr_storage sm_local_ss;
socklen_t sm_local_slen;
struct sockaddr_storage ss;
in_port_t port;
int type;
+ int flags;
int fd;
struct event ev;
struct event evt;
};
TAILQ_HEAD(addresslist, address);
+#define ADDRESS_FLAG_READ 0x1
+#define ADDRESS_FLAG_WRITE 0x2
+#define ADDRESS_FLAG_NOTIFY 0x4
+
struct trap_address {
struct sockaddr_storage ss;
struct sockaddr_storage ss_local;
int proc_flush_imsg(struct privsep *, enum privsep_procid, int);
/* traphandler.c */
-void traphandler(struct privsep *, struct privsep_proc *);
-void traphandler_shutdown(void);
-int snmpd_dispatch_traphandler(int, struct privsep_proc *, struct imsg *);
+int traphandler_parse(struct snmp_message *);
+int traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *);
void trapcmd_free(struct trapcmd *);
int trapcmd_add(struct trapcmd *);
struct trapcmd *
-/* $OpenBSD: snmpe.c,v 1.67 2020/09/06 17:29:35 martijn Exp $ */
+/* $OpenBSD: snmpe.c,v 1.68 2021/01/22 06:33:27 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
evtimer_set(&h->evt, snmpe_acceptcb, h);
} else {
event_set(&h->ev, h->fd, EV_READ|EV_PERSIST,
- snmpe_recvmsg, env);
+ snmpe_recvmsg, h);
}
event_add(&h->ev, NULL);
}
if (class != BER_CLASS_CONTEXT)
goto parsefail;
+ msg->sm_type = type;
switch (type) {
case SNMP_C_GETBULKREQ:
if (msg->sm_version == SNMP_V1) {
case SNMP_C_GETNEXTREQ:
if (type == SNMP_C_GETNEXTREQ)
stats->snmp_ingetnexts++;
+ if (!(msg->sm_aflags & ADDRESS_FLAG_READ)) {
+ msg->sm_errstr = "read requests disabled";
+ goto fail;
+ }
if (msg->sm_version != SNMP_V3 &&
strcmp(env->sc_rdcommunity, msg->sm_community) != 0 &&
(env->sc_readonly ||
case SNMP_C_SETREQ:
stats->snmp_insetrequests++;
+ if (!(msg->sm_aflags & ADDRESS_FLAG_WRITE)) {
+ msg->sm_errstr = "write requests disabled";
+ goto fail;
+ }
if (msg->sm_version != SNMP_V3 &&
(env->sc_readonly ||
strcmp(env->sc_rwcommunity, msg->sm_community) != 0)) {
goto parsefail;
case SNMP_C_TRAP:
+ if (msg->sm_version != SNMP_V1) {
+ msg->sm_errstr = "trapv1 request on !SNMPv1 message";
+ goto parsefail;
+ }
case SNMP_C_TRAPV2:
- if (msg->sm_version != SNMP_V3 &&
- strcmp(env->sc_trcommunity, msg->sm_community) != 0) {
+ if (type == SNMP_C_TRAPV2 &&
+ !(msg->sm_version == SNMP_V2 ||
+ msg->sm_version != SNMP_V3)) {
+ msg->sm_errstr = "trapv2 request on !SNMPv2C or "
+ "!SNMPv3 message";
+ goto parsefail;
+ }
+ if (!(msg->sm_aflags & ADDRESS_FLAG_NOTIFY)) {
+ msg->sm_errstr = "notify requests disabled";
+ goto fail;
+ }
+ if (msg->sm_version == SNMP_V3) {
+ msg->sm_errstr = "SNMPv3 doesn't support traps yet";
+ goto fail;
+ }
+ if (strcmp(env->sc_trcommunity, msg->sm_community) != 0) {
stats->snmp_inbadcommunitynames++;
msg->sm_errstr = "wrong trap community";
goto fail;
}
stats->snmp_intraps++;
- msg->sm_errstr = "received trap";
- goto fail;
+ /*
+ * This should probably go into parsevarbinds, but that's for a
+ * next refactor
+ */
+ if (traphandler_parse(msg) == -1)
+ goto fail;
+ /* Shortcircuit */
+ return 0;
default:
msg->sm_errstr = "invalid context";
print_host(ss, msg->sm_host, sizeof(msg->sm_host));
if (msg->sm_version == SNMP_V3)
- log_debug("%s: %s: SNMPv3 context %d, flags %#x, "
+ log_debug("%s: %s:%hd: SNMPv3 context %d, flags %#x, "
"secmodel %lld, user '%s', ctx-engine %s, ctx-name '%s', "
- "request %lld", __func__, msg->sm_host, msg->sm_context,
- msg->sm_flags, msg->sm_secmodel, msg->sm_username,
- tohexstr(msg->sm_ctxengineid, msg->sm_ctxengineid_len),
- msg->sm_ctxname, msg->sm_request);
+ "request %lld", __func__, msg->sm_host, msg->sm_port,
+ msg->sm_context, msg->sm_flags, msg->sm_secmodel,
+ msg->sm_username, tohexstr(msg->sm_ctxengineid,
+ msg->sm_ctxengineid_len), msg->sm_ctxname, msg->sm_request);
else
- log_debug("%s: %s: SNMPv%d '%s' context %d request %lld",
- __func__, msg->sm_host, msg->sm_version + 1,
+ log_debug("%s: %s:%hd: SNMPv%d '%s' context %d request %lld",
+ __func__, msg->sm_host, msg->sm_port, msg->sm_version + 1,
msg->sm_community, msg->sm_context, msg->sm_request);
return (0);
stats->snmp_inasnparseerrs++;
fail:
print_host(ss, msg->sm_host, sizeof(msg->sm_host));
- log_debug("%s: %s: %s", __func__, msg->sm_host, msg->sm_errstr);
+ log_debug("%s: %s:%hd: %s", __func__, msg->sm_host, msg->sm_port,
+ msg->sm_errstr);
return (-1);
}
if (o.bo_n < BER_MIN_OID_LEN || o.bo_n > BER_MAX_OID_LEN)
goto varfail;
- log_debug("%s: %s: oid %s", __func__, msg->sm_host,
- smi_oid2string(&o, buf, sizeof(buf), 0));
+ log_debug("%s: %s:%hd: oid %s", __func__, msg->sm_host,
+ msg->sm_port, smi_oid2string(&o, buf, sizeof(buf), 0));
/*
* XXX intotalreqvars should only be incremented after all are
return 0;
varfail:
- log_debug("%s: %s: %s, error index %d", __func__,
- msg->sm_host, msg->sm_errstr, i);
+ log_debug("%s: %s:%hd: %s, error index %d", __func__,
+ msg->sm_host, msg->sm_port, msg->sm_errstr, i);
if (msg->sm_error == 0)
msg->sm_error = SNMP_ERROR_GENERR;
msg->sm_errorindex = i;
if ((msg = calloc(1, sizeof(*msg))) == NULL)
goto fail;
+ memcpy(&(msg->sm_ss), &ss, len);
+ msg->sm_slen = len;
+ msg->sm_aflags = h->flags;
+ msg->sm_port = h->port;
snmpe_prepare_read(msg, afd);
return;
fail:
if ((nmsg = calloc(1, sizeof(*nmsg))) == NULL)
goto fail;
+ memcpy(&(nmsg->sm_ss), &(msg->sm_ss), msg->sm_slen);
+ nmsg->sm_slen = msg->sm_slen;
+ nmsg->sm_aflags = msg->sm_aflags;
+ nmsg->sm_port = msg->sm_port;
/*
* Reuse the connection.
void
snmpe_recvmsg(int fd, short sig, void *arg)
{
- struct snmpd *env = arg;
- struct snmp_stats *stats = &env->sc_stats;
+ struct address *h = arg;
+ struct snmp_stats *stats = &snmpd_env->sc_stats;
ssize_t len;
struct snmp_message *msg;
if ((msg = calloc(1, sizeof(*msg))) == NULL)
return;
+ msg->sm_aflags = h->flags;
msg->sm_sock = fd;
msg->sm_slen = sizeof(msg->sm_ss);
+ msg->sm_port = h->port;
if ((len = recvfromto(fd, msg->sm_data, sizeof(msg->sm_data), 0,
(struct sockaddr *)&msg->sm_ss, &msg->sm_slen,
(struct sockaddr *)&msg->sm_local_ss, &msg->sm_local_slen)) < 1) {
void
snmpe_dispatchmsg(struct snmp_message *msg)
{
+ if (msg->sm_type == SNMP_C_TRAP ||
+ msg->sm_type == SNMP_C_TRAPV2) {
+ snmp_msgfree(msg);
+ return;
+ }
/* dispatched to subagent */
/* XXX Do proper error handling */
(void) snmpe_parsevarbinds(msg);
-/* $OpenBSD: traphandler.c,v 1.19 2021/01/05 18:12:15 martijn Exp $ */
+/* $OpenBSD: traphandler.c,v 1.20 2021/01/22 06:33:27 martijn Exp $ */
/*
* Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
#include "snmpd.h"
#include "mib.h"
-char trap_path[PATH_MAX];
-
-void traphandler_init(struct privsep *, struct privsep_proc *, void *arg);
-int traphandler_dispatch_parent(int, struct privsep_proc *, struct imsg *);
-int traphandler_bind(struct address *);
-void traphandler_recvmsg(int, short, void *);
int traphandler_priv_recvmsg(struct privsep_proc *, struct imsg *);
int traphandler_fork_handler(struct privsep_proc *, struct imsg *);
-int traphandler_parse(struct ber_element *, char *, struct sockaddr *);
struct ber_element *
- traphandler_v1translate(struct ber_element *, char *, int);
+ traphandler_v1translate(struct snmp_message *, int);
int trapcmd_cmp(struct trapcmd *, struct trapcmd *);
void trapcmd_exec(struct trapcmd *, struct sockaddr *,
struct ber_element *);
struct trapcmd_tree trapcmd_tree = RB_INITIALIZER(&trapcmd_tree);
-static struct privsep_proc procs[] = {
- { "parent", PROC_PARENT, traphandler_dispatch_parent }
-};
-
-void
-traphandler(struct privsep *ps, struct privsep_proc *p)
-{
- struct snmpd *env = ps->ps_env;
- struct address *h;
-
- if (env->sc_traphandler) {
- TAILQ_FOREACH(h, &env->sc_addresses, entry) {
- if (h->type != SOCK_DGRAM)
- continue;
- if ((h->fd = traphandler_bind(h)) == -1)
- fatal("could not create trap listener socket");
- }
- }
-
- proc_run(ps, p, procs, nitems(procs), traphandler_init, NULL);
-}
-
-void
-traphandler_init(struct privsep *ps, struct privsep_proc *p, void *arg)
-{
- struct snmpd *env = ps->ps_env;
- struct address *h;
-
- if (pledge("stdio id proc recvfd exec", NULL) == -1)
- fatal("pledge");
-
- if (!env->sc_traphandler)
- return;
-
- /* listen for SNMP trap messages */
- TAILQ_FOREACH(h, &env->sc_addresses, entry) {
- event_set(&h->ev, h->fd, EV_READ|EV_PERSIST,
- traphandler_recvmsg, NULL);
- event_add(&h->ev, NULL);
- }
-}
-
-int
-traphandler_bind(struct address *addr)
-{
- int s;
- char buf[512];
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
-
- if (addr->ss.ss_family == AF_INET) {
- sin = (struct sockaddr_in *)&(addr->ss);
- sin->sin_port = htons(162);
- } else {
- sin6 = (struct sockaddr_in6 *)&(addr->ss);
- sin6->sin6_port = htons(162);
- }
- if ((s = snmpd_socket_af(&addr->ss, SOCK_DGRAM)) == -1)
- return (-1);
-
- if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
- goto bad;
-
- if (bind(s, (struct sockaddr *)&addr->ss, addr->ss.ss_len) == -1)
- goto bad;
-
- if (print_host(&addr->ss, buf, sizeof(buf)) == NULL)
- goto bad;
-
- log_info("traphandler: listening on %s:%s", buf, SNMPD_TRAPPORT);
-
- return (s);
- bad:
- close (s);
- return (-1);
-}
-
-void
-traphandler_shutdown(void)
-{
- struct address *h;
-
- TAILQ_FOREACH(h, &snmpd_env->sc_addresses, entry) {
- event_del(&h->ev);
- close(h->fd);
- }
-}
-
-int
-traphandler_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
-{
- switch (imsg->hdr.type) {
- default:
- break;
- }
-
- return (-1);
-}
-
-int
-snmpd_dispatch_traphandler(int fd, struct privsep_proc *p, struct imsg *imsg)
-{
- switch (imsg->hdr.type) {
- case IMSG_ALERT:
- return (traphandler_priv_recvmsg(p, imsg));
- default:
- break;
- }
-
- return (-1);
-}
-
-void
-traphandler_recvmsg(int fd, short events, void *arg)
-{
- struct ber ber = {0};
- struct ber_element *msg = NULL, *pdu;
- char buf[8196];
- struct sockaddr_storage ss;
- socklen_t slen;
- ssize_t n;
- int vers;
- char *community;
-
- slen = sizeof(ss);
- if ((n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&ss,
- &slen)) == -1)
- return;
-
- ober_set_application(&ber, smi_application);
- ober_set_readbuf(&ber, buf, n);
-
- if ((msg = ober_read_elements(&ber, NULL)) == NULL)
- goto parsefail;
-
- if (ober_scanf_elements(msg, "{dse", &vers, &community, &pdu) == -1)
- goto parsefail;
-
- switch (vers) {
- case SNMP_V1:
- if (pdu->be_type != SNMP_C_TRAP)
- goto parsefail;
- break;
- case SNMP_V2:
- if (pdu->be_type != SNMP_C_TRAPV2)
- goto parsefail;
- break;
- default:
- goto parsefail;
- }
-
- (void)traphandler_parse(pdu, community, (struct sockaddr *)&ss);
-
-parsefail:
- ober_free(&ber);
- if (msg != NULL)
- ober_free_elements(msg);
-}
-
/*
* Validate received message
*/
int
-traphandler_parse(struct ber_element *pdu, char *community, struct sockaddr *sa)
+traphandler_parse(struct snmp_message *msg)
{
struct privsep *ps = &snmpd_env->sc_ps;
+ struct snmp_stats *stats = &snmpd_env->sc_stats;
struct ber ber = {0};
struct ber_element *vblist = NULL, *elm, *elm2;
struct ber_oid o1, o2, snmpTrapOIDOID;
ssize_t buflen;
int ret = -1;
- switch (pdu->be_type) {
+ switch (msg->sm_pdu->be_type) {
case SNMP_C_TRAP:
- vblist = traphandler_v1translate(pdu, community, 0);
- if (vblist == NULL)
+ if ((vblist = traphandler_v1translate(msg, 0)) == NULL)
goto done;
break;
case SNMP_C_TRAPV2:
- if (ober_scanf_elements(pdu, "{SSe}", &elm) == -1)
+ if (ober_scanf_elements(msg->sm_pdu, "{SSe}", &elm) == -1) {
+ stats->snmp_inasnparseerrs++;
goto done;
- if (elm->be_type != BER_TYPE_INTEGER)
+ }
+ if (elm->be_type != BER_TYPE_INTEGER) {
+ stats->snmp_inasnparseerrs++;
goto done;
+ }
vblist = ober_unlink_elements(elm);
break;
default:
- log_warnx("unsupported SNMP trap version '%d'", pdu->be_type);
- goto done;
+ fatalx("%s called without proper context", __func__);
}
(void)ober_string2oid("1.3.6.1.2.1.1.3.0", &sysUpTimeOID);
&snmpTrapOID) == -1 ||
ober_oid_cmp(&o1, &sysUpTimeOID) != 0 ||
ober_oid_cmp(&o2, &snmpTrapOIDOID) != 0) {
+ stats->snmp_inasnparseerrs++;
goto done;
}
(void)ober_scanf_elements(vblist, "{Se", &elm);
for (elm = elm->be_next; elm != NULL; elm = elm->be_next) {
if (ober_scanf_elements(elm, "{oe}", &o1, &elm2) == -1 ||
- elm2->be_next != NULL)
+ elm2->be_next != NULL) {
+ stats->snmp_inasnparseerrs++;
goto done;
+ }
}
ober_set_application(&ber, smi_application);
if ((buflen = ober_write_elements(&ber, vblist)) == -1 ||
- ober_get_writebuf(&ber, &buf) == -1)
+ ober_get_writebuf(&ber, &buf) == -1) {
+ msg->sm_errstr = "failed to handle trap";
goto done;
+ }
- iov[0].iov_base = sa;
- iov[0].iov_len = sa->sa_len;
+ iov[0].iov_base = &(msg->sm_ss);
+ iov[0].iov_len = msg->sm_slen;
iov[1].iov_base = buf;
iov[1].iov_len = buflen;
/* Forward it to the parent process */
- if (proc_composev(ps, PROC_PARENT, IMSG_ALERT, iov, 2) == -1)
+ if (proc_composev(ps, PROC_PARENT, IMSG_TRAP_EXEC, iov, 2) == -1) {
+ msg->sm_errstr = "failed to handle trap";
goto done;
+ }
ret = 0;
done:
}
struct ber_element *
-traphandler_v1translate(struct ber_element *pdu, char *community, int proxy)
+traphandler_v1translate(struct snmp_message *msg, int proxy)
{
+ struct snmp_stats *stats = &snmpd_env->sc_stats;
struct ber_oid trapoid, enterprise, oid, snmpTrapAddressOid;
struct ber_oid snmpTrapCommunityOid, snmpTrapEnterpriseOid;
struct ber_element *elm, *last, *vblist, *vb0 = NULL;
int generic_trap, specific_trap, time_stamp;
int hasaddress = 0, hascommunity = 0, hasenterprise = 0;
- if (ober_scanf_elements(pdu, "{oxddde", &enterprise, &agent_addr,
- &agent_addrlen, &generic_trap, &specific_trap, &time_stamp,
- &vblist) == -1 ||
+ if (ober_scanf_elements(msg->sm_pdu, "{oxddde", &enterprise,
+ &agent_addr, &agent_addrlen, &generic_trap, &specific_trap,
+ &time_stamp, &vblist) == -1 ||
agent_addrlen != 4 ||
vblist->be_type != BER_TYPE_SEQUENCE) {
- errno = EINVAL;
+ stats->snmp_inasnparseerrs++;
return NULL;
}
switch (generic_trap) {
break;
case 6:
trapoid = enterprise;
+ /* Officially this should be 128, but BER_MAX_OID_LEN is 64 */
if (trapoid.bo_n + 2 > BER_MAX_OID_LEN) {
- errno = EINVAL;
+ stats->snmp_inasnparseerrs++;
return NULL;
}
trapoid.bo_id[trapoid.bo_n++] = 0;
trapoid.bo_id[trapoid.bo_n++] = specific_trap;
break;
default:
- errno = EINVAL;
+ stats->snmp_inasnparseerrs++;
return NULL;
}
vb0 = ober_unlink_elements(vblist);
if ((vblist = ober_add_sequence(NULL)) == NULL) {
+ msg->sm_errstr = strerror(errno);
if (vb0 != NULL)
ober_free_elements(vb0);
return NULL;
}
if (ober_printf_elements(vblist, "{od}{oO}e", "1.3.6.1.2.1.1.3.0",
time_stamp, "1.3.6.1.6.3.1.1.4.1.0", &trapoid, vb0) == NULL) {
+ msg->sm_errstr = strerror(errno);
if (vb0 != 0)
ober_free_elements(vb0);
ober_free_elements(vblist);
&snmpTrapEnterpriseOid);
for (elm = vblist->be_sub; elm != NULL; elm = elm->be_next) {
if (ober_get_oid(elm->be_sub, &oid) == -1) {
+ msg->sm_errstr = "failed to read oid";
ober_free_elements(vblist);
return NULL;
}
if (ober_printf_elements(last, "{Oxt}{Os}{OO}",
&snmpTrapAddressOid, agent_addr, 4,
BER_CLASS_APPLICATION, SNMP_T_IPADDR,
- &snmpTrapCommunityOid, community,
+ &snmpTrapCommunityOid, msg->sm_community,
&snmpTrapEnterpriseOid, &enterprise) == NULL) {
+ msg->sm_errstr = strerror(errno);
ober_free_elements(vblist);
return NULL;
}