diff --git a/doc/api/os.markdown b/doc/api/os.markdown index d867047ae9..eff85200dd 100644 --- a/doc/api/os.markdown +++ b/doc/api/os.markdown @@ -113,9 +113,15 @@ Example inspection of os.cpus: Get a list of network interfaces: - { lo: { ip: '127.0.0.1', internal: true, ip6: '::1' }, - eth0: { ip6: 'fe80::f2de:f1ff:fe19:ae7', internal: false }, - wlan0: { ip: '10.0.1.118', internal: false, ip6: 'fe80::226:c7ff:fe7d:1602' }, - vboxnet0: {} } - + { lo0: + [ { address: '::1', family: 'IPv6', internal: true }, + { address: 'fe80::1', family: 'IPv6', internal: true }, + { 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 } ] } diff --git a/src/platform_darwin.cc b/src/platform_darwin.cc index 8cd38af4a0..deaf629c42 100644 --- a/src/platform_darwin.cc +++ b/src/platform_darwin.cc @@ -34,6 +34,13 @@ #include #include #include +#include +#include +#include +#include +#include + + namespace node { @@ -212,7 +219,71 @@ int Platform::GetLoadAvg(Local *loads) { v8::Handle Platform::GetInterfaceAddresses() { HandleScope scope; - return scope.Close(Object::New()); + struct ::ifaddrs *addrs, *ent; + struct ::sockaddr_in *in4; + struct ::sockaddr_in6 *in6; + char ip[INET6_ADDRSTRLEN]; + Local ret, o; + Local name, ipaddr, family; + Local 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::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, "", INET6_ADDRSTRLEN); + family = String::New(""); + } + + 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 diff --git a/src/platform_linux.cc b/src/platform_linux.cc index 00b9c8649c..54937b487a 100644 --- a/src/platform_linux.cc +++ b/src/platform_linux.cc @@ -313,63 +313,71 @@ bool IsInternal(struct ifaddrs* addr) { Handle Platform::GetInterfaceAddresses() { HandleScope scope; - - struct ::ifaddrs *addrs; - - int r = getifaddrs(&addrs); - - if (r != 0) { + struct ::ifaddrs *addrs, *ent; + struct ::sockaddr_in *in4; + struct ::sockaddr_in6 *in6; + char ip[INET6_ADDRSTRLEN]; + Local ret, o; + Local name, ipaddr, family; + Local ifarr; + + if (getifaddrs(&addrs) != 0) { return ThrowException(ErrnoException(errno, "getifaddrs")); } - struct ::ifaddrs *addr; + ret = Object::New(); - Local 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; - addr; - addr = addr->ifa_next) { - Local name = String::New(addr->ifa_name); - Local info; + if (ent->ifa_addr == NULL) { + continue; + } - 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::Cast(ret->Get(name)); } else { - info = Object::New(); - a->Set(name, info); + ifarr = Array::New(); + ret->Set(name, ifarr); } - struct sockaddr *address = addr->ifa_addr; - char ip[INET6_ADDRSTRLEN]; - - switch (address->sa_family) { - case AF_INET6: { - struct sockaddr_in6 *a6 = (struct sockaddr_in6*)address; - inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); - info->Set(String::New("ip6"), String::New(ip)); - if (addr->ifa_flags) { - info->Set(String::New("internal"), - IsInternal(addr) ? True() : False()); - } - break; - } - - case AF_INET: { - struct sockaddr_in *a4 = (struct sockaddr_in*)address; - inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); - info->Set(String::New("ip"), String::New(ip)); - if (addr->ifa_flags) { - info->Set(String::New("internal"), - IsInternal(addr) ? True() : False()); - } - break; - } + 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) strncpy(ip, "", INET6_ADDRSTRLEN); + family = String::New(""); } + + 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(a); + return scope.Close(ret); } diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index 1db98b7710..3011c3e2bb 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -32,6 +32,13 @@ #include #include #include +#include +#include +#include +#include +#include + + #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #define PROCFS_FILE_OFFSET_BITS_HACK 1 @@ -265,7 +272,64 @@ int Platform::GetLoadAvg(Local *loads) { Handle Platform::GetInterfaceAddresses() { HandleScope scope; - return scope.Close(Object::New()); + struct ::ifaddrs *addrs, *ent; + struct ::sockaddr_in *in4; + struct ::sockaddr_in6 *in6; + char ip[INET6_ADDRSTRLEN]; + Local ret, o; + Local name, ipaddr, family; + Local 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::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, "", INET6_ADDRSTRLEN); + family = String::New(""); + } + + 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); }