int nn_iface_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { int rc; int s; struct ifreq req; /* Asterisk is a special name meaning "all interfaces". */ if (addrlen == 1 && addr [0] == '*') { nn_iface_any (ipv4only, result, resultlen); return 0; } /* Open the helper socket. */ #ifdef SOCK_CLOEXEC s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); #else s = socket (AF_INET, SOCK_DGRAM, 0); #endif errno_assert (s != -1); /* Create the interface name resolution request. */ if (sizeof (req.ifr_name) <= addrlen) { nn_closefd (s); return -ENODEV; } memcpy (req.ifr_name, addr, addrlen); req.ifr_name [addrlen] = 0; /* Execute the request. */ rc = ioctl (s, SIOCGIFADDR, (caddr_t) &req, sizeof (struct ifreq)); if (rc == -1) { nn_closefd (s); return -ENODEV; } /* Interface name resolution succeeded. Return the address to the user. */ /* TODO: What about IPv6 addresses? */ nn_assert (req.ifr_addr.sa_family == AF_INET); if (result) memcpy (result, (struct sockaddr_in*) &req.ifr_addr, sizeof (struct sockaddr_in)); if (resultlen) *resultlen = sizeof (struct sockaddr_in); nn_closefd (s); return 0; }
/* The last resort case. If we haven't found any mechanism for turning NIC names into addresses, we'll try to resolve the string as an address literal. */ int nn_iface_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { int rc; /* Asterisk is a special name meaning "all interfaces". */ if (addrlen == 1 && addr [0] == '*') { nn_iface_any (ipv4only, result, resultlen); return 0; } /* On Windows there are no sane network interface names. We'll treat the name as a IP address literal. */ rc = nn_literal_resolve (addr, addrlen, ipv4only, result, resultlen); if (rc == -EINVAL) return -ENODEV; errnum_assert (rc == 0, -rc); return 0; }
int nn_iface_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { int rc; struct ifaddrs *ifaces; struct ifaddrs *it; struct ifaddrs *ipv4; struct ifaddrs *ipv6; size_t ifalen; /* Asterisk is a special name meaning "all interfaces". */ if (addrlen == 1 && addr [0] == '*') { nn_iface_any (ipv4only, result, resultlen); return 0; } /* Try to resolve the supplied string as a literal address. */ rc = nn_literal_resolve (addr, addrlen, ipv4only, result, resultlen); if (rc == 0) return 0; errnum_assert (rc == -EINVAL, -rc); /* Get the list of local network interfaces from the system. */ ifaces = NULL; rc = getifaddrs (&ifaces); errno_assert (rc == 0); nn_assert (ifaces); /* Find the NIC with the specified name. */ ipv4 = NULL; ipv6 = NULL; for (it = ifaces; it != NULL; it = it->ifa_next) { if (!it->ifa_addr) continue; ifalen = strlen (it->ifa_name); if (ifalen != addrlen || memcmp (it->ifa_name, addr, addrlen) != 0) continue; switch (it->ifa_addr->sa_family) { case AF_INET: nn_assert (!ipv4); ipv4 = it; break; case AF_INET6: nn_assert (!ipv6); ipv6 = it; break; } } /* IPv6 address is preferable. */ if (ipv6 && !ipv4only) { if (result) { result->ss_family = AF_INET6; memcpy (result, ipv6->ifa_addr, sizeof (struct sockaddr_in6)); } if (resultlen) *resultlen = sizeof (struct sockaddr_in6); freeifaddrs (ifaces); return 0; } /* Use IPv4 address. */ if (ipv4) { if (result) { result->ss_family = AF_INET; memcpy (result, ipv4->ifa_addr, sizeof (struct sockaddr_in)); } if (resultlen) *resultlen = sizeof (struct sockaddr_in); freeifaddrs (ifaces); return 0; } /* There's no such interface. */ freeifaddrs (ifaces); return -ENODEV; }