Coverage Report

Created: 2026-07-16 06:07

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