The following diff adds support for listening multiple addresses (thus
for dual-stack setups). Multiple "listen on" settings are allowed, the
default is to listen on 0.0.0.0 and :: (currently, only 0.0.0.0).
A single "listen on hostname" line arbitrarily supports up to 16
addresses.
It also tweaks the host*() functions so that addresses are used in the
order where they are resolved*. This affects bind addresses, but also
"trap receiver" addresses. So in "trap receiver hostname", if hostname
resolves to both an IPv4 and an IPv6 address, the address that is picked
up respects the order defined by the "family" keyword in resolv.conf.
This *could* break existing setups.
Feedback and oks welcome,
* httpd, relayd and ldapd might also benefit from such a change
Index: control.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/control.c,v
retrieving revision 1.39
diff -u -p -r1.39 control.c
--- control.c 2 Sep 2016 13:28:36 -0000 1.39
+++ control.c 9 Nov 2016 23:09:28 -0000
@@ -592,7 +592,7 @@ control_dispatch_agentx(int fd, short ev
}
}
dispatch:
- snmpe_dispatchmsg(msg);
+ snmpe_dispatchmsg(msg, fd);
break;
}
Index: parse.y
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.40
diff -u -p -r1.40 parse.y
--- parse.y 9 Nov 2016 20:31:56 -0000 1.40
+++ parse.y 9 Nov 2016 23:31:13 -0000
@@ -198,25 +198,13 @@ yesno : STRING {
;
main : LISTEN ON STRING {
- struct addresslist al;
- struct address *h;
-
- TAILQ_INIT(&al);
- if (host($3, &al, 1, SNMPD_PORT, NULL, NULL, NULL)
- <= 0) {
+ if (host($3, &conf->sc_addresses, 16, SNMPD_PORT, NULL,
+ NULL, NULL) <= 0) {
yyerror("invalid ip address: %s", $3);
free($3);
YYERROR;
}
free($3);
- h = TAILQ_FIRST(&al);
- bcopy(&h->ss, &conf->sc_address.ss, sizeof(*h));
- conf->sc_address.port = h->port;
-
- while ((h = TAILQ_FIRST(&al)) != NULL) {
- TAILQ_REMOVE(&al, h, entry);
- free(h);
- }
}
| READONLY COMMUNITY STRING {
if (strlcpy(conf->sc_rdcommunity, $3,
@@ -989,8 +977,7 @@ parse_config(const char *filename, u_int
conf->sc_flags = flags;
conf->sc_confpath = filename;
- conf->sc_address.ss.ss_family = AF_INET;
- conf->sc_address.port = SNMPD_PORT;
+ TAILQ_INIT(&conf->sc_addresses);
conf->sc_ps.ps_csock.cs_name = SNMPD_SOCKET;
TAILQ_INIT(&conf->sc_ps.ps_rcsocks);
strlcpy(conf->sc_rdcommunity, "public", SNMPD_MAXCOMMUNITYLEN);
@@ -1011,6 +998,22 @@ parse_config(const char *filename, u_int
endservent();
+ if (TAILQ_EMPTY(&conf->sc_addresses)) {
+ struct address *h;
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ fatal("snmpe: %s", __func__);
+ h->ss.ss_family = AF_INET;
+ h->port = SNMPD_PORT;
+ TAILQ_INSERT_TAIL(&conf->sc_addresses, h, entry);
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ fatal("snmpe: %s", __func__);
+ h->ss.ss_family = AF_INET6;
+ h->port = SNMPD_PORT;
+ TAILQ_INSERT_TAIL(&conf->sc_addresses, h, entry);
+ }
+
/* Free macros and check which have not been used. */
for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
next = TAILQ_NEXT(sym, entry);
@@ -1215,7 +1218,7 @@ host_dns(const char *s, struct addressli
h->sa_srcaddr = src;
- TAILQ_INSERT_HEAD(al, h, entry);
+ TAILQ_INSERT_TAIL(al, h, entry);
cnt++;
}
if (cnt == max && res) {
@@ -1262,7 +1265,7 @@ host(const char *s, struct addresslist *
}
h->sa_srcaddr = src;
- TAILQ_INSERT_HEAD(al, h, entry);
+ TAILQ_INSERT_TAIL(al, h, entry);
return (1);
}
Index: snmpd.h
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/snmpd.h,v
retrieving revision 1.72
diff -u -p -r1.72 snmpd.h
--- snmpd.h 9 Nov 2016 20:31:56 -0000 1.72
+++ snmpd.h 9 Nov 2016 23:09:28 -0000
@@ -518,6 +518,18 @@ struct address {
};
TAILQ_HEAD(addresslist, address);
+struct sock {
+ int fd;
+ TAILQ_ENTRY(sock) entry;
+};
+TAILQ_HEAD(socklist, sock);
+
+struct evnode {
+ struct event event;
+ TAILQ_ENTRY(evnode) entry;
+};
+TAILQ_HEAD(eventlist, evnode);
+
enum usmauth {
AUTH_NONE = 0,
AUTH_MD5, /* HMAC-MD5-96, RFC3414 */
@@ -556,9 +568,7 @@ struct snmpd {
#define SNMPD_F_NONAMES 0x02
const char *sc_confpath;
- struct address sc_address;
- int sc_sock;
- struct event sc_ev;
+ struct addresslist sc_addresses;
struct timeval sc_starttime;
u_int32_t sc_engine_boots;
@@ -652,7 +662,7 @@ struct kif_arp *karp_getaddr(struct sock
/* snmpe.c */
void snmpe(struct privsep *, struct privsep_proc *);
void snmpe_shutdown(void);
-void snmpe_dispatchmsg(struct snmp_message *);
+void snmpe_dispatchmsg(struct snmp_message *, int);
/* trap.c */
void trap_init(void);
Index: snmpe.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/snmpe.c,v
retrieving revision 1.45
diff -u -p -r1.45 snmpe.c
--- snmpe.c 9 Nov 2016 20:31:56 -0000 1.45
+++ snmpe.c 9 Nov 2016 23:09:28 -0000
@@ -53,6 +53,8 @@ int snmpe_encode(struct snmp_message *)
void snmp_msgfree(struct snmp_message *);
struct imsgev *iev_parent;
+struct socklist snmpesocks;
+struct eventlist snmpeevents;
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, snmpe_dispatch_parent }
@@ -62,6 +64,8 @@ void
snmpe(struct privsep *ps, struct privsep_proc *p)
{
struct snmpd *env = ps->ps_env;
+ struct address *h;
+ struct sock *so;
#ifdef DEBUG
char buf[BUFSIZ];
struct oid *oid;
@@ -74,9 +78,18 @@ snmpe(struct privsep *ps, struct privsep
}
#endif
- /* bind SNMP UDP socket */
- if ((env->sc_sock = snmpe_bind(&env->sc_address)) == -1)
- fatalx("snmpe: failed to bind SNMP UDP socket");
+ TAILQ_INIT(&snmpesocks);
+
+ /* bind SNMP UDP sockets */
+ TAILQ_FOREACH(h, &env->sc_addresses, entry) {
+ so = calloc(1, sizeof(*so));
+ if (so == NULL)
+ fatal("snmpe: %s", __func__);
+ so->fd = snmpe_bind(h);
+ if (so->fd == -1)
+ fatal("snmpe: failed to bind SNMP UDP socket");
+ TAILQ_INSERT_TAIL(&snmpesocks, so, entry);
+ }
proc_run(ps, p, procs, nitems(procs), snmpe_init, NULL);
}
@@ -86,16 +99,26 @@ void
snmpe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
struct snmpd *env = ps->ps_env;
+ struct sock *so;
+ struct evnode *ev;
kr_init();
trap_init();
timer_init();
usm_generate_keys();
+ TAILQ_INIT(&snmpeevents);
+
/* listen for incoming SNMP UDP messages */
- event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST,
- snmpe_recvmsg, env);
- event_add(&env->sc_ev, NULL);
+ TAILQ_FOREACH(so, &snmpesocks, entry) {
+ ev = calloc(1, sizeof(*ev));
+ if (ev == NULL)
+ fatal("%s", __func__);
+ event_set(&ev->event, so->fd, EV_READ|EV_PERSIST,
+ snmpe_recvmsg, env);
+ event_add(&ev->event, NULL);
+ TAILQ_INSERT_TAIL(&snmpeevents, ev, entry);
+ }
}
void
@@ -519,18 +542,18 @@ snmpe_recvmsg(int fd, short sig, void *a
}
}
- snmpe_dispatchmsg(msg);
+ snmpe_dispatchmsg(msg, fd);
}
void
-snmpe_dispatchmsg(struct snmp_message *msg)
+snmpe_dispatchmsg(struct snmp_message *msg, int sock)
{
if (snmpe_parsevarbinds(msg) == 1)
return;
/* not dispatched to subagent; respond directly */
msg->sm_context = SNMP_C_GETRESP;
- snmpe_response(snmpd_env->sc_sock, msg);
+ snmpe_response(sock, msg);
}
void
Index: traphandler.c
===================================================================
RCS file: /d/cvs/src/usr.sbin/snmpd/traphandler.c,v
retrieving revision 1.6
diff -u -p -r1.6 traphandler.c
--- traphandler.c 28 Oct 2016 09:07:08 -0000 1.6
+++ traphandler.c 9 Nov 2016 23:11:55 -0000
@@ -43,9 +43,9 @@
#include "snmpd.h"
#include "mib.h"
-int trapsock;
-struct event trapev;
-char trap_path[PATH_MAX];
+struct socklist trapsocks;
+struct eventlist trapevents;
+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 *);
@@ -76,10 +76,20 @@ void
traphandler(struct privsep *ps, struct privsep_proc *p)
{
struct snmpd *env = ps->ps_env;
+ struct address *h;
+ struct sock *so;
- if (env->sc_traphandler &&
- (trapsock = traphandler_bind(&env->sc_address)) == -1)
- fatal("could not create trap listener socket");
+ TAILQ_INIT(&trapsocks);
+
+ if (env->sc_traphandler) {
+ TAILQ_FOREACH(h, &env->sc_addresses, entry) {
+ so = calloc(1, sizeof(*so));
+ so->fd = traphandler_bind(h);
+ if (so->fd == -1)
+ fatal("could not create trap listener socket");
+ TAILQ_INSERT_TAIL(&trapsocks, so, entry);
+ }
+ }
proc_run(ps, p, procs, nitems(procs), traphandler_init, NULL);
}
@@ -88,20 +98,31 @@ void
traphandler_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
struct snmpd *env = ps->ps_env;
+ struct sock *so;
+ struct evnode *ev;
+
+ TAILQ_INIT(&trapevents);
if (!env->sc_traphandler)
return;
/* listen for SNMP trap messages */
- event_set(&trapev, trapsock, EV_READ|EV_PERSIST, traphandler_recvmsg,
- ps);
- event_add(&trapev, NULL);
+ TAILQ_FOREACH(so, &trapsocks, entry) {
+ ev = calloc(1, sizeof (*ev));
+ if (ev == NULL)
+ fatal("%s", __func__);
+ event_set(&ev->event, so->fd, EV_READ|EV_PERSIST,
+ traphandler_recvmsg, ps);
+ event_add(&ev->event, NULL);
+ TAILQ_INSERT_TAIL(&trapevents, ev, entry);
+ }
}
int
traphandler_bind(struct address *addr)
{
int s;
+ char buf[512];
if ((s = snmpd_socket_af(&addr->ss, htons(SNMPD_TRAPPORT))) == -1)
return (-1);
@@ -112,6 +133,11 @@ traphandler_bind(struct address *addr)
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("%s: binding to address %s:%d", __func__, buf, SNMPD_TRAPPORT);
+
return (s);
bad:
close (s);
@@ -121,8 +147,14 @@ traphandler_bind(struct address *addr)
void
traphandler_shutdown(void)
{
- event_del(&trapev);
- close(trapsock);
+ struct evnode *ev;
+ struct sock *so;
+
+ TAILQ_FOREACH(ev, &trapevents, entry)
+ event_del(&ev->event);
+
+ TAILQ_FOREACH(so, &trapsocks, entry)
+ close(so->fd);
}
int
--
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE