On 10 August 2011 14:29, Steven McCoy <[email protected]> wrote:

> On 8 August 2011 18:47, Martin Sustrik <[email protected]> wrote:
>
>> Hi Steven,
>>
>> I guess there may be a problem here:
>>
>>    for (ifaddrs *ifp = ifa; ifp != NULL ;ifp = ifp->ifa_next)
>>    {
>>        if (ifp->ifa_addr == NULL)
>>            continue;
>>
>>        int family = ifp->ifa_addr->sa_family;
>>
>>        if ((family == AF_INET
>>             || (!ipv4only_ && family == AF_INET6))
>>            && !strcmp (interface_, ifp->ifa_name))
>>        {
>>            memcpy (addr_, ifp->ifa_addr,
>>                    (family == AF_INET) ? sizeof (struct sockaddr_in)
>>                                        : sizeof (struct sockaddr_in6));
>>            found = true;
>>            break;
>>        }
>>    }
>>
>> Specifically, if you have both IPv4 and IPv6 interface with the same name
>> and ipv4only is false, it depends on ordering of the results in getifaddrs()
>> resultset which of those two is returned.
>>
>> I would suppose in such case IPv6 address should be returned.
>>
>>
>  I think I would prefer if the entire adapter was used in bind ("eth0"),
> therefore a return value of in6addr_any with the sin6_scope_id set
> appropriately would be more sound.
>


Modified patch #2 attached to implement this.

-- 
Steve-o
From a576bf9520e56e193086b93205e40bce9540f29f Mon Sep 17 00:00:00 2001
From: Steven McCoy <[email protected]>
Date: Wed, 10 Aug 2011 14:44:30 +0800
Subject: [PATCH] Update resolve_nic_name to take more generic sockaddr parameter.  Return in6addr_any for full adapter.


Signed-off-by: Steven McCoy <[email protected]>
---
 src/ip.cpp |   99 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 75 insertions(+), 24 deletions(-)

diff --git a/src/ip.cpp b/src/ip.cpp
index a4f9562..e3f86e0 100644
--- a/src/ip.cpp
+++ b/src/ip.cpp
@@ -35,15 +35,19 @@
 #include <unistd.h>
 
 //  On Solaris platform, network interface name can be queried by ioctl.
-static int resolve_nic_name (in_addr* addr_, char const *interface_)
+static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,
+    bool ipv4only_)
 {
+    //  Unused parameter, IPv6 support not implemented for Solaris.
+    (void)ipv4only;
+
     //  Create a socket.
     int fd = socket (AF_INET, SOCK_DGRAM, 0);
     zmq_assert (fd != -1);
 
     //  Retrieve number of interfaces.
     lifnum ifn;
-    ifn.lifn_family = AF_UNSPEC;
+    ifn.lifn_family = AF_INET;
     ifn.lifn_flags = 0;
     int rc = ioctl (fd, SIOCGLIFNUM, (char*) &ifn);
     zmq_assert (rc != -1);
@@ -55,7 +59,7 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
     
     //  Retrieve interface names.
     lifconf ifc;
-    ifc.lifc_family = AF_UNSPEC;
+    ifc.lifc_family = AF_INET;
     ifc.lifc_flags = 0;
     ifc.lifc_len = ifr_size;
     ifc.lifc_buf = ifr;
@@ -97,8 +101,12 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
 #include <sys/ioctl.h>
 #include <net/if.h>
 
-static int resolve_nic_name (in_addr* addr_, char const *interface_)
+static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,
+    bool ipv4only_)
 {
+    //  Unused parameter, IPv6 support not implemented for AIX or HP/UX.
+    (void)ipv4only;
+
     //  Create a socket.
     int sd = socket (AF_INET, SOCK_DGRAM, 0);
     zmq_assert (sd != -1);
@@ -133,7 +141,8 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
 
 //  On these platforms, network interface name can be queried
 //  using getifaddrs function.
-static int resolve_nic_name (in_addr* addr_, char const *interface_)
+static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,
+    bool ipv4only_)
 {
     //  Get the addresses.
     ifaddrs* ifa = NULL;
@@ -142,15 +151,35 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
     zmq_assert (ifa != NULL);
 
     //  Find the corresponding network interface.
-    bool found = false;
+    int found = 0;
+    uint32_t sin6_scope_id = 0;
     for (ifaddrs *ifp = ifa; ifp != NULL ;ifp = ifp->ifa_next)
-        if (ifp->ifa_addr && ifp->ifa_addr->sa_family == AF_INET 
-            && !strcmp (interface_, ifp->ifa_name)) 
+    {
+        if (ifp->ifa_addr == NULL)
+            continue;
+
+        int family = ifp->ifa_addr->sa_family;
+
+        if ((family == AF_INET
+             || (!ipv4only_ && family == AF_INET6))
+            && !strcmp (interface_, ifp->ifa_name))
         {
-            *addr_ = ((sockaddr_in*) ifp->ifa_addr)->sin_addr;
-            found = true;
-            break;
+            found++;
+            //  Duplicate interfaces only occur on IPv6 enabled adapters.
+            if (ipv4only_) {
+                memcpy (addr_, ifp->ifa_addr,
+                        (family == AF_INET) ? sizeof (struct sockaddr_in)
+                                            : sizeof (struct sockaddr_in6));
+                break;
+            }
+            //  Save scope identifier for adapter.
+            if (family == AF_INET6) {
+                sockaddr_in6 sin6;
+                memcpy (&sin6, ifp->ifa_addr, sizeof (sin6));
+                sin6_scope_id = sin6.sin6_scope_id;
+            }
         }
+    }
 
     //  Clean-up;
     freeifaddrs (ifa);
@@ -160,6 +189,16 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
         return -1;
     }
 
+    //  Multiple matching interfaces, therefore return entire adapter.
+    if (found > 1) {
+        sockaddr_in6 sin6;
+        memset (&sin6, 0, sizeof (sin6));
+        sin6.sin6_family = AF_INET6;
+        memcpy (&sin6.sin6_addr, in6addr_any, sizeof (in6addr_any));
+        sin6.sin6_scope_id = sin6_scope_id;
+        memcpy (addr_, &sin6, sizeof (sin6));
+    }
+
     return 0;
 }
 
@@ -167,8 +206,14 @@ static int resolve_nic_name (in_addr* addr_, char const *interface_)
 
 //  On other platforms we assume there are no sane interface names.
 //  This is true especially of Windows.
-static int resolve_nic_name (in_addr* addr_, char const *interface_)
+static int resolve_nic_name (struct sockaddr* addr_, char const *interface_,
+    bool ipv4only_)
 {
+    //  All unused parameters.
+    (void)addr_;
+    (void)interface_;
+    (void)ipv4only_;
+
     errno = ENODEV;
     return -1;
 }
@@ -189,28 +234,34 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
     std::string iface (interface_, delimiter - interface_);
     std::string service (delimiter + 1);
 
+    //  0 is not a valid port.
+    uint16_t sin_port = htons ((uint16_t) atoi (service.c_str()));
+    if (!sin_port) {
+        errno = EINVAL;
+        return -1;
+    }
+
     //  Initialize the output parameter.
     memset (addr_, 0, sizeof (*addr_));
 
+    //  Initialize temporary output pointers with storage address.
+    sockaddr_storage ss;
+    sockaddr *out_addr = (sockaddr *) &ss;
+    socklen_t out_addrlen;
+
     //  Initialise IPv4-format family/port.
     sockaddr_in ip4_addr;
     memset (&ip4_addr, 0, sizeof (ip4_addr));
     ip4_addr.sin_family = AF_INET;
-    ip4_addr.sin_port = htons ((uint16_t) atoi (service.c_str()));
-
-    //  Initialize temporary output pointers with ip4_addr
-    sockaddr *out_addr = (sockaddr *) &ip4_addr;
-    socklen_t out_addrlen = (socklen_t) sizeof (ip4_addr);
+    ip4_addr.sin_port = sin_port;
+    ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
 
-    //  0 is not a valid port.
-    if (!ip4_addr.sin_port) {
-        errno = EINVAL;
-        return -1;
-    }
+    //  Populate temporary output pointers with ip4_addr.
+    out_addrlen = (socklen_t) sizeof (ip4_addr);
+    memcpy (out_addr, &ip4_addr, out_addrlen);
 
     //  * resolves to INADDR_ANY.
     if (iface.compare("*") == 0) {
-        ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
         zmq_assert (out_addrlen <= (socklen_t) sizeof (*addr_));
         memcpy (addr_, out_addr, out_addrlen);
         *addr_len_ = out_addrlen;
@@ -218,7 +269,7 @@ int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
     }
 
     //  Try to resolve the string as a NIC name.
-    int rc = resolve_nic_name (&ip4_addr.sin_addr, iface.c_str());
+    int rc = resolve_nic_name (out_addr, iface.c_str(), true);
     if (rc != 0 && errno != ENODEV)
         return rc;
     if (rc == 0) {
-- 
1.7.4.1

_______________________________________________
zeromq-dev mailing list
[email protected]
http://lists.zeromq.org/mailman/listinfo/zeromq-dev

Reply via email to