]>
Commit | Line | Data |
---|---|---|
cc6119a0 | 1 | #include <arpa/inet.h> |
4ba0d9af | 2 | #include <errno.h> |
cc6119a0 CB |
3 | #include <linux/if.h> |
4 | #include <linux/if_addr.h> | |
5 | #include <linux/if_link.h> | |
6 | #include <linux/if_packet.h> | |
4ba0d9af SG |
7 | #include <linux/netlink.h> |
8 | #include <linux/rtnetlink.h> | |
cc6119a0 CB |
9 | #include <linux/types.h> |
10 | #include <net/ethernet.h> | |
59e9eabe | 11 | #include <netinet/in.h> |
cc6119a0 CB |
12 | #include <stdbool.h> |
13 | #include <stdio.h> | |
59e9eabe CB |
14 | #include <stdlib.h> |
15 | #include <string.h> | |
16 | #include <sys/socket.h> | |
17 | #include <unistd.h> | |
4ba0d9af | 18 | |
a3aba110 | 19 | #include "config.h" |
cc6119a0 CB |
20 | #include "nl.h" |
21 | #include "macro.h" | |
22 | #include "netns_ifaddrs.h" | |
23 | ||
24 | #ifndef NETNS_RTA | |
25 | #define NETNS_RTA(r) \ | |
26 | ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg)))) | |
27 | #endif | |
4ba0d9af | 28 | |
59e9eabe | 29 | #define IFADDRS_HASH_SIZE 64 |
4ba0d9af | 30 | |
59e9eabe | 31 | #define __NETLINK_ALIGN(len) (((len) + 3) & ~3) |
4ba0d9af | 32 | |
59e9eabe | 33 | #define __NLMSG_OK(nlh, end) \ |
49bdee73 | 34 | ((size_t)((char *)(end) - (char *)(nlh)) >= sizeof(struct nlmsghdr)) |
4ba0d9af | 35 | |
59e9eabe CB |
36 | #define __NLMSG_NEXT(nlh) \ |
37 | (struct nlmsghdr *)((char *)(nlh) + __NETLINK_ALIGN((nlh)->nlmsg_len)) | |
4ba0d9af | 38 | |
59e9eabe | 39 | #define __NLMSG_DATA(nlh) ((void *)((char *)(nlh) + sizeof(struct nlmsghdr))) |
4ba0d9af | 40 | |
59e9eabe | 41 | #define __NLMSG_DATAEND(nlh) ((char *)(nlh) + (nlh)->nlmsg_len) |
4ba0d9af | 42 | |
59e9eabe CB |
43 | #define __NLMSG_RTA(nlh, len) \ |
44 | ((void *)((char *)(nlh) + sizeof(struct nlmsghdr) + \ | |
45 | __NETLINK_ALIGN(len))) | |
4ba0d9af | 46 | |
59e9eabe CB |
47 | #define __RTA_DATALEN(rta) ((rta)->rta_len - sizeof(struct rtattr)) |
48 | ||
49 | #define __RTA_NEXT(rta) \ | |
50 | (struct rtattr *)((char *)(rta) + __NETLINK_ALIGN((rta)->rta_len)) | |
51 | ||
52 | #define __RTA_OK(nlh, end) \ | |
49bdee73 | 53 | ((size_t)((char *)(end) - (char *)(rta)) >= sizeof(struct rtattr)) |
59e9eabe CB |
54 | |
55 | #define __NLMSG_RTAOK(rta, nlh) __RTA_OK(rta, __NLMSG_DATAEND(nlh)) | |
56 | ||
57 | #define __IN6_IS_ADDR_LINKLOCAL(a) \ | |
58 | ((((uint8_t *)(a))[0]) == 0xfe && (((uint8_t *)(a))[1] & 0xc0) == 0x80) | |
59 | ||
60 | #define __IN6_IS_ADDR_MC_LINKLOCAL(a) \ | |
61 | (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *)(a))[1] & 0xf) == 0x2)) | |
62 | ||
63 | #define __RTA_DATA(rta) ((void *)((char *)(rta) + sizeof(struct rtattr))) | |
4ba0d9af | 64 | |
cc6119a0 CB |
65 | /* getifaddrs() reports hardware addresses with PF_PACKET that implies struct |
66 | * sockaddr_ll. But e.g. Infiniband socket address length is longer than | |
67 | * sockaddr_ll.ssl_addr[8] can hold. Use this hack struct to extend ssl_addr - | |
68 | * callers should be able to still use it. | |
69 | */ | |
59e9eabe CB |
70 | struct sockaddr_ll_hack { |
71 | unsigned short sll_family, sll_protocol; | |
72 | int sll_ifindex; | |
73 | unsigned short sll_hatype; | |
74 | unsigned char sll_pkttype, sll_halen; | |
75 | unsigned char sll_addr[24]; | |
76 | }; | |
77 | ||
78 | union sockany { | |
79 | struct sockaddr sa; | |
80 | struct sockaddr_ll_hack ll; | |
81 | struct sockaddr_in v4; | |
82 | struct sockaddr_in6 v6; | |
83 | }; | |
84 | ||
85 | struct ifaddrs_storage { | |
cc6119a0 | 86 | struct netns_ifaddrs ifa; |
59e9eabe CB |
87 | struct ifaddrs_storage *hash_next; |
88 | union sockany addr, netmask, ifu; | |
89 | unsigned int index; | |
90 | char name[IFNAMSIZ + 1]; | |
91 | }; | |
92 | ||
93 | struct ifaddrs_ctx { | |
94 | struct ifaddrs_storage *first; | |
95 | struct ifaddrs_storage *last; | |
96 | struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; | |
97 | }; | |
98 | ||
59e9eabe CB |
99 | static void copy_addr(struct sockaddr **r, int af, union sockany *sa, |
100 | void *addr, size_t addrlen, int ifindex) | |
4ba0d9af | 101 | { |
59e9eabe CB |
102 | uint8_t *dst; |
103 | size_t len; | |
104 | ||
105 | switch (af) { | |
106 | case AF_INET: | |
107 | dst = (uint8_t *)&sa->v4.sin_addr; | |
108 | len = 4; | |
109 | break; | |
110 | case AF_INET6: | |
111 | dst = (uint8_t *)&sa->v6.sin6_addr; | |
112 | len = 16; | |
cc6119a0 CB |
113 | if (__IN6_IS_ADDR_LINKLOCAL(addr) || |
114 | __IN6_IS_ADDR_MC_LINKLOCAL(addr)) | |
59e9eabe CB |
115 | sa->v6.sin6_scope_id = ifindex; |
116 | break; | |
117 | default: | |
118 | return; | |
119 | } | |
120 | ||
121 | if (addrlen < len) | |
122 | return; | |
123 | ||
124 | sa->sa.sa_family = af; | |
125 | ||
126 | memcpy(dst, addr, len); | |
127 | ||
128 | *r = &sa->sa; | |
4ba0d9af SG |
129 | } |
130 | ||
59e9eabe CB |
131 | static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, |
132 | int prefixlen) | |
4ba0d9af | 133 | { |
59e9eabe CB |
134 | uint8_t addr[16] = {0}; |
135 | int i; | |
136 | ||
137 | if ((size_t)prefixlen > 8 * sizeof(addr)) | |
138 | prefixlen = 8 * sizeof(addr); | |
139 | ||
140 | i = prefixlen / 8; | |
141 | ||
142 | memset(addr, 0xff, i); | |
143 | ||
144 | if ((size_t)i < sizeof(addr)) | |
145 | addr[i++] = 0xff << (8 - (prefixlen % 8)); | |
146 | ||
147 | copy_addr(r, af, sa, addr, sizeof(addr), 0); | |
4ba0d9af SG |
148 | } |
149 | ||
59e9eabe CB |
150 | static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, |
151 | size_t addrlen, int ifindex, unsigned short hatype) | |
4ba0d9af | 152 | { |
59e9eabe CB |
153 | if (addrlen > sizeof(sa->ll.sll_addr)) |
154 | return; | |
155 | ||
156 | sa->ll.sll_family = AF_PACKET; | |
157 | sa->ll.sll_ifindex = ifindex; | |
158 | sa->ll.sll_hatype = hatype; | |
159 | sa->ll.sll_halen = addrlen; | |
160 | ||
161 | memcpy(sa->ll.sll_addr, addr, addrlen); | |
162 | ||
163 | *r = &sa->sa; | |
4ba0d9af SG |
164 | } |
165 | ||
cc6119a0 | 166 | static int nl_msg_to_ifaddr(void *pctx, bool *netnsid_aware, struct nlmsghdr *h) |
4ba0d9af | 167 | { |
59e9eabe CB |
168 | struct ifaddrs_storage *ifs, *ifs0; |
169 | struct rtattr *rta; | |
170 | int stats_len = 0; | |
171 | struct ifinfomsg *ifi = __NLMSG_DATA(h); | |
172 | struct ifaddrmsg *ifa = __NLMSG_DATA(h); | |
173 | struct ifaddrs_ctx *ctx = pctx; | |
174 | ||
175 | if (h->nlmsg_type == RTM_NEWLINK) { | |
6ce39620 CB |
176 | #pragma GCC diagnostic push |
177 | #pragma GCC diagnostic ignored "-Wcast-align" | |
59e9eabe CB |
178 | for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h); |
179 | rta = __RTA_NEXT(rta)) { | |
da5efb6f CB |
180 | #if HAVE_STRUCT_RTNL_LINK_STATS64 |
181 | if (rta->rta_type != IFLA_STATS64) | |
182 | #else | |
59e9eabe | 183 | if (rta->rta_type != IFLA_STATS) |
da5efb6f | 184 | #endif |
59e9eabe CB |
185 | continue; |
186 | ||
187 | stats_len = __RTA_DATALEN(rta); | |
188 | break; | |
189 | } | |
6ce39620 | 190 | #pragma GCC diagnostic pop |
59e9eabe CB |
191 | } else { |
192 | for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; | |
193 | ifs0 = ifs0->hash_next) | |
194 | if (ifs0->index == ifa->ifa_index) | |
195 | break; | |
196 | if (!ifs0) | |
197 | return 0; | |
198 | } | |
199 | ||
200 | ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); | |
201 | if (!ifs) { | |
202 | errno = ENOMEM; | |
203 | return -1; | |
204 | } | |
205 | ||
6ce39620 CB |
206 | #pragma GCC diagnostic push |
207 | #pragma GCC diagnostic ignored "-Wcast-align" | |
59e9eabe CB |
208 | if (h->nlmsg_type == RTM_NEWLINK) { |
209 | ifs->index = ifi->ifi_index; | |
cc6119a0 | 210 | ifs->ifa.ifa_ifindex = ifi->ifi_index; |
59e9eabe CB |
211 | ifs->ifa.ifa_flags = ifi->ifi_flags; |
212 | ||
213 | for (rta = __NLMSG_RTA(h, sizeof(*ifi)); __NLMSG_RTAOK(rta, h); | |
214 | rta = __RTA_NEXT(rta)) { | |
215 | switch (rta->rta_type) { | |
216 | case IFLA_IFNAME: | |
217 | if (__RTA_DATALEN(rta) < sizeof(ifs->name)) { | |
218 | memcpy(ifs->name, __RTA_DATA(rta), | |
219 | __RTA_DATALEN(rta)); | |
220 | ifs->ifa.ifa_name = ifs->name; | |
221 | } | |
222 | break; | |
223 | case IFLA_ADDRESS: | |
224 | copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, | |
225 | __RTA_DATA(rta), __RTA_DATALEN(rta), | |
226 | ifi->ifi_index, ifi->ifi_type); | |
227 | break; | |
228 | case IFLA_BROADCAST: | |
cc6119a0 | 229 | copy_lladdr(&ifs->ifa.__ifa_broadaddr, &ifs->ifu, |
59e9eabe CB |
230 | __RTA_DATA(rta), __RTA_DATALEN(rta), |
231 | ifi->ifi_index, ifi->ifi_type); | |
232 | break; | |
da5efb6f CB |
233 | #if HAVE_STRUCT_RTNL_LINK_STATS64 |
234 | case IFLA_STATS64: | |
235 | ifs->ifa.ifa_stats_type = IFLA_STATS64; | |
da5efb6f | 236 | #else |
59e9eabe | 237 | case IFLA_STATS: |
da5efb6f | 238 | ifs->ifa.ifa_stats_type = IFLA_STATS; |
3ccf815f CB |
239 | #endif |
240 | memcpy(&ifs->ifa.ifa_stats, __RTA_DATA(rta), | |
59e9eabe CB |
241 | __RTA_DATALEN(rta)); |
242 | break; | |
cc6119a0 CB |
243 | case IFLA_MTU: |
244 | memcpy(&ifs->ifa.ifa_mtu, __RTA_DATA(rta), | |
245 | sizeof(int)); | |
246 | break; | |
247 | case IFLA_TARGET_NETNSID: | |
248 | *netnsid_aware = true; | |
249 | break; | |
59e9eabe CB |
250 | } |
251 | } | |
252 | ||
253 | if (ifs->ifa.ifa_name) { | |
254 | unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; | |
255 | ifs->hash_next = ctx->hash[bucket]; | |
256 | ctx->hash[bucket] = ifs; | |
257 | } | |
258 | } else { | |
259 | ifs->ifa.ifa_name = ifs0->ifa.ifa_name; | |
cc6119a0 CB |
260 | ifs->ifa.ifa_mtu = ifs0->ifa.ifa_mtu; |
261 | ifs->ifa.ifa_ifindex = ifs0->ifa.ifa_ifindex; | |
59e9eabe CB |
262 | ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; |
263 | ||
264 | for (rta = __NLMSG_RTA(h, sizeof(*ifa)); __NLMSG_RTAOK(rta, h); | |
265 | rta = __RTA_NEXT(rta)) { | |
266 | switch (rta->rta_type) { | |
267 | case IFA_ADDRESS: | |
268 | /* If ifa_addr is already set we, received an | |
cc6119a0 CB |
269 | * IFA_LOCAL before so treat this as |
270 | * destination address. | |
59e9eabe CB |
271 | */ |
272 | if (ifs->ifa.ifa_addr) | |
cc6119a0 | 273 | copy_addr(&ifs->ifa.__ifa_dstaddr, |
59e9eabe CB |
274 | ifa->ifa_family, &ifs->ifu, |
275 | __RTA_DATA(rta), | |
276 | __RTA_DATALEN(rta), | |
277 | ifa->ifa_index); | |
278 | else | |
279 | copy_addr(&ifs->ifa.ifa_addr, | |
280 | ifa->ifa_family, &ifs->addr, | |
281 | __RTA_DATA(rta), | |
282 | __RTA_DATALEN(rta), | |
283 | ifa->ifa_index); | |
284 | break; | |
285 | case IFA_BROADCAST: | |
cc6119a0 | 286 | copy_addr(&ifs->ifa.__ifa_broadaddr, |
59e9eabe CB |
287 | ifa->ifa_family, &ifs->ifu, |
288 | __RTA_DATA(rta), __RTA_DATALEN(rta), | |
289 | ifa->ifa_index); | |
290 | break; | |
291 | case IFA_LOCAL: | |
292 | /* If ifa_addr is set and we get IFA_LOCAL, | |
cc6119a0 CB |
293 | * assume we have a point-to-point network. |
294 | * Move address to correct field. | |
59e9eabe CB |
295 | */ |
296 | if (ifs->ifa.ifa_addr) { | |
297 | ifs->ifu = ifs->addr; | |
cc6119a0 | 298 | ifs->ifa.__ifa_dstaddr = &ifs->ifu.sa; |
59e9eabe CB |
299 | |
300 | memset(&ifs->addr, 0, sizeof(ifs->addr)); | |
301 | } | |
302 | ||
303 | copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, | |
304 | &ifs->addr, __RTA_DATA(rta), | |
305 | __RTA_DATALEN(rta), ifa->ifa_index); | |
306 | break; | |
307 | case IFA_LABEL: | |
308 | if (__RTA_DATALEN(rta) < sizeof(ifs->name)) { | |
309 | memcpy(ifs->name, __RTA_DATA(rta), | |
310 | __RTA_DATALEN(rta)); | |
311 | ifs->ifa.ifa_name = ifs->name; | |
312 | } | |
313 | break; | |
cc6119a0 CB |
314 | case IFA_TARGET_NETNSID: |
315 | *netnsid_aware = true; | |
316 | break; | |
59e9eabe CB |
317 | } |
318 | } | |
319 | ||
cc6119a0 | 320 | if (ifs->ifa.ifa_addr) { |
59e9eabe CB |
321 | gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, |
322 | &ifs->netmask, ifa->ifa_prefixlen); | |
cc6119a0 CB |
323 | ifs->ifa.ifa_prefixlen = ifa->ifa_prefixlen; |
324 | } | |
59e9eabe | 325 | } |
6ce39620 CB |
326 | #pragma GCC diagnostic pop |
327 | ||
59e9eabe CB |
328 | if (ifs->ifa.ifa_name) { |
329 | if (!ctx->first) | |
330 | ctx->first = ifs; | |
331 | ||
332 | if (ctx->last) | |
333 | ctx->last->ifa.ifa_next = &ifs->ifa; | |
334 | ||
335 | ctx->last = ifs; | |
336 | } else { | |
337 | free(ifs); | |
338 | } | |
339 | ||
340 | return 0; | |
4ba0d9af SG |
341 | } |
342 | ||
cc6119a0 CB |
343 | static int __ifaddrs_netlink_send(int fd, struct nlmsghdr *nlmsghdr) |
344 | { | |
345 | int ret; | |
346 | struct sockaddr_nl nladdr; | |
347 | struct iovec iov = { | |
348 | .iov_base = nlmsghdr, | |
349 | .iov_len = nlmsghdr->nlmsg_len, | |
350 | }; | |
351 | struct msghdr msg = { | |
352 | .msg_name = &nladdr, | |
353 | .msg_namelen = sizeof(nladdr), | |
354 | .msg_iov = &iov, | |
355 | .msg_iovlen = 1, | |
356 | }; | |
357 | ||
358 | memset(&nladdr, 0, sizeof(nladdr)); | |
359 | nladdr.nl_family = AF_NETLINK; | |
360 | nladdr.nl_pid = 0; | |
361 | nladdr.nl_groups = 0; | |
362 | ||
363 | ret = sendmsg(fd, &msg, MSG_NOSIGNAL); | |
364 | if (ret < 0) | |
365 | return -1; | |
366 | ||
367 | return ret; | |
368 | } | |
369 | ||
370 | static int __ifaddrs_netlink_recv(int fd, unsigned int seq, int type, int af, | |
371 | __s32 netns_id, bool *netnsid_aware, | |
372 | int (*cb)(void *ctx, bool *netnsid_aware, | |
373 | struct nlmsghdr *h), | |
374 | void *ctx) | |
4ba0d9af | 375 | { |
7d60776a | 376 | int r, property, ret; |
cc6119a0 CB |
377 | char *buf; |
378 | struct nlmsghdr *hdr; | |
379 | struct ifinfomsg *ifi_msg; | |
380 | struct ifaddrmsg *ifa_msg; | |
59e9eabe CB |
381 | union { |
382 | uint8_t buf[8192]; | |
383 | struct { | |
384 | struct nlmsghdr nlh; | |
385 | struct rtgenmsg g; | |
386 | } req; | |
387 | struct nlmsghdr reply; | |
388 | } u; | |
7d60776a CB |
389 | char getlink_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) + |
390 | __NETLINK_ALIGN(sizeof(struct ifinfomsg)) + | |
391 | __NETLINK_ALIGN(1024)] = {0}; | |
392 | char getaddr_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) + | |
393 | __NETLINK_ALIGN(sizeof(struct ifaddrmsg)) + | |
394 | __NETLINK_ALIGN(1024)] = {0}; | |
d3d5554a CB |
395 | |
396 | #pragma GCC diagnostic push | |
397 | #pragma GCC diagnostic ignored "-Wcast-align" | |
7d60776a CB |
398 | if (type == RTM_GETLINK) { |
399 | buf = getlink_buf; | |
400 | hdr = (struct nlmsghdr *)buf; | |
401 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi_msg)); | |
402 | ||
cc6119a0 | 403 | ifi_msg = (struct ifinfomsg *)__NLMSG_DATA(hdr); |
7d60776a | 404 | ifi_msg->ifi_family = af; |
cc6119a0 | 405 | |
7d60776a CB |
406 | property = IFLA_TARGET_NETNSID; |
407 | } else if (type == RTM_GETADDR) { | |
408 | buf = getaddr_buf; | |
409 | hdr = (struct nlmsghdr *)buf; | |
cc6119a0 | 410 | hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa_msg)); |
7d60776a CB |
411 | |
412 | ifa_msg = (struct ifaddrmsg *)__NLMSG_DATA(hdr); | |
413 | ifa_msg->ifa_family = af; | |
414 | ||
415 | property = IFA_TARGET_NETNSID; | |
416 | } else { | |
417 | errno = EINVAL; | |
418 | return -1; | |
419 | } | |
d3d5554a | 420 | #pragma GCC diagnostic pop |
cc6119a0 CB |
421 | |
422 | hdr->nlmsg_type = type; | |
423 | hdr->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; | |
424 | hdr->nlmsg_pid = 0; | |
425 | hdr->nlmsg_seq = seq; | |
cc6119a0 CB |
426 | |
427 | if (netns_id >= 0) | |
428 | addattr(hdr, 1024, property, &netns_id, sizeof(netns_id)); | |
429 | ||
430 | r = __ifaddrs_netlink_send(fd, hdr); | |
59e9eabe | 431 | if (r < 0) |
cc6119a0 | 432 | return -1; |
59e9eabe CB |
433 | |
434 | for (;;) { | |
435 | r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); | |
436 | if (r <= 0) | |
437 | return -1; | |
438 | ||
6ce39620 CB |
439 | #pragma GCC diagnostic push |
440 | #pragma GCC diagnostic ignored "-Wcast-align" | |
cc6119a0 CB |
441 | for (hdr = &u.reply; __NLMSG_OK(hdr, (void *)&u.buf[r]); |
442 | hdr = __NLMSG_NEXT(hdr)) { | |
443 | if (hdr->nlmsg_type == NLMSG_DONE) | |
59e9eabe CB |
444 | return 0; |
445 | ||
cc6119a0 | 446 | if (hdr->nlmsg_type == NLMSG_ERROR) { |
59e9eabe CB |
447 | errno = EINVAL; |
448 | return -1; | |
449 | } | |
450 | ||
cc6119a0 | 451 | ret = cb(ctx, netnsid_aware, hdr); |
59e9eabe CB |
452 | if (ret) |
453 | return ret; | |
454 | } | |
6ce39620 | 455 | #pragma GCC diagnostic pop |
59e9eabe | 456 | } |
4ba0d9af SG |
457 | } |
458 | ||
cc6119a0 CB |
459 | static int __rtnl_enumerate(int link_af, int addr_af, __s32 netns_id, |
460 | bool *netnsid_aware, | |
461 | int (*cb)(void *ctx, bool *netnsid_aware, struct nlmsghdr *h), | |
462 | void *ctx) | |
4ba0d9af | 463 | { |
59e9eabe | 464 | int fd, r, saved_errno; |
cc6119a0 | 465 | bool getaddr_netnsid_aware = false, getlink_netnsid_aware = false; |
59e9eabe CB |
466 | |
467 | fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); | |
468 | if (fd < 0) | |
469 | return -1; | |
470 | ||
c8ca5a43 | 471 | r = setsockopt(fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &(int){1}, |
c6b64720 CB |
472 | sizeof(int)); |
473 | if (r < 0 && netns_id >= 0) { | |
474 | close(fd); | |
475 | *netnsid_aware = false; | |
476 | return -1; | |
477 | } | |
478 | ||
cc6119a0 CB |
479 | r = __ifaddrs_netlink_recv(fd, 1, RTM_GETLINK, link_af, netns_id, |
480 | &getlink_netnsid_aware, cb, ctx); | |
59e9eabe | 481 | if (!r) |
cc6119a0 CB |
482 | r = __ifaddrs_netlink_recv(fd, 2, RTM_GETADDR, addr_af, netns_id, |
483 | &getaddr_netnsid_aware, cb, ctx); | |
59e9eabe CB |
484 | |
485 | saved_errno = errno; | |
486 | close(fd); | |
487 | errno = saved_errno; | |
488 | ||
cc6119a0 CB |
489 | if (getaddr_netnsid_aware && getlink_netnsid_aware) |
490 | *netnsid_aware = true; | |
491 | else | |
492 | *netnsid_aware = false; | |
493 | ||
59e9eabe | 494 | return r; |
4ba0d9af SG |
495 | } |
496 | ||
cc6119a0 CB |
497 | void netns_freeifaddrs(struct netns_ifaddrs *ifp) |
498 | { | |
499 | struct netns_ifaddrs *n; | |
500 | ||
501 | while (ifp) { | |
502 | n = ifp->ifa_next; | |
503 | free(ifp); | |
504 | ifp = n; | |
505 | } | |
506 | } | |
507 | ||
508 | int netns_getifaddrs(struct netns_ifaddrs **ifap, __s32 netns_id, | |
509 | bool *netnsid_aware) | |
4ba0d9af | 510 | { |
59e9eabe CB |
511 | int r, saved_errno; |
512 | struct ifaddrs_ctx _ctx; | |
513 | struct ifaddrs_ctx *ctx = &_ctx; | |
4ba0d9af | 514 | |
59e9eabe CB |
515 | memset(ctx, 0, sizeof *ctx); |
516 | ||
cc6119a0 CB |
517 | r = __rtnl_enumerate(AF_UNSPEC, AF_UNSPEC, netns_id, netnsid_aware, |
518 | nl_msg_to_ifaddr, ctx); | |
59e9eabe CB |
519 | saved_errno = errno; |
520 | if (r < 0) | |
cc6119a0 | 521 | netns_freeifaddrs(&ctx->first->ifa); |
59e9eabe CB |
522 | else |
523 | *ifap = &ctx->first->ifa; | |
524 | errno = saved_errno; | |
525 | ||
526 | return r; | |
4ba0d9af | 527 | } |