On Sun, 2021-08-08 at 14:44 +0100, Stuart Henderson wrote:
> > This is probably is a bad example.
> > Reading it like this: you're correct that we listen on all interfaces
> > by default, but that's not listed in snmpd.conf(5). So that should
> > probably be fixed (including mentioning that setting one "listen on"
> > disables the all interfaces default).
>
> Let's handle that separately. (it would be convenient to support
> "any" to mean any v4+v6 as well).
>
> > Second, your examples enable snmpv2c on all interfaces, while you
> > enable an implicit snmpv3 on 127.0.0.1. This should probably be the
>
> I wasn't intending that they should all be uncommented at once,
> just showing some common options. And actually it seems snmpd
> doesn't allow listening to 0.0.0.0 as well as a specific v4 address
> (and similarly for :: and v6) so while it's a convenient idea to
> allow v2c on localhost for quick testing while using v3 for external
> traffic, it doesn't actually work.
This diff fixes all of the above:
- Allow any to be used resolving to 0.0.0.0 and ::
- Set SO_REUSEADDR on sockets, so we can listen on both any and
localhost
- Document that we listen on any by default
The listen on text is starting to get quite large, so I hope that one of
our man guru's can either confirm that it's still readable enough or
help me to polish it.
martijn@
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v
retrieving revision 1.64
diff -u -p -r1.64 parse.y
--- parse.y 20 Jun 2021 19:55:48 -0000 1.64
+++ parse.y 9 Aug 2021 09:53:08 -0000
@@ -128,8 +128,9 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> hostcmn
+%type <v.number> listenproto listenflag listenflags
%type <v.string> srcaddr port
-%type <v.number> optwrite yesno seclevel listenopt listenopts
+%type <v.number> optwrite yesno seclevel
%type <v.data> objtype cmd
%type <v.oid> oid hostoid trapoid
%type <v.auth> auth
@@ -195,7 +196,7 @@ yesno : STRING {
}
;
-main : LISTEN ON listenproto
+main : LISTEN ON listen_udptcp
| READONLY COMMUNITY STRING {
if (strlcpy(conf->sc_rdcommunity, $3,
sizeof(conf->sc_rdcommunity)) >=
@@ -273,15 +274,16 @@ main : LISTEN ON listenproto
}
;
-listenproto : UDP listen_udp
- | TCP listen_tcp
- | listen_udp
+listenproto : /* empty */ { $$ = SOCK_DGRAM; }
+ | UDP { $$ = SOCK_DGRAM; }
+ | TCP listen_tcp { $$ = SOCK_STREAM; }
+ ;
-listenopts : /* empty */ { $$ = 0; }
- | listenopts listenopt { $$ |= $2; }
+listenflags : /* empty */ { $$ = 0; }
+ | listenflags listenflag { $$ |= $2; }
;
-listenopt : READ { $$ = ADDRESS_FLAG_READ; }
+listenflag : READ { $$ = ADDRESS_FLAG_READ; }
| WRITE { $$ = ADDRESS_FLAG_WRITE; }
| NOTIFY { $$ = ADDRESS_FLAG_NOTIFY; }
| SNMPV1 { $$ = ADDRESS_FLAG_SNMPV1; }
@@ -289,71 +291,50 @@ listenopt : READ { $$ = ADDRESS_FLAG_REA
| SNMPV3 { $$ = ADDRESS_FLAG_SNMPV3; }
;
-listen_udp : STRING port listenopts {
+listen_udptcp : listenproto STRING port listenflags {
struct sockaddr_storage ss[16];
- int nhosts, i;
- char *port = $2;
+ int nhosts, j;
+ char *address[2], *port = $3;
+ size_t addresslen = 1, i;
if (port == NULL) {
- if (($3 & ADDRESS_FLAG_PERM) ==
+ if (($4 & ADDRESS_FLAG_PERM) ==
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);
- free($2);
- YYERROR;
+ if (strcmp($2, "any") == 0) {
+ addresslen = 2;
+ address[0] = "0.0.0.0";
+ address[1] = "::";
+ } else {
+ addresslen = 1;
+ address[0] = $2;
}
- if (nhosts > (int)nitems(ss))
- log_warn("%s:%s resolves to more than %zu
hosts",
- $1, port, nitems(ss));
- free($1);
- free($2);
- for (i = 0; i < nhosts; i++) {
- if (listen_add(&(ss[i]), SOCK_DGRAM, $3) == -1)
{
- yyerror("calloc");
+ for (i = 0; i < addresslen; i++) {
+ nhosts = host(address[i], port, $1, ss,
nitems(ss));
+ if (nhosts < 1) {
+ yyerror("invalid address: %s", $2);
+ free($2);
+ free($3);
YYERROR;
}
- }
- }
-
-listen_tcp : STRING port listenopts {
- struct sockaddr_storage ss[16];
- int nhosts, i;
- char *port = $2;
-
- if (port == NULL) {
- if (($3 & ADDRESS_FLAG_PERM) ==
- 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);
- free($2);
- YYERROR;
- }
- if (nhosts > (int)nitems(ss))
- log_warn("%s:%s resolves to more than %zu
hosts",
- $1, port, nitems(ss));
-
- free($1);
- free($2);
- for (i = 0; i < nhosts; i++) {
- if (listen_add(&(ss[i]), SOCK_STREAM, $3) ==
-1) {
- yyerror("calloc");
- YYERROR;
+ if (nhosts > (int)nitems(ss))
+ log_warn("%s:%s resolves to more than "
+ "%zu hosts", $2, port, nitems(ss));
+
+ for (j = 0; j < nhosts; j++) {
+ if (listen_add(&(ss[j]), $1, $4) == -1)
{
+ yyerror("calloc");
+ YYERROR;
+ }
}
}
+ free($2);
+ free($3);
}
port : /* empty */ {
Index: snmpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.c,v
retrieving revision 1.44
diff -u -p -r1.44 snmpd.c
--- snmpd.c 27 Jan 2021 07:21:54 -0000 1.44
+++ snmpd.c 9 Aug 2021 09:53:08 -0000
@@ -314,8 +314,22 @@ snmpd_dispatch_snmpe(int fd, struct priv
int
snmpd_socket_af(struct sockaddr_storage *ss, int type)
{
- return socket(ss->ss_family, (type == SOCK_STREAM ?
+ int fd, serrno;
+ const int enable = 1;
+
+ fd = socket(ss->ss_family, (type == SOCK_STREAM ?
SOCK_STREAM | SOCK_NONBLOCK : SOCK_DGRAM) | SOCK_CLOEXEC, 0);
+ if (fd == -1)
+ return -1;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
+ sizeof(enable)) == -1) {
+ serrno = errno;
+ close(fd);
+ errno = serrno;
+ return -1;
+ }
+ return fd;
}
void
Index: snmpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v
retrieving revision 1.52
diff -u -p -r1.52 snmpd.conf.5
--- snmpd.conf.5 8 Aug 2021 13:41:26 -0000 1.52
+++ snmpd.conf.5 9 Aug 2021 09:53:08 -0000
@@ -96,9 +96,22 @@ reduced during bulk updates.
The default is
.Ic no .
.It Ic listen on Oo Ic tcp | udp Oc Ar address Oo Ic port Ar port Oc Op Ar
flags
-Specify the local address
+Specify the local
+.Ar address
.Xr snmpd 8
should listen on for incoming SNMP messages.
+If
+.Ar address
+is set to
+.Cm any
+it resolves to 0.0.0.0 and ::.
+Multiple
+.Ic listen on
+statements are supported.
+If no
+.Ic listen on
+statements are present it defaults to
+.Cm any .
.Pp
The
.Ar flags
@@ -119,9 +132,6 @@ Enables SNMPv2c subsystem on the listen
Enables SNMPv3 subsystem on the listen address.
.El
.Pp
-Multiple
-.Ic listen on
-statements are supported.
The default protocol is
.Ic udp .
The default