1 /* Copyright libuv project contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "internal.h" 24 25 #include <errno.h> 26 #include <stddef.h> 27 28 #include <ifaddrs.h> 29 #include <net/if.h> 30 #if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__) 31 #include <net/if_dl.h> 32 #endif 33 34 #if defined(__HAIKU__) 35 #define IFF_RUNNING IFF_LINK 36 #endif 37 38 static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { 39 if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) 40 return 1; 41 if (ent->ifa_addr == NULL) 42 return 1; 43 #if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__) 44 /* 45 * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family` 46 * equals `AF_LINK`. Otherwise, the result depends on the operating 47 * system with `AF_LINK` or `PF_INET`. 48 */ 49 if (exclude_type == UV__EXCLUDE_IFPHYS) 50 return (ent->ifa_addr->sa_family != AF_LINK); 51 #endif 52 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \ 53 defined(__HAIKU__) 54 /* 55 * On BSD getifaddrs returns information related to the raw underlying 56 * devices. We're not interested in this information. 57 */ 58 if (ent->ifa_addr->sa_family == AF_LINK) 59 return 1; 60 #elif defined(__NetBSD__) || defined(__OpenBSD__) 61 if (ent->ifa_addr->sa_family != PF_INET && 62 ent->ifa_addr->sa_family != PF_INET6) 63 return 1; 64 #endif 65 return 0; 66 } 67 68 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { 69 struct ifaddrs* addrs; 70 struct ifaddrs* ent; 71 uv_interface_address_t* address; 72 #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) 73 int i; 74 #endif 75 76 *count = 0; 77 *addresses = NULL; 78 79 if (getifaddrs(&addrs) != 0) 80 return UV__ERR(errno); 81 82 /* Count the number of interfaces */ 83 for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 84 if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) 85 continue; 86 (*count)++; 87 } 88 89 if (*count == 0) { 90 freeifaddrs(addrs); 91 return 0; 92 } 93 94 /* Make sure the memory is initiallized to zero using calloc() */ 95 *addresses = uv__calloc(*count, sizeof(**addresses)); 96 97 if (*addresses == NULL) { 98 freeifaddrs(addrs); 99 return UV_ENOMEM; 100 } 101 102 address = *addresses; 103 104 for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 105 if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) 106 continue; 107 108 address->name = uv__strdup(ent->ifa_name); 109 110 if (ent->ifa_addr->sa_family == AF_INET6) { 111 address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); 112 } else { 113 address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); 114 } 115 116 if (ent->ifa_netmask == NULL) { 117 memset(&address->netmask, 0, sizeof(address->netmask)); 118 } else if (ent->ifa_netmask->sa_family == AF_INET6) { 119 address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); 120 } else { 121 address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); 122 } 123 124 address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); 125 126 address++; 127 } 128 129 #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) 130 /* Fill in physical addresses for each interface */ 131 for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 132 if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) 133 continue; 134 135 address = *addresses; 136 137 for (i = 0; i < *count; i++) { 138 if (strcmp(address->name, ent->ifa_name) == 0) { 139 struct sockaddr_dl* sa_addr; 140 sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); 141 memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); 142 } 143 address++; 144 } 145 } 146 #endif 147 148 freeifaddrs(addrs); 149 150 return 0; 151 } 152 153 154 void uv_free_interface_addresses(uv_interface_address_t* addresses, 155 int count) { 156 int i; 157 158 for (i = 0; i < count; i++) { 159 uv__free(addresses[i].name); 160 } 161 162 uv__free(addresses); 163 } 164