Moving towards individual transport mappings, it's becoming more convenient to have the protocol directly after the listen on statement. This gives me more flexibility in using mapping-specific APIs, also when other transport mappings might become available in the future it allows for easier mapping-specific features.
While here I decided to also add port support for snmpe, which at this point is rather trivial. Traphandler is not my point of focus at this time. having udp|tcp at the last position is still supported, but generates a pretty deprecated warning. Probably to be removed after release. OK? martijn@ Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v retrieving revision 1.60 diff -u -p -r1.60 parse.y --- parse.y 6 Sep 2020 15:51:28 -0000 1.60 +++ parse.y 6 Sep 2020 20:08:08 -0000 @@ -40,6 +40,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <inttypes.h> #include <limits.h> #include <stdint.h> #include <stdarg.h> @@ -92,6 +93,7 @@ char *symget(const char *); 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); @@ -122,11 +124,11 @@ typedef struct { %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 HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER +%token HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER PORT %token <v.string> STRING %token <v.number> NUMBER %type <v.string> hostcmn -%type <v.string> srcaddr +%type <v.string> srcaddr port %type <v.number> optwrite yesno seclevel proto %type <v.data> objtype cmd %type <v.oid> oid hostoid trapoid @@ -193,28 +195,7 @@ yesno : STRING { } ; -main : LISTEN ON STRING proto { - struct sockaddr_storage ss[16]; - int nhosts, i; - - nhosts = host($3, SNMPD_PORT, $4, ss, nitems(ss)); - if (nhosts < 1) { - yyerror("invalid address: %s", $3); - free($3); - YYERROR; - } - if (nhosts > (int)nitems(ss)) - log_warn("%s resolves to more than %zu hosts", - $3, nitems(ss)); - free($3); - - for (i = 0; i < nhosts; i++) { - if (listen_add(&(ss[i]), $4) == -1) { - yyerror("calloc"); - YYERROR; - } - } - } +main : LISTEN ON listenproto | READONLY COMMUNITY STRING { if (strlcpy(conf->sc_rdcommunity, $3, sizeof(conf->sc_rdcommunity)) >= @@ -295,6 +276,128 @@ main : LISTEN ON STRING proto { } ; +listenproto : UDP listen_udp + | TCP listen_tcp + | listen_empty + +listen_udp : STRING port { + struct sockaddr_storage ss[16]; + int nhosts, i; + + nhosts = host($1, $2, SOCK_DGRAM, ss, nitems(ss)); + if (nhosts < 1) { + yyerror("invalid address: %s", $1); + free($1); + if ($2 != snmpd_port) + free($2); + YYERROR; + } + if (nhosts > (int)nitems(ss)) + log_warn("%s:%s resolves to more than %zu hosts", + $1, $2, nitems(ss)); + + free($1); + if ($2 != snmpd_port) + free($2); + for (i = 0; i < nhosts; i++) { + if (listen_add(&(ss[i]), SOCK_DGRAM) == -1) { + yyerror("calloc"); + YYERROR; + } + } + } + +listen_tcp : STRING port { + struct sockaddr_storage ss[16]; + int nhosts, i; + + nhosts = host($1, $2, SOCK_STREAM, ss, nitems(ss)); + if (nhosts < 1) { + yyerror("invalid address: %s", $1); + free($1); + if ($2 != snmpd_port) + free($2); + YYERROR; + } + if (nhosts > (int)nitems(ss)) + log_warn("%s:%s resolves to more than %zu hosts", + $1, $2, nitems(ss)); + + free($1); + if ($2 != snmpd_port) + free($2); + for (i = 0; i < nhosts; i++) { + if (listen_add(&(ss[i]), SOCK_STREAM) == -1) { + yyerror("calloc"); + YYERROR; + } + } + } + +/* Remove after deprecation period and replace with listen_udp */ +listen_empty : STRING port proto { + struct sockaddr_storage ss[16]; + int nhosts, i; + + nhosts = host($1, $2, $3, ss, nitems(ss)); + if (nhosts < 1) { + yyerror("invalid address: %s", $1); + free($1); + if ($2 != snmpd_port) + free($2); + YYERROR; + } + if (nhosts > (int)nitems(ss)) + log_warn("%s:%s resolves to more than %zu hosts", + $1, $2, nitems(ss)); + + free($1); + if ($2 != snmpd_port) + free($2); + for (i = 0; i < nhosts; i++) { + if (listen_add(&(ss[i]), $3) == -1) { + yyerror("calloc"); + YYERROR; + } + } + } + +port : /* empty */ { + $$ = snmpd_port; + } + | PORT STRING { + $$ = $2; + } + | PORT NUMBER { + char *number; + + if ($2 > UINT16_MAX) { + yyerror("port number too large"); + YYERROR; + } + if (asprintf(&number, "%"PRId64, $2) == -1) { + yyerror("malloc"); + YYERROR; + } + $$ = number; + } + ; + +proto : /* empty */ { + $$ = SOCK_DGRAM; + } + | UDP { + log_warnx("udp as last keyword on listen on line is " + "deprecated"); + $$ = SOCK_DGRAM; + } + | TCP { + log_warnx("tcp as last keyword on listen on line is " + "deprecated"); + $$ = SOCK_STREAM; + } + ; + system : SYSTEM sysmib ; @@ -541,11 +644,6 @@ enc : STRING { } ; -proto : /* empty */ { $$ = SOCK_DGRAM; } - | TCP { $$ = SOCK_STREAM; } - | UDP { $$ = SOCK_DGRAM; } - ; - cmd : STRING { struct trapcmd *cmd; size_t span, limit; @@ -646,6 +744,7 @@ lookup(char *s) { "none", NONE }, { "oid", OBJECTID }, { "on", ON }, + { "port", PORT }, { "read-only", READONLY }, { "read-write", READWRITE }, { "receiver", RECEIVER }, Index: snmpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/snmpd/snmpd.conf.5,v retrieving revision 1.43 diff -u -p -r1.43 snmpd.conf.5 --- snmpd.conf.5 30 Jun 2020 17:11:49 -0000 1.43 +++ snmpd.conf.5 6 Sep 2020 20:08:08 -0000 @@ -95,7 +95,7 @@ Routing table information will not be av reduced during bulk updates. The default is .Ic no . -.It Ic listen on Ar address Op Ic tcp | udp +.It Ic listen on Oo Ic tcp | udp Oc Ar address Op Ic port Ar port Specify the local address .Xr snmpd 8 should listen on for incoming SNMP messages.