Skip to content

Commit

Permalink
unix, win: add netmask to uv_interface_address
Browse files Browse the repository at this point in the history
Include the netmask when returning information about the OS network
interfaces.

This commit provides implementations for windows and those unix platforms
using getifaddrs().

AIX was not implemented because it requires the use ioctls and I do not
have an AIX development/test environment.  The windows code was developed
using mingw on winxp as I do not have access to visual studio.

Tested on darwin (ipv4/ipv6) and winxp (ipv4 only).  Needs testing on
newer windows using ipv6 and other unix platforms.
  • Loading branch information
wanderview committed Feb 10, 2013
1 parent c15d4a7 commit d681546
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 3 deletions.
4 changes: 4 additions & 0 deletions include/uv.h
Expand Up @@ -1437,6 +1437,10 @@ struct uv_interface_address_s {
struct sockaddr_in address4;
struct sockaddr_in6 address6;
} address;
union {
struct sockaddr_in netmask4;
struct sockaddr_in6 netmask6;
} netmask;
};

UV_EXTERN char** uv_setup_args(int argc, char** argv);
Expand Down
2 changes: 2 additions & 0 deletions src/unix/aix.c
Expand Up @@ -369,6 +369,8 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
address->address.address4 = *((struct sockaddr_in *)&p->ifr_addr);
}

/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */

address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;

address++;
Expand Down
6 changes: 6 additions & 0 deletions src/unix/darwin.c
Expand Up @@ -435,6 +435,12 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
}

if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6 *)ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in *)ent->ifa_netmask);
}

address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0;

address++;
Expand Down
6 changes: 6 additions & 0 deletions src/unix/linux-core.c
Expand Up @@ -770,6 +770,12 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
}

if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6 *)ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in *)ent->ifa_netmask);
}

address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0;

address++;
Expand Down
6 changes: 6 additions & 0 deletions src/unix/netbsd.c
Expand Up @@ -331,6 +331,12 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count)
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
}

if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6 *)ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in *)ent->ifa_netmask);
}

address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK) ? 1 : 0;

address++;
Expand Down
6 changes: 6 additions & 0 deletions src/unix/sunos.c
Expand Up @@ -622,6 +622,12 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
}

if (ent->ifa_netmask->sa_family == AF_INET6) {
address->netmask.netmask6 = *((struct sockaddr_in6 *)ent->ifa_netmask);
} else {
address->netmask.netmask4 = *((struct sockaddr_in *)ent->ifa_netmask);
}

address->is_internal = ent->ifa_flags & IFF_PRIVATE || ent->ifa_flags &
IFF_LOOPBACK ? 1 : 0;

Expand Down
42 changes: 39 additions & 3 deletions src/win/util.c
Expand Up @@ -31,6 +31,7 @@
#include "uv.h"
#include "internal.h"

#include <Winsock2.h>
#include <iphlpapi.h>
#include <psapi.h>
#include <tlhelp32.h>
Expand Down Expand Up @@ -765,7 +766,7 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr,
/* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
/* win_address_buf_size. */
r = GetAdaptersAddresses(AF_UNSPEC,
0,
GAA_FLAG_INCLUDE_PREFIX,
NULL,
win_address_buf,
&win_address_buf_size);
Expand Down Expand Up @@ -882,6 +883,7 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr,
win_address != NULL;
win_address = win_address->Next) {
IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address;
IP_ADAPTER_PREFIX* prefix;
int name_size;
size_t max_name_size;

Expand All @@ -907,21 +909,55 @@ uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr,
return uv__new_sys_error(GetLastError());
}

prefix = win_address->FirstPrefix;

/* Add an uv_interface_address_t element for every unicast address. */
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
win_address->FirstUnicastAddress;
unicast_address != NULL;
unicast_address = unicast_address->Next) {
struct sockaddr* sa;
int prefixlen;

uv_address->name = name_buf;

/* Walk the prefix list in sync with the address list and extract
the prefixlen for each address. On Vista and newer, we could
instead just use: unicast_address->OnLinkPrefixLength */
if (prefix != NULL) {
prefixlen = prefix->PrefixLength;
prefix = prefix->Next;
} else {
prefixlen = 0;
}

sa = unicast_address->Address.lpSockaddr;
if (sa->sa_family == AF_INET6)
if (sa->sa_family == AF_INET6) {
int i;

uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
else

uv_address->netmask.netmask6.sin6_family = AF_INET6;
prefixlen = prefixlen > 0 ? prefixlen : 128;
for (i = 0; i < 16; ++i) {
int bits;
uint8_t byte_val;

bits = prefixlen < 8 ? prefixlen : 8;
byte_val = ~(0xff >> bits);
prefixlen -= bits;

uv_address->netmask.netmask6.sin6_addr.s6_addr[i] = byte_val;
}
} else {
uv_address->address.address4 = *((struct sockaddr_in *) sa);

uv_address->netmask.netmask4.sin_family = AF_INET;
prefixlen = prefixlen > 0 ? prefixlen : 32;
uv_address->netmask.netmask4.sin_addr.s_addr =
htonl(0xffffffff << (32 - prefixlen));
}

uv_address->is_internal =
(win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK);

Expand Down
8 changes: 8 additions & 0 deletions test/test-platform-output.c
Expand Up @@ -80,6 +80,14 @@ TEST_IMPL(platform_output) {
}

printf(" address: %s\n", buffer);

if (interfaces[i].netmask.netmask4.sin_family == AF_INET) {
uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer));
} else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) {
uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer));
}

printf(" netmask: %s\n", buffer);
}
uv_free_interface_addresses(interfaces, count);

Expand Down

0 comments on commit d681546

Please sign in to comment.