--- include/net-snmp/library/snmpIPBaseDomain.h | 2 + snmplib/transports/snmpIPBaseDomain.c | 41 +++++++++++++++++++-- snmplib/transports/snmpIPv4BaseDomain.c | 2 + snmplib/transports/snmpIPv6BaseDomain.c | 2 + snmplib/transports/snmpTCPDomain.c | 7 ++++ snmplib/transports/snmpTCPIPv6Domain.c | 6 +++ snmplib/transports/snmpUDPIPv4BaseDomain.c | 13 ++++++- snmplib/transports/snmpUDPIPv6Domain.c | 13 ++++++- 8 files changed, 79 insertions(+), 7 deletions(-)
diff --git a/include/net-snmp/library/snmpIPBaseDomain.h b/include/net-snmp/library/snmpIPBaseDomain.h index 6eaf37ac4253..635c748ac930 100644 --- a/include/net-snmp/library/snmpIPBaseDomain.h +++ b/include/net-snmp/library/snmpIPBaseDomain.h @@ -26,9 +26,11 @@ struct netsnmp_ep { */ struct netsnmp_ep_str { char addr[64]; + char iface[16]; uint16_t port; }; int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint); +int netsnmp_bindtodevice(int fd, const char *iface); #endif /* _SNMPIPBASEDOMAIN_H_ */ diff --git a/snmplib/transports/snmpIPBaseDomain.c b/snmplib/transports/snmpIPBaseDomain.c index ac94ba73840d..ea0a291c8529 100644 --- a/snmplib/transports/snmpIPBaseDomain.c +++ b/snmplib/transports/snmpIPBaseDomain.c @@ -3,6 +3,7 @@ #include <net-snmp/library/system.h> #include <net-snmp/library/snmpIPBaseDomain.h> #include <ctype.h> +#include <errno.h> #include <stdlib.h> static int isnumber(const char *cp) @@ -23,7 +24,7 @@ static int isnumber(const char *cp) */ int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint) { - char *dup, *cp, *addrstr = NULL, *portstr = NULL; + char *dup, *cp, *addrstr = NULL, *iface = NULL, *portstr = NULL; unsigned port; if (!endpoint) @@ -46,9 +47,16 @@ int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint) } else { goto invalid; } - } else if (*cp != ':') { + } else if (*cp != '@' && *cp != ':') { addrstr = cp; - cp = strrchr(cp, ':'); + cp = strchr(addrstr, '@'); + if (!cp) + cp = strrchr(addrstr, ':'); + } + if (cp && *cp == '@') { + *cp = '\0'; + iface = cp + 1; + cp = strchr(cp + 1, ':'); } if (cp && *cp == ':') { *cp++ = '\0'; @@ -62,6 +70,8 @@ int netsnmp_parse_ep_str(struct netsnmp_ep_str *ep_str, const char *endpoint) if (addrstr) strlcpy(ep_str->addr, addrstr, sizeof(ep_str->addr)); + if (iface) + strlcpy(ep_str->iface, iface, sizeof(ep_str->iface)); if (portstr) { port = atoi(portstr); if (port > 0 && port <= 0xffff) @@ -77,3 +87,28 @@ invalid: free(dup); return 0; } + +int netsnmp_bindtodevice(int fd, const char *iface) +{ + /* If no interface name has been specified, report success. */ + if (!iface || iface[0] == '\0') + return 0; + +#ifdef HAVE_SO_BINDTODEVICE + /* + * +1 to work around the Linux kernel bug that the passed in name is not + * '\0'-terminated. + */ + int ifacelen = strlen(iface) + 1; + int ret; + + ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface, ifacelen); + if (ret < 0) + snmp_log(LOG_ERR, "Binding socket to interface %s failed: %s\n", iface, + strerror(errno)); + return ret; +#else + errno = EINVAL; + return -1; +#endif +} diff --git a/snmplib/transports/snmpIPv4BaseDomain.c b/snmplib/transports/snmpIPv4BaseDomain.c index d8537fbdc912..c3f2671cbe98 100644 --- a/snmplib/transports/snmpIPv4BaseDomain.c +++ b/snmplib/transports/snmpIPv4BaseDomain.c @@ -108,6 +108,8 @@ netsnmp_sockaddr_in3(struct netsnmp_ep *ep, if (netsnmp_parse_ep_str(&ep_str, inpeername)) { if (ep_str.port) addr->sin_port = htons(ep_str.port); + if (ep_str.iface[0]) + strlcpy(ep->iface, ep_str.iface, sizeof(ep->iface)); if (strcmp(ep_str.addr, "255.255.255.255") == 0 ) { /* * The explicit broadcast address hack diff --git a/snmplib/transports/snmpIPv6BaseDomain.c b/snmplib/transports/snmpIPv6BaseDomain.c index c2baacc5d42c..1a87ee97767e 100644 --- a/snmplib/transports/snmpIPv6BaseDomain.c +++ b/snmplib/transports/snmpIPv6BaseDomain.c @@ -309,6 +309,8 @@ netsnmp_sockaddr_in6_3(struct netsnmp_ep *ep, !netsnmp_resolve_v6_hostname(&addr->sin6_addr, ep_str.addr)) return 0; } + if (ep_str.iface[0]) + strlcpy(ep->iface, ep_str.iface, sizeof(ep->iface)); if (ep_str.port) addr->sin6_port = htons(ep_str.port); } diff --git a/snmplib/transports/snmpTCPDomain.c b/snmplib/transports/snmpTCPDomain.c index ac9b66a16fd5..cfe6b13d75de 100644 --- a/snmplib/transports/snmpTCPDomain.c +++ b/snmplib/transports/snmpTCPDomain.c @@ -227,6 +227,13 @@ netsnmp_tcp_transport(const struct netsnmp_ep *ep, int local) sizeof(opt)); if (!socket_initialized) { + rc = netsnmp_bindtodevice(t->sock, ep->iface); + if (rc != 0) { + DEBUGMSGTL(("netsnmp_tcpbase", + "failed to bind to iface %s: %s\n", + ep->iface, strerror(errno))); + goto err; + } rc = bind(t->sock, (const struct sockaddr *)addr, sizeof(*addr)); if (rc != 0) goto err; diff --git a/snmplib/transports/snmpTCPIPv6Domain.c b/snmplib/transports/snmpTCPIPv6Domain.c index cdff5fab6843..47bf5747840b 100644 --- a/snmplib/transports/snmpTCPIPv6Domain.c +++ b/snmplib/transports/snmpTCPIPv6Domain.c @@ -231,6 +231,12 @@ netsnmp_tcp6_transport(const struct netsnmp_ep *ep, int local) setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)); if (!socket_initialized) { + rc = netsnmp_bindtodevice(t->sock, ep->iface); + if (rc != 0) { + DEBUGMSGTL(("netsnmp_tcp6", "failed to bind to iface %s: %s\n", + ep->iface, strerror(errno))); + goto err; + } rc = bind(t->sock, (const struct sockaddr *)addr, sizeof(*addr)); if (rc != 0) goto err; diff --git a/snmplib/transports/snmpUDPIPv4BaseDomain.c b/snmplib/transports/snmpUDPIPv4BaseDomain.c index 7f8b68108d6d..eb30ea99f7ec 100644 --- a/snmplib/transports/snmpUDPIPv4BaseDomain.c +++ b/snmplib/transports/snmpUDPIPv4BaseDomain.c @@ -208,16 +208,25 @@ netsnmp_udpipv4base_transport_bind(netsnmp_transport *t, t->sock, str)); free(str); } + rc = netsnmp_bindtodevice(t->sock, ep->iface); + if (rc != 0) { + DEBUGMSGTL(("netsnmp_udpbase", "failed to bind to iface %s: %s\n", + ep->iface, strerror(errno))); + goto err; + } rc = bind(t->sock, (const struct sockaddr *)addr, sizeof(*addr)); if ( rc != 0 ) { DEBUGMSGTL(("netsnmp_udpbase", "failed to bind for clientaddr: %d %s\n", errno, strerror(errno))); - netsnmp_socketbase_close(t); - return 1; + goto err; } return 0; + +err: + netsnmp_socketbase_close(t); + return 1; } void diff --git a/snmplib/transports/snmpUDPIPv6Domain.c b/snmplib/transports/snmpUDPIPv6Domain.c index 1f8c3765f21d..083edf099253 100644 --- a/snmplib/transports/snmpUDPIPv6Domain.c +++ b/snmplib/transports/snmpUDPIPv6Domain.c @@ -312,15 +312,24 @@ netsnmp_udp6_transport_bind(netsnmp_transport *t, t->sock, str)); free(str); } + rc = netsnmp_bindtodevice(t->sock, ep->iface); + if (rc != 0) { + DEBUGMSGTL(("netsnmp_udp6", "failed to bind to iface %s: %s\n", + ep->iface, strerror(errno))); + goto err; + } rc = bind(t->sock, (const struct sockaddr *)addr, sizeof(*addr)); if (rc != 0) { DEBUGMSGTL(("netsnmp_udp6", "failed to bind for clientaddr: %d %s\n", errno, strerror(errno))); - netsnmp_socketbase_close(t); - return -1; + goto err; } return 0; + +err: + netsnmp_socketbase_close(t); + return -1; } int -- 2.19.1 _______________________________________________ Net-snmp-coders mailing list Net-snmp-coders@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/net-snmp-coders