---
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders