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
