Rework getNetworkInterfaces() for Linux, SunOS, Mac OS X

This commit is contained in:
Robert Mustacchi 2011-05-19 18:32:05 -07:00 committed by Ryan Dahl
parent 73ea01cd64
commit 317653b4df
4 changed files with 198 additions and 49 deletions

View File

@ -113,9 +113,15 @@ Example inspection of os.cpus:
Get a list of network interfaces: Get a list of network interfaces:
{ lo: { ip: '127.0.0.1', internal: true, ip6: '::1' }, { lo0:
eth0: { ip6: 'fe80::f2de:f1ff:fe19:ae7', internal: false }, [ { address: '::1', family: 'IPv6', internal: true },
wlan0: { ip: '10.0.1.118', internal: false, ip6: 'fe80::226:c7ff:fe7d:1602' }, { address: 'fe80::1', family: 'IPv6', internal: true },
vboxnet0: {} } { address: '127.0.0.1', family: 'IPv4', internal: true } ],
en1:
[ { address: 'fe80::cabc:c8ff:feef:f996', family: 'IPv6',
internal: false },
{ address: '10.0.1.123', family: 'IPv4', internal: false } ],
vmnet1: [ { address: '10.99.99.254', family: 'IPv4', internal: false } ],
vmnet8: [ { address: '10.88.88.1', family: 'IPv4', internal: false } ],
ppp0: [ { address: '10.2.0.231', family: 'IPv4', internal: false } ] }

View File

@ -34,6 +34,13 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <time.h> #include <time.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
namespace node { namespace node {
@ -212,7 +219,71 @@ int Platform::GetLoadAvg(Local<Array> *loads) {
v8::Handle<v8::Value> Platform::GetInterfaceAddresses() { v8::Handle<v8::Value> Platform::GetInterfaceAddresses() {
HandleScope scope; HandleScope scope;
return scope.Close(Object::New()); struct ::ifaddrs *addrs, *ent;
struct ::sockaddr_in *in4;
struct ::sockaddr_in6 *in6;
char ip[INET6_ADDRSTRLEN];
Local<Object> ret, o;
Local<String> name, ipaddr, family;
Local<Array> ifarr;
if (getifaddrs(&addrs) != 0) {
return ThrowException(ErrnoException(errno, "getifaddrs"));
}
ret = Object::New();
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
bzero(&ip, sizeof (ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
continue;
}
if (ent->ifa_addr == NULL) {
continue;
}
/*
* On Mac OS X getifaddrs returns information related to Mac Addresses for
* various devices, such as firewire, etc. These are not relevant here.
*/
if (ent->ifa_addr->sa_family == AF_LINK)
continue;
name = String::New(ent->ifa_name);
if (ret->Has(name)) {
ifarr = Local<Array>::Cast(ret->Get(name));
} else {
ifarr = Array::New();
ret->Set(name, ifarr);
}
if (ent->ifa_addr->sa_family == AF_INET6) {
in6 = (struct sockaddr_in6 *)ent->ifa_addr;
inet_ntop(AF_INET6, &(in6->sin6_addr), ip, INET6_ADDRSTRLEN);
family = String::New("IPv6");
} else if (ent->ifa_addr->sa_family == AF_INET) {
in4 = (struct sockaddr_in *)ent->ifa_addr;
inet_ntop(AF_INET, &(in4->sin_addr), ip, INET6_ADDRSTRLEN);
family = String::New("IPv4");
} else {
(void) strlcpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
family = String::New("<unknown>");
}
o = Object::New();
o->Set(String::New("address"), String::New(ip));
o->Set(String::New("family"), family);
o->Set(String::New("internal"), ent->ifa_flags & IFF_LOOPBACK ?
True() : False());
ifarr->Set(ifarr->Length(), o);
}
freeifaddrs(addrs);
return scope.Close(ret);
} }
} // namespace node } // namespace node

View File

@ -313,63 +313,71 @@ bool IsInternal(struct ifaddrs* addr) {
Handle<Value> Platform::GetInterfaceAddresses() { Handle<Value> Platform::GetInterfaceAddresses() {
HandleScope scope; HandleScope scope;
struct ::ifaddrs *addrs, *ent;
struct ::sockaddr_in *in4;
struct ::sockaddr_in6 *in6;
char ip[INET6_ADDRSTRLEN];
Local<Object> ret, o;
Local<String> name, ipaddr, family;
Local<Array> ifarr;
struct ::ifaddrs *addrs; if (getifaddrs(&addrs) != 0) {
int r = getifaddrs(&addrs);
if (r != 0) {
return ThrowException(ErrnoException(errno, "getifaddrs")); return ThrowException(ErrnoException(errno, "getifaddrs"));
} }
struct ::ifaddrs *addr; ret = Object::New();
Local<Object> a = Object::New(); for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
bzero(&ip, sizeof (ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
continue;
}
for (addr = addrs; if (ent->ifa_addr == NULL) {
addr; continue;
addr = addr->ifa_next) { }
Local<String> name = String::New(addr->ifa_name);
Local<Object> info;
if (a->Has(name)) { /*
info = a->Get(name)->ToObject(); * On Linux getifaddrs returns information related to the raw underlying
* devices. We're not interested in this information.
*/
if (ent->ifa_addr->sa_family == PF_PACKET)
continue;
name = String::New(ent->ifa_name);
if (ret->Has(name)) {
ifarr = Local<Array>::Cast(ret->Get(name));
} else { } else {
info = Object::New(); ifarr = Array::New();
a->Set(name, info); ret->Set(name, ifarr);
} }
struct sockaddr *address = addr->ifa_addr; if (ent->ifa_addr->sa_family == AF_INET6) {
char ip[INET6_ADDRSTRLEN]; in6 = (struct sockaddr_in6 *)ent->ifa_addr;
inet_ntop(AF_INET6, &(in6->sin6_addr), ip, INET6_ADDRSTRLEN);
switch (address->sa_family) { family = String::New("IPv6");
case AF_INET6: { } else if (ent->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in6 *a6 = (struct sockaddr_in6*)address; in4 = (struct sockaddr_in *)ent->ifa_addr;
inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); inet_ntop(AF_INET, &(in4->sin_addr), ip, INET6_ADDRSTRLEN);
info->Set(String::New("ip6"), String::New(ip)); family = String::New("IPv4");
if (addr->ifa_flags) { } else {
info->Set(String::New("internal"), (void) strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
IsInternal(addr) ? True() : False()); family = String::New("<unknown>");
}
break;
} }
case AF_INET: { o = Object::New();
struct sockaddr_in *a4 = (struct sockaddr_in*)address; o->Set(String::New("address"), String::New(ip));
inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); o->Set(String::New("family"), family);
info->Set(String::New("ip"), String::New(ip)); o->Set(String::New("internal"), ent->ifa_flags & IFF_LOOPBACK ?
if (addr->ifa_flags) { True() : False());
info->Set(String::New("internal"),
IsInternal(addr) ? True() : False()); ifarr->Set(ifarr->Length(), o);
}
break;
}
}
} }
freeifaddrs(addrs); freeifaddrs(addrs);
return scope.Close(a); return scope.Close(ret);
} }

View File

@ -32,6 +32,13 @@
#include <inttypes.h> #include <inttypes.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/loadavg.h> #include <sys/loadavg.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
#define PROCFS_FILE_OFFSET_BITS_HACK 1 #define PROCFS_FILE_OFFSET_BITS_HACK 1
@ -265,7 +272,64 @@ int Platform::GetLoadAvg(Local<Array> *loads) {
Handle<Value> Platform::GetInterfaceAddresses() { Handle<Value> Platform::GetInterfaceAddresses() {
HandleScope scope; HandleScope scope;
return scope.Close(Object::New()); struct ::ifaddrs *addrs, *ent;
struct ::sockaddr_in *in4;
struct ::sockaddr_in6 *in6;
char ip[INET6_ADDRSTRLEN];
Local<Object> ret, o;
Local<String> name, ipaddr, family;
Local<Array> ifarr;
if (getifaddrs(&addrs) != 0) {
return ThrowException(ErrnoException(errno, "getifaddrs"));
}
ret = Object::New();
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
bzero(&ip, sizeof (ip));
if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
continue;
}
if (ent->ifa_addr == NULL) {
continue;
}
name = String::New(ent->ifa_name);
if (ret->Has(name)) {
ifarr = Local<Array>::Cast(ret->Get(name));
} else {
ifarr = Array::New();
ret->Set(name, ifarr);
}
if (ent->ifa_addr->sa_family == AF_INET6) {
in6 = (struct sockaddr_in6 *)ent->ifa_addr;
inet_ntop(AF_INET6, &(in6->sin6_addr), ip, INET6_ADDRSTRLEN);
family = String::New("IPv6");
} else if (ent->ifa_addr->sa_family == AF_INET) {
in4 = (struct sockaddr_in *)ent->ifa_addr;
inet_ntop(AF_INET, &(in4->sin_addr), ip, INET6_ADDRSTRLEN);
family = String::New("IPv4");
} else {
(void) strlcpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
family = String::New("<unknown>");
}
o = Object::New();
o->Set(String::New("address"), String::New(ip));
o->Set(String::New("family"), family);
o->Set(String::New("internal"), ent->ifa_flags & IFF_PRIVATE || ent->ifa_flags &
IFF_LOOPBACK ? True() : False());
ifarr->Set(ifarr->Length(), o);
}
freeifaddrs(addrs);
return scope.Close(ret);
} }