Example #1
0
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;
}
Example #2
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;
}
Example #3
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;
}