---
 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

Reply via email to