diff --git a/include/uv.h b/include/uv.h index 6a385583..c281ed4d 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1526,6 +1526,7 @@ struct uv_cpu_info_s { struct uv_interface_address_s { char* name; + char phys_addr[6]; int is_internal; union { struct sockaddr_in address4; diff --git a/src/unix/darwin.c b/src/unix/darwin.c index e716cfb3..81570f39 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -27,6 +27,7 @@ #include #include +#include #include @@ -355,6 +356,8 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; if (getifaddrs(&addrs)) return -errno; @@ -363,7 +366,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == AF_LINK)) { continue; @@ -379,21 +382,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) continue; - } - if (ent->ifa_addr == NULL) { + 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) { + if (ent->ifa_addr->sa_family == AF_LINK) continue; - } address->name = strdup(ent->ifa_name); @@ -409,11 +409,30 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); } - address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0; + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); address++; } + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + freeifaddrs(addrs); return 0; diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index afdc4095..b1e8eb7d 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -25,6 +25,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -322,13 +326,98 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - /* TODO: implement */ - *addresses = NULL; - *count = 0; + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On FreeBSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + 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); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + return 0; } void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); } diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 8365ea86..fa5dec19 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -47,6 +47,9 @@ #endif #ifdef HAVE_IFADDRS_H # include +# include +# include +# include #endif #undef NANOSEC @@ -624,8 +627,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, return -ENOSYS; #else struct ifaddrs *addrs, *ent; - char ip[INET6_ADDRSTRLEN]; uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; if (getifaddrs(&addrs)) return -errno; @@ -634,7 +638,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == PF_PACKET)) { continue; @@ -650,22 +654,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - bzero(&ip, sizeof (ip)); - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) continue; - } - if (ent->ifa_addr == NULL) { + if (ent->ifa_addr == NULL) continue; - } /* * On Linux getifaddrs returns information related to the raw underlying - * devices. We're not interested in this information. + * devices. We're not interested in this information yet. */ - if (ent->ifa_addr->sa_family == PF_PACKET) { + if (ent->ifa_addr->sa_family == PF_PACKET) continue; - } address->name = strdup(ent->ifa_name); @@ -681,11 +681,30 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); } - address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0; + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); address++; } + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_PACKET)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sll = (struct sockaddr_ll*)ent->ifa_addr; + memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); + } + address++; + } + } + freeifaddrs(addrs); return 0; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 8c7197eb..0722a6bf 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -274,9 +275,10 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs; - struct ifaddrs *ent; + struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; if (getifaddrs(&addrs)) return -errno; @@ -285,7 +287,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family != PF_INET)) { continue; @@ -301,17 +303,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) continue; - } - if (ent->ifa_addr == NULL) { + if (ent->ifa_addr == NULL) continue; - } - if (ent->ifa_addr->sa_family != PF_INET) { + if (ent->ifa_addr->sa_family != PF_INET) continue; - } address->name = strdup(ent->ifa_name); @@ -327,11 +326,30 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); } - address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK) ? 1 : 0; + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); address++; } + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + freeifaddrs(addrs); return 0; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 5f112e34..30f6fbdc 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -28,6 +28,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -291,13 +295,94 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - /* TODO: implement */ - *addresses = NULL; - *count = 0; + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs) != 0) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + 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); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + return 0; } void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); } diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 829f0723..8df65b70 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -32,6 +32,7 @@ # include #endif #include +#include #include #include @@ -580,7 +581,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return -ENOSYS; #else struct ifaddrs *addrs, *ent; - char ip[INET6_ADDRSTRLEN]; uv_interface_address_t* address; if (getifaddrs(&addrs)) @@ -590,7 +590,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == PF_PACKET)) { continue; @@ -606,15 +606,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - memset(&ip, 0, sizeof(ip)); - - if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) continue; - } - if (ent->ifa_addr == NULL) { + if (ent->ifa_addr == NULL) continue; - } address->name = strdup(ent->ifa_name); @@ -630,12 +626,31 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); } - address->is_internal = ent->ifa_flags & IFF_PRIVATE || ent->ifa_flags & - IFF_LOOPBACK ? 1 : 0; + address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || + (ent->ifa_flags & IFF_LOOPBACK)); address++; } + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + freeifaddrs(addrs); return 0; diff --git a/src/win/util.c b/src/win/util.c index fe373ff0..a8183438 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -940,6 +940,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, memset(uv_address, 0, sizeof *uv_address); uv_address->name = name_buf; + + if (win_address->PhysicalAddressLength == sizeof(uv_address->phys_addr)) { + memcpy(uv_address->phys_addr, + win_address->PhysicalAddress, + sizeof(uv_address->phys_addr)); + } + uv_address->is_internal = (win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 4e029e4f..d2104f40 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -72,6 +72,14 @@ TEST_IMPL(platform_output) { for (i = 0; i < count; i++) { printf(" name: %s\n", interfaces[i].name); printf(" internal: %d\n", interfaces[i].is_internal); + printf(" physical address: "); + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + (unsigned char)interfaces[i].phys_addr[0], + (unsigned char)interfaces[i].phys_addr[1], + (unsigned char)interfaces[i].phys_addr[2], + (unsigned char)interfaces[i].phys_addr[3], + (unsigned char)interfaces[i].phys_addr[4], + (unsigned char)interfaces[i].phys_addr[5]); if (interfaces[i].address.address4.sin_family == AF_INET) { uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer));