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


Reply via email to