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__)
31 #include <net/if_dl.h>
32 #endif
33
34 #if defined(__HAIKU__)
35 #define IFF_RUNNING IFF_LINK
36 #endif
37
uv__ifaddr_exclude(struct ifaddrs * ent,int exclude_type)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__)
44 /*
45 * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
46 * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
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
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)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__))
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->sa_family == AF_INET6) {
117 address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
118 } else {
119 address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
120 }
121
122 address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
123
124 address++;
125 }
126
127 #if !(defined(__CYGWIN__) || defined(__MSYS__))
128 /* Fill in physical addresses for each interface */
129 for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
130 if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
131 continue;
132
133 address = *addresses;
134
135 for (i = 0; i < *count; i++) {
136 if (strcmp(address->name, ent->ifa_name) == 0) {
137 struct sockaddr_dl* sa_addr;
138 sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
139 memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
140 }
141 address++;
142 }
143 }
144 #endif
145
146 freeifaddrs(addrs);
147
148 return 0;
149 }
150
151
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)152 void uv_free_interface_addresses(uv_interface_address_t* addresses,
153 int count) {
154 int i;
155
156 for (i = 0; i < count; i++) {
157 uv__free(addresses[i].name);
158 }
159
160 uv__free(addresses);
161 }
162