Re: snmpd source address
Jeremie Courreges-Anglaswrites: > Jeremie Courreges-Anglas writes: > >> Jeremie Courreges-Anglas writes: >> >>> Jeremie Courreges-Anglas writes: >>> j...@wxcvbn.org (Jeremie Courreges-Anglas) writes: > SNMP uses UDP and snmpd listens on a single address. This means that > you can have issues with the source address of the replies sent by > snmpd. "listen on $loopback_address": > > http://marc.info/?l=openbsd-misc=147445870822415=2 > > seems to be unsufficient, but I don't understand why it would fail. > > The diff below should fix the source address selection for replies. > Configuring the source address for traps is a different problem and will > be implemented in a different diff. Updated diff that implements a "source-address" parameter for trap receivers, as discussed with Reyk. > WIP, only tested on a single box so far. Thoughts / oks? source-address lightly tested with: trap receiver 127.0.0.1 trap receiver 127.0.0.1 source-address 192.168.0.44 trap receiver fe80::1%lo0 source-address ::1 Comments and test reports welcome. >>> >>> Notes regarding source-address: >>> - only try to handle an address, not a hostname. I didn't want >>> to handle the additional complexity as I'm not sure it's worth it. >>> - say we have "trap receiver somehostname source-address fd00::1". >>> Should we try to filter out potential IPv4 addresses and find an >>> appropriate IPv6 address? The diff below would error out if the first >>> record found is an IPv4. >> >> I decided to go ahead and skip records in case of AF mismatch. Lightly >> tested with: >> - /etc/snmpd.conf >> trap receiver somehostname source-address ::1 >> - $ ifconfig lo1 >> lo1: flags=8049 mtu 32768 >> index 6 priority 0 llprio 3 >> groups: lo >> inet 192.0.2.1 netmask 0xff00 >> inet6 ::1 prefixlen 128 >> inet6 fe80::1%lo1 prefixlen 64 scopeid 0x6 >> inet6 2001:db8::1 prefixlen 64 >> - /etc/hosts >> 192.0.2.1 somehostname >> 2001:db8::1 somehostname >> >> Comments and test reports still welcome. :) > > Ping. Now with manpage bits. Updated diff after recent commits in snmpd. Index: parse.y === RCS file: /d/cvs/src/usr.sbin/snmpd/parse.y,v retrieving revision 1.39 diff -u -p -r1.39 parse.y --- parse.y 21 Jun 2016 21:35:25 - 1.39 +++ parse.y 1 Nov 2016 17:45:40 - @@ -98,9 +98,10 @@ static intnctlsocks = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); int host_dns(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, + struct address *); int host(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, char *); typedef struct { union { @@ -127,10 +128,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 SOCKET RESTRICTED AGENTX HANDLE DEFAULT +%token SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR %token STRING %token NUMBER %typehostcmn +%typesrcaddr %typeoptwrite yesno seclevel socktype %type objtype cmd %type oid hostoid trapoid @@ -200,7 +202,8 @@ main: LISTEN ON STRING { struct address *h; TAILQ_INIT(); - if (host($3, , 1, SNMPD_PORT, NULL, NULL) <= 0) { + if (host($3, , 1, SNMPD_PORT, NULL, NULL, NULL) + <= 0) { yyerror("invalid ip address: %s", $3); free($3); YYERROR; @@ -445,9 +448,13 @@ hostcmn: /* empty */ { $$ = NULL; } | COMMUNITY STRING { $$ = $2; } ; -hostdef: STRING hostoid hostcmn{ +srcaddr: /* empty */ { $$ = NULL; } + | SRCADDR STRING{ $$ = $2; } + ; + +hostdef: STRING hostoid hostcmn srcaddr{ if (host($1, hlist, 1, - SNMPD_TRAPPORT, $2, $3) <= 0) { + SNMPD_TRAPPORT, $2, $3, $4) <= 0) { yyerror("invalid
Re: snmpd source address
Jeremie Courreges-Anglaswrites: > Jeremie Courreges-Anglas writes: > >> Jeremie Courreges-Anglas writes: >> >>> j...@wxcvbn.org (Jeremie Courreges-Anglas) writes: >>> SNMP uses UDP and snmpd listens on a single address. This means that you can have issues with the source address of the replies sent by snmpd. "listen on $loopback_address": http://marc.info/?l=openbsd-misc=147445870822415=2 seems to be unsufficient, but I don't understand why it would fail. The diff below should fix the source address selection for replies. Configuring the source address for traps is a different problem and will be implemented in a different diff. >>> >>> Updated diff that implements a "source-address" parameter for trap >>> receivers, as discussed with Reyk. >>> WIP, only tested on a single box so far. Thoughts / oks? >>> >>> source-address lightly tested with: >>> trap receiver 127.0.0.1 >>> trap receiver 127.0.0.1 source-address 192.168.0.44 >>> trap receiver fe80::1%lo0 source-address ::1 >>> >>> Comments and test reports welcome. >> >> Notes regarding source-address: >> - only try to handle an address, not a hostname. I didn't want >> to handle the additional complexity as I'm not sure it's worth it. >> - say we have "trap receiver somehostname source-address fd00::1". >> Should we try to filter out potential IPv4 addresses and find an >> appropriate IPv6 address? The diff below would error out if the first >> record found is an IPv4. > > I decided to go ahead and skip records in case of AF mismatch. Lightly > tested with: > - /etc/snmpd.conf > trap receiver somehostname source-address ::1 > - $ ifconfig lo1 > lo1: flags=8049 mtu 32768 > index 6 priority 0 llprio 3 > groups: lo > inet 192.0.2.1 netmask 0xff00 > inet6 ::1 prefixlen 128 > inet6 fe80::1%lo1 prefixlen 64 scopeid 0x6 > inet6 2001:db8::1 prefixlen 64 > - /etc/hosts > 192.0.2.1 somehostname > 2001:db8::1 somehostname > > Comments and test reports still welcome. :) Ping. Now with manpage bits. Index: parse.y === RCS file: /d/cvs/src/usr.sbin/snmpd/parse.y,v retrieving revision 1.39 diff -u -p -r1.39 parse.y --- parse.y 21 Jun 2016 21:35:25 - 1.39 +++ parse.y 21 Oct 2016 11:28:15 - @@ -98,9 +98,10 @@ static intnctlsocks = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); int host_dns(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, + struct address *); int host(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, char *); typedef struct { union { @@ -127,10 +128,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 SOCKET RESTRICTED AGENTX HANDLE DEFAULT +%token SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR %token STRING %token NUMBER %typehostcmn +%typesrcaddr %typeoptwrite yesno seclevel socktype %type objtype cmd %type oid hostoid trapoid @@ -200,7 +202,8 @@ main: LISTEN ON STRING { struct address *h; TAILQ_INIT(); - if (host($3, , 1, SNMPD_PORT, NULL, NULL) <= 0) { + if (host($3, , 1, SNMPD_PORT, NULL, NULL, NULL) + <= 0) { yyerror("invalid ip address: %s", $3); free($3); YYERROR; @@ -445,9 +448,13 @@ hostcmn: /* empty */ { $$ = NULL; } | COMMUNITY STRING { $$ = $2; } ; -hostdef: STRING hostoid hostcmn{ +srcaddr: /* empty */ { $$ = NULL; } + | SRCADDR STRING{ $$ = $2; } + ; + +hostdef: STRING hostoid hostcmn srcaddr{ if (host($1, hlist, 1, - SNMPD_TRAPPORT, $2, $3) <= 0) { + SNMPD_TRAPPORT, $2, $3, $4) <= 0) { yyerror("invalid host: %s", $1); free($1); YYERROR; @@ -636,6 +643,7 @@ lookup(char *s) {
Re: snmpd source address
Jeremie Courreges-Anglaswrites: > Jeremie Courreges-Anglas writes: > >> j...@wxcvbn.org (Jeremie Courreges-Anglas) writes: >> >>> SNMP uses UDP and snmpd listens on a single address. This means that >>> you can have issues with the source address of the replies sent by >>> snmpd. "listen on $loopback_address": >>> >>> http://marc.info/?l=openbsd-misc=147445870822415=2 >>> >>> seems to be unsufficient, but I don't understand why it would fail. >>> >>> The diff below should fix the source address selection for replies. >>> Configuring the source address for traps is a different problem and will >>> be implemented in a different diff. >> >> Updated diff that implements a "source-address" parameter for trap >> receivers, as discussed with Reyk. >> >>> WIP, only tested on a single box so far. Thoughts / oks? >> >> source-address lightly tested with: >> trap receiver 127.0.0.1 >> trap receiver 127.0.0.1 source-address 192.168.0.44 >> trap receiver fe80::1%lo0 source-address ::1 >> >> Comments and test reports welcome. > > Notes regarding source-address: > - only try to handle an address, not a hostname. I didn't want > to handle the additional complexity as I'm not sure it's worth it. > - say we have "trap receiver somehostname source-address fd00::1". > Should we try to filter out potential IPv4 addresses and find an > appropriate IPv6 address? The diff below would error out if the first > record found is an IPv4. I decided to go ahead and skip records in case of AF mismatch. Lightly tested with: - /etc/snmpd.conf trap receiver somehostname source-address ::1 - $ ifconfig lo1 lo1: flags=8049 mtu 32768 index 6 priority 0 llprio 3 groups: lo inet 192.0.2.1 netmask 0xff00 inet6 ::1 prefixlen 128 inet6 fe80::1%lo1 prefixlen 64 scopeid 0x6 inet6 2001:db8::1 prefixlen 64 - /etc/hosts 192.0.2.1 somehostname 2001:db8::1 somehostname Comments and test reports still welcome. :) Index: parse.y === RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v retrieving revision 1.39 diff -u -p -r1.39 parse.y --- parse.y 21 Jun 2016 21:35:25 - 1.39 +++ parse.y 30 Sep 2016 14:15:25 - @@ -98,9 +98,10 @@ static intnctlsocks = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); int host_dns(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, + struct address *); int host(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, char *); typedef struct { union { @@ -127,10 +128,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 SOCKET RESTRICTED AGENTX HANDLE DEFAULT +%token SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR %token STRING %token NUMBER %typehostcmn +%typesrcaddr %typeoptwrite yesno seclevel socktype %type objtype cmd %type oid hostoid trapoid @@ -200,7 +202,8 @@ main: LISTEN ON STRING { struct address *h; TAILQ_INIT(); - if (host($3, , 1, SNMPD_PORT, NULL, NULL) <= 0) { + if (host($3, , 1, SNMPD_PORT, NULL, NULL, NULL) + <= 0) { yyerror("invalid ip address: %s", $3); free($3); YYERROR; @@ -445,9 +448,13 @@ hostcmn: /* empty */ { $$ = NULL; } | COMMUNITY STRING { $$ = $2; } ; -hostdef: STRING hostoid hostcmn{ +srcaddr: /* empty */ { $$ = NULL; } + | SRCADDR STRING{ $$ = $2; } + ; + +hostdef: STRING hostoid hostcmn srcaddr{ if (host($1, hlist, 1, - SNMPD_TRAPPORT, $2, $3) <= 0) { + SNMPD_TRAPPORT, $2, $3, $4) <= 0) { yyerror("invalid host: %s", $1); free($1); YYERROR; @@ -636,6 +643,7 @@ lookup(char *s) { "seclevel", SECLEVEL }, { "services", SERVICES }, { "socket", SOCKET }, + {
Re: snmpd source address
Jeremie Courreges-Anglaswrites: > j...@wxcvbn.org (Jeremie Courreges-Anglas) writes: > >> SNMP uses UDP and snmpd listens on a single address. This means that >> you can have issues with the source address of the replies sent by >> snmpd. "listen on $loopback_address": >> >> http://marc.info/?l=openbsd-misc=147445870822415=2 >> >> seems to be unsufficient, but I don't understand why it would fail. >> >> The diff below should fix the source address selection for replies. >> Configuring the source address for traps is a different problem and will >> be implemented in a different diff. > > Updated diff that implements a "source-address" parameter for trap > receivers, as discussed with Reyk. > >> WIP, only tested on a single box so far. Thoughts / oks? > > source-address lightly tested with: > trap receiver 127.0.0.1 > trap receiver 127.0.0.1 source-address 192.168.0.44 > trap receiver fe80::1%lo0 source-address ::1 > > Comments and test reports welcome. Notes regarding source-address: - only try to handle an address, not a hostname. I didn't want to handle the additional complexity as I'm not sure it's worth it. - say we have "trap receiver somehostname source-address fd00::1". Should we try to filter out potential IPv4 addresses and find an appropriate IPv6 address? The diff below would error out if the first record found is an IPv4. > > Index: parse.y > === > RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v > retrieving revision 1.39 > diff -u -p -r1.39 parse.y > --- parse.y 21 Jun 2016 21:35:25 - 1.39 > +++ parse.y 30 Sep 2016 13:33:28 - > @@ -98,9 +98,10 @@ static int nctlsocks = 0; > struct address *host_v4(const char *); > struct address *host_v6(const char *); > int host_dns(const char *, struct addresslist *, > - int, in_port_t, struct ber_oid *, char *); > + int, in_port_t, struct ber_oid *, char *, > + struct address *); > int host(const char *, struct addresslist *, > - int, in_port_t, struct ber_oid *, char *); > + int, in_port_t, struct ber_oid *, char *, char *); > > typedef struct { > union { > @@ -127,10 +128,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 SOCKET RESTRICTED AGENTX HANDLE DEFAULT > +%token SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR > %token STRING > %token NUMBER > %type hostcmn > +%type srcaddr > %type optwrite yesno seclevel socktype > %typeobjtype cmd > %type oid hostoid trapoid > @@ -200,7 +202,8 @@ main : LISTEN ON STRING { > struct address *h; > > TAILQ_INIT(); > - if (host($3, , 1, SNMPD_PORT, NULL, NULL) <= 0) { > + if (host($3, , 1, SNMPD_PORT, NULL, NULL, NULL) > + <= 0) { > yyerror("invalid ip address: %s", $3); > free($3); > YYERROR; > @@ -445,9 +448,13 @@ hostcmn : /* empty */ > { $$ = NULL; } > | COMMUNITY STRING { $$ = $2; } > ; > > -hostdef : STRING hostoid hostcmn{ > +srcaddr : /* empty */ { $$ = NULL; } > + | SRCADDR STRING{ $$ = $2; } > + ; > + > +hostdef : STRING hostoid hostcmn srcaddr{ > if (host($1, hlist, 1, > - SNMPD_TRAPPORT, $2, $3) <= 0) { > + SNMPD_TRAPPORT, $2, $3, $4) <= 0) { > yyerror("invalid host: %s", $1); > free($1); > YYERROR; > @@ -636,6 +643,7 @@ lookup(char *s) > { "seclevel", SECLEVEL }, > { "services", SERVICES }, > { "socket", SOCKET }, > + { "source-address", SRCADDR }, > { "string", OCTETSTRING }, > { "system", SYSTEM }, > { "trap", TRAP }, > @@ -1151,7 +1159,7 @@ host_v6(const char *s) > > int > host_dns(const char *s, struct addresslist *al, int max, > - in_port_t port, struct ber_oid *oid, char *cmn) > + in_port_t port, struct ber_oid *oid, char *cmn, struct address *src) > { > struct addrinfo hints, *res0, *res; > int error, cnt
Re: snmpd source address
j...@wxcvbn.org (Jeremie Courreges-Anglas) writes: > SNMP uses UDP and snmpd listens on a single address. This means that > you can have issues with the source address of the replies sent by > snmpd. "listen on $loopback_address": > > http://marc.info/?l=openbsd-misc=147445870822415=2 > > seems to be unsufficient, but I don't understand why it would fail. > > The diff below should fix the source address selection for replies. > Configuring the source address for traps is a different problem and will > be implemented in a different diff. Updated diff that implements a "source-address" parameter for trap receivers, as discussed with Reyk. > WIP, only tested on a single box so far. Thoughts / oks? source-address lightly tested with: trap receiver 127.0.0.1 trap receiver 127.0.0.1 source-address 192.168.0.44 trap receiver fe80::1%lo0 source-address ::1 Comments and test reports welcome. Index: parse.y === RCS file: /cvs/src/usr.sbin/snmpd/parse.y,v retrieving revision 1.39 diff -u -p -r1.39 parse.y --- parse.y 21 Jun 2016 21:35:25 - 1.39 +++ parse.y 30 Sep 2016 13:33:28 - @@ -98,9 +98,10 @@ static intnctlsocks = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); int host_dns(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, + struct address *); int host(const char *, struct addresslist *, - int, in_port_t, struct ber_oid *, char *); + int, in_port_t, struct ber_oid *, char *, char *); typedef struct { union { @@ -127,10 +128,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 SOCKET RESTRICTED AGENTX HANDLE DEFAULT +%token SOCKET RESTRICTED AGENTX HANDLE DEFAULT SRCADDR %token STRING %token NUMBER %typehostcmn +%typesrcaddr %typeoptwrite yesno seclevel socktype %type objtype cmd %type oid hostoid trapoid @@ -200,7 +202,8 @@ main: LISTEN ON STRING { struct address *h; TAILQ_INIT(); - if (host($3, , 1, SNMPD_PORT, NULL, NULL) <= 0) { + if (host($3, , 1, SNMPD_PORT, NULL, NULL, NULL) + <= 0) { yyerror("invalid ip address: %s", $3); free($3); YYERROR; @@ -445,9 +448,13 @@ hostcmn: /* empty */ { $$ = NULL; } | COMMUNITY STRING { $$ = $2; } ; -hostdef: STRING hostoid hostcmn{ +srcaddr: /* empty */ { $$ = NULL; } + | SRCADDR STRING{ $$ = $2; } + ; + +hostdef: STRING hostoid hostcmn srcaddr{ if (host($1, hlist, 1, - SNMPD_TRAPPORT, $2, $3) <= 0) { + SNMPD_TRAPPORT, $2, $3, $4) <= 0) { yyerror("invalid host: %s", $1); free($1); YYERROR; @@ -636,6 +643,7 @@ lookup(char *s) { "seclevel", SECLEVEL }, { "services", SERVICES }, { "socket", SOCKET }, + { "source-address", SRCADDR }, { "string", OCTETSTRING }, { "system", SYSTEM }, { "trap", TRAP }, @@ -1151,7 +1159,7 @@ host_v6(const char *s) int host_dns(const char *s, struct addresslist *al, int max, -in_port_t port, struct ber_oid *oid, char *cmn) + in_port_t port, struct ber_oid *oid, char *cmn, struct address *src) { struct addrinfo hints, *res0, *res; int error, cnt = 0; @@ -1202,6 +1210,13 @@ host_dns(const char *s, struct addressli memcpy(>sin6_addr, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); } + if (src != NULL) { + if (h->ss.ss_family != src->ss.ss_family) { + log_warnx("host and source-address family mismatch"); + return (-1); + } + h->sa_srcaddr = src; + } TAILQ_INSERT_HEAD(al, h, entry);
snmpd source address
SNMP uses UDP and snmpd listens on a single address. This means that you can have issues with the source address of the replies sent by snmpd. "listen on $loopback_address": http://marc.info/?l=openbsd-misc=147445870822415=2 seems to be unsufficient, but I don't understand why it would fail. The diff below should fix the source address selection for replies. Configuring the source address for traps is a different problem and will be implemented in a different diff. WIP, only tested on a single box so far. Thoughts / oks? Index: snmpd.h === RCS file: /cvs/src/usr.sbin/snmpd/snmpd.h,v retrieving revision 1.68 diff -u -p -r1.68 snmpd.h --- snmpd.h 25 Sep 2016 14:58:00 - 1.68 +++ snmpd.h 28 Sep 2016 20:11:05 - @@ -390,6 +390,9 @@ struct snmp_message { socklen_tsm_slen; char sm_host[HOST_NAME_MAX+1]; + struct sockaddr_storage sm_local_ss; + socklen_tsm_local_slen; + struct ber sm_ber; struct ber_element *sm_req; struct ber_element *sm_resp; @@ -766,6 +769,10 @@ struct trapcmd * /* util.c */ int varbind_convert(struct agentx_pdu *, struct agentx_varbind_hdr *, struct ber_element **, struct ber_element **); +ssize_t sendtofrom(int, void *, size_t, int, struct sockaddr *, + socklen_t, struct sockaddr *, socklen_t); +ssize_t recvfromto(int, void *, size_t, int, struct sockaddr *, + socklen_t *, struct sockaddr *, socklen_t *); voidprint_debug(const char *, ...); voidprint_verbose(const char *, ...); const char *log_in6addr(const struct in6_addr *); Index: snmpe.c === RCS file: /cvs/src/usr.sbin/snmpd/snmpe.c,v retrieving revision 1.42 diff -u -p -r1.42 snmpe.c --- snmpe.c 16 Aug 2016 18:41:57 - 1.42 +++ snmpe.c 28 Sep 2016 20:11:05 - @@ -120,7 +120,7 @@ int snmpe_bind(struct address *addr) { char buf[512]; - int s; + int val, s; if ((s = snmpd_socket_af(>ss, htons(addr->port))) == -1) return (-1); @@ -131,6 +131,26 @@ snmpe_bind(struct address *addr) if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) goto bad; + switch (addr->ss.ss_family) { + case AF_INET: + val = 1; + if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, + , sizeof(int)) == -1) { + log_warn("%s: failed to set IPv4 packet info", + __func__); + goto bad; + } + break; + case AF_INET6: + val = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, + , sizeof(int)) == -1) { + log_warn("%s: failed to set IPv6 packet info", + __func__); + goto bad; + } + } + if (bind(s, (struct sockaddr *)>ss, addr->ss.ss_len) == -1) goto bad; @@ -460,8 +480,9 @@ snmpe_recvmsg(int fd, short sig, void *a return; msg->sm_slen = sizeof(msg->sm_ss); - if ((len = recvfrom(fd, msg->sm_data, sizeof(msg->sm_data), 0, - (struct sockaddr *)>sm_ss, >sm_slen)) < 1) { + if ((len = recvfromto(fd, msg->sm_data, sizeof(msg->sm_data), 0, + (struct sockaddr *)>sm_ss, >sm_slen, + (struct sockaddr *)>sm_local_ss, >sm_local_slen)) < 1) { free(msg); return; } @@ -549,8 +570,9 @@ snmpe_response(int fd, struct snmp_messa goto done; usm_finalize_digest(msg, ptr, len); - len = sendto(fd, ptr, len, 0, (struct sockaddr *)>sm_ss, - msg->sm_slen); + len = sendtofrom(fd, ptr, len, 0, + (struct sockaddr *)>sm_ss, msg->sm_slen, + (struct sockaddr *)>sm_local_ss, msg->sm_local_slen); if (len != -1) stats->snmp_outpkts++; Index: util.c === RCS file: /cvs/src/usr.sbin/snmpd/util.c,v retrieving revision 1.5 diff -u -p -r1.5 util.c --- util.c 21 Nov 2015 13:06:22 - 1.5 +++ util.c 28 Sep 2016 20:11:05 - @@ -156,6 +156,128 @@ varbind_convert(struct agentx_pdu *pdu, return (ret); } +ssize_t +sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to, +socklen_t tolen, struct sockaddr *from, socklen_t fromlen) +{ + struct iovec iov; + struct msghdrmsg; + struct cmsghdr *cmsg; + struct in6_pktinfo *pkt6; + struct sockaddr_in *in; + struct sockaddr_in6 *in6; + union { + struct cmsghdr hdr; + char