Coverage Report

Created: 2026-05-30 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lldpd/src/daemon/netlink.c
Line
Count
Source
1
/* -*- mode: c; c-file-style: "openbsd" -*- */
2
/*
3
 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4
 *
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* Grabbing interfaces information with netlink only. */
19
20
#include "lldpd.h"
21
22
#include <errno.h>
23
#include <sys/socket.h>
24
#include <netdb.h>
25
#include <net/if_arp.h>
26
#include <linux/netlink.h>
27
#include <linux/rtnetlink.h>
28
#include <linux/if_bridge.h>
29
30
0
#define NETLINK_BUFFER 4096
31
32
struct netlink_req {
33
  struct nlmsghdr hdr;
34
  struct ifinfomsg ifm;
35
  /* attribute has to be NLMSG aligned */
36
  struct rtattr ext_req __attribute__((aligned(NLMSG_ALIGNTO)));
37
  __u32 ext_filter_mask;
38
};
39
40
struct lldpd_netlink {
41
  int nl_socket_queries;
42
  int nl_socket_changes;
43
  int nl_socket_recv_size;
44
  /* Cache */
45
  struct interfaces_device_list *devices;
46
  struct interfaces_address_list *addresses;
47
};
48
49
/**
50
 * Set netlink socket buffer size.
51
 *
52
 * This returns the effective size on success. If the provided value is 0, this
53
 * returns the current size instead. It returns -1 on system errors and -2 if
54
 * the size was not changed appropriately (when reaching the max).
55
 */
56
static int
57
netlink_socket_set_buffer_size(int s, int optname, const char *optname_str, int bufsize)
58
0
{
59
0
  socklen_t size = sizeof(int);
60
0
  int got = 0;
61
62
0
  if (bufsize > 0 &&
63
0
      setsockopt(s, SOL_SOCKET, optname, &bufsize, sizeof(bufsize)) < 0) {
64
0
    log_warn("netlink", "unable to set %s to '%d'", optname_str, bufsize);
65
0
    return -1;
66
0
  }
67
68
  /* Now read them back from kernel.
69
   * SO_SNDBUF & SO_RCVBUF are cap-ed at sysctl `net.core.rmem_max` &
70
   * `net.core.wmem_max`. This it the easiest [probably sanest too]
71
   * to validate that our socket buffers were set properly.
72
   */
73
0
  if (getsockopt(s, SOL_SOCKET, optname, &got, &size) < 0) {
74
0
    log_warn("netlink", "unable to get %s", optname_str);
75
0
    return -1;
76
0
  }
77
0
  if (bufsize > 0 && got < bufsize) {
78
0
    log_warnx("netlink",
79
0
        "tried to set %s to '%d' "
80
0
        "but got '%d'",
81
0
        optname_str, bufsize, got);
82
0
    return -2;
83
0
  }
84
85
0
  return got;
86
0
}
87
88
/**
89
 * Connect to netlink.
90
 *
91
 * Open a Netlink socket and connect to it.
92
 *
93
 * @param groups   Which groups we want to subscribe to
94
 * @return 0 on success, -1 otherwise
95
 */
96
static int
97
netlink_connect(struct lldpd *cfg, unsigned groups)
98
0
{
99
0
  int s1 = -1, s2 = -1;
100
0
  struct sockaddr_nl local = { .nl_family = AF_NETLINK,
101
0
    .nl_pid = 0,
102
0
    .nl_groups = groups };
103
104
  /* Open Netlink socket for subscriptions */
105
0
  log_debug("netlink", "opening netlink sockets");
106
0
  s1 = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
107
0
  if (s1 == -1) {
108
0
    log_warn("netlink", "unable to open netlink socket for changes");
109
0
    goto error;
110
0
  }
111
0
  if (NETLINK_SEND_BUFSIZE &&
112
0
      netlink_socket_set_buffer_size(s1, SO_SNDBUF, "SO_SNDBUF",
113
0
    NETLINK_SEND_BUFSIZE) == -1) {
114
0
    log_warn("netlink", "unable to set send buffer size");
115
0
    goto error;
116
0
  }
117
118
0
  int rc = netlink_socket_set_buffer_size(s1, SO_RCVBUF, "SO_RCVBUF",
119
0
      NETLINK_RECEIVE_BUFSIZE);
120
0
  switch (rc) {
121
0
  case -1:
122
0
    log_warn("netlink", "unable to set receiver buffer size");
123
0
    goto error;
124
0
  case -2:
125
    /* Cannot set size */
126
0
    cfg->g_netlink->nl_socket_recv_size = 0;
127
0
    break;
128
0
  default:
129
0
    cfg->g_netlink->nl_socket_recv_size = rc;
130
0
    break;
131
0
  }
132
0
  if (groups &&
133
0
      bind(s1, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
134
0
    log_warn("netlink", "unable to bind netlink socket");
135
0
    goto error;
136
0
  }
137
138
  /* Opening Netlink socket to for queries */
139
0
  s2 = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
140
0
  if (s2 == -1) {
141
0
    log_warn("netlink", "unable to open netlink socket for queries");
142
0
    goto error;
143
0
  }
144
0
  cfg->g_netlink->nl_socket_changes = s1;
145
0
  cfg->g_netlink->nl_socket_queries = s2;
146
0
  return 0;
147
0
error:
148
0
  if (s1 != -1) close(s1);
149
0
  if (s2 != -1) close(s2);
150
0
  return -1;
151
0
}
152
153
/**
154
 * Send a netlink message.
155
 *
156
 * The type of the message can be chosen as well the route family. The
157
 * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
158
 *
159
 * @param s      the netlink socket
160
 * @param type   the request type (eg RTM_GETLINK)
161
 * @param family the rt family (eg AF_PACKET)
162
 * @return 0 on success, -1 otherwise
163
 */
164
static int
165
netlink_send(int s, int type, int family, int seq)
166
0
{
167
0
  struct netlink_req req = { .hdr = { .nlmsg_len =
168
0
            NLMSG_LENGTH(sizeof(struct ifinfomsg)),
169
0
               .nlmsg_type = type,
170
0
               .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
171
0
               .nlmsg_seq = seq,
172
0
               .nlmsg_pid = getpid() },
173
0
    .ifm = { .ifi_family = family } };
174
0
  struct iovec iov = { .iov_base = &req, .iov_len = req.hdr.nlmsg_len };
175
0
  struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
176
0
  struct msghdr rtnl_msg = { .msg_iov = &iov,
177
0
    .msg_iovlen = 1,
178
0
    .msg_name = &peer,
179
0
    .msg_namelen = sizeof(struct sockaddr_nl) };
180
181
0
  if (family == AF_BRIDGE) {
182
0
    unsigned int len = RTA_LENGTH(sizeof(__u32));
183
    /* request bridge vlan attributes */
184
0
    req.ext_req.rta_type = IFLA_EXT_MASK;
185
0
    req.ext_req.rta_len = len;
186
0
    req.ext_filter_mask = RTEXT_FILTER_BRVLAN;
187
0
    req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_ALIGN(len);
188
0
    iov.iov_len = req.hdr.nlmsg_len;
189
0
  }
190
191
  /* Send netlink message. This is synchronous but we are guaranteed
192
   * to not block. */
193
0
  log_debug("netlink", "sending netlink message");
194
0
  if (sendmsg(s, (struct msghdr *)&rtnl_msg, 0) == -1) {
195
0
    log_warn("netlink", "unable to send netlink message");
196
0
    return -1;
197
0
  }
198
199
0
  return 0;
200
0
}
201
202
static void
203
netlink_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
204
0
{
205
0
  while (RTA_OK(rta, len)) {
206
0
    if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
207
0
      tb[rta->rta_type] = rta;
208
0
    rta = RTA_NEXT(rta, len);
209
0
  }
210
0
}
211
212
/**
213
 * Parse a `linkinfo` attributes.
214
 *
215
 * @param iff where to put the result
216
 * @param rta linkinfo attribute
217
 * @param len length of attributes
218
 */
219
static void
220
netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
221
0
{
222
0
  struct rtattr *link_info_attrs[IFLA_INFO_MAX + 1] = {};
223
0
  char *kind = NULL;
224
0
  uint16_t vlan_id;
225
226
0
  netlink_parse_rtattr(link_info_attrs, IFLA_INFO_MAX, rta, len);
227
228
0
  if (link_info_attrs[IFLA_INFO_KIND]) {
229
0
    kind = strdup(RTA_DATA(link_info_attrs[IFLA_INFO_KIND]));
230
0
    if (kind) {
231
0
      if (!strcmp(kind, "vlan")) {
232
0
        log_debug("netlink", "interface %s is a VLAN",
233
0
            iff->name);
234
0
        iff->type |= IFACE_VLAN_T;
235
0
      } else if (!strcmp(kind, "bridge")) {
236
0
        log_debug("netlink", "interface %s is a bridge",
237
0
            iff->name);
238
0
        iff->type |= IFACE_BRIDGE_T;
239
0
      } else if (!strcmp(kind, "bond")) {
240
0
        log_debug("netlink", "interface %s is a bond",
241
0
            iff->name);
242
0
        iff->type |= IFACE_BOND_T;
243
0
      } else if (!strcmp(kind, "team")) {
244
0
        log_debug("netlink", "interface %s is a team",
245
0
            iff->name);
246
0
        iff->type |= IFACE_BOND_T;
247
0
      }
248
0
    }
249
0
  }
250
251
0
  if (kind && !strcmp(kind, "vlan") && link_info_attrs[IFLA_INFO_DATA]) {
252
0
    struct rtattr *vlan_link_info_data_attrs[IFLA_VLAN_MAX + 1] = {};
253
0
    netlink_parse_rtattr(vlan_link_info_data_attrs, IFLA_VLAN_MAX,
254
0
        RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
255
0
        RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
256
257
0
    if (vlan_link_info_data_attrs[IFLA_VLAN_ID]) {
258
0
      vlan_id = *(uint16_t *)RTA_DATA(
259
0
          vlan_link_info_data_attrs[IFLA_VLAN_ID]);
260
0
      bitmap_set(iff->vlan_bmap, vlan_id);
261
0
      log_debug("netlink", "VLAN ID for interface %s is %d",
262
0
          iff->name, vlan_id);
263
0
    }
264
0
  }
265
266
0
  if (kind && !strcmp(kind, "bridge") && link_info_attrs[IFLA_INFO_DATA]) {
267
0
    struct rtattr *bridge_link_info_data_attrs[IFLA_BR_MAX + 1] = {};
268
0
    netlink_parse_rtattr(bridge_link_info_data_attrs, IFLA_BR_MAX,
269
0
        RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
270
0
        RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
271
272
0
    if (bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING] &&
273
0
        *(uint8_t *)RTA_DATA(
274
0
      bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING]) > 0) {
275
0
      iff->type |= IFACE_BRIDGE_VLAN_T;
276
0
    }
277
0
  }
278
279
0
  free(kind);
280
0
}
281
282
/**
283
 * Parse a `afspec` attributes.
284
 *
285
 * @param iff where to put the result
286
 * @param rta afspec attribute
287
 * @param len length of attributes
288
 */
289
static void
290
netlink_parse_afspec(struct interfaces_device *iff, struct rtattr *rta, int len)
291
0
{
292
0
  while (RTA_OK(rta, len)) {
293
0
    struct bridge_vlan_info *vinfo;
294
0
    switch (rta->rta_type) {
295
0
    case IFLA_BRIDGE_VLAN_INFO:
296
0
      vinfo = RTA_DATA(rta);
297
0
      log_debug("netlink", "found VLAN %d on interface %s",
298
0
          vinfo->vid, iff->name ? iff->name : "(unknown)");
299
300
0
      bitmap_set(iff->vlan_bmap, vinfo->vid);
301
0
      if (vinfo->flags &
302
0
          (BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED))
303
0
        iff->pvid = vinfo->vid;
304
0
      break;
305
0
    default:
306
0
      log_debug("netlink",
307
0
          "unknown afspec attribute type %d for iface %s",
308
0
          rta->rta_type, iff->name ? iff->name : "(unknown)");
309
0
      break;
310
0
    }
311
0
    rta = RTA_NEXT(rta, len);
312
0
  }
313
  /* All enbridged interfaces will have VLAN 1 by default, ignore it */
314
0
  if (iff->vlan_bmap[0] == 2 && (bitmap_numbits(iff->vlan_bmap) == 1) &&
315
0
      iff->pvid == 1) {
316
0
    log_debug("netlink",
317
0
        "found only default VLAN 1 on interface %s, removing",
318
0
        iff->name ? iff->name : "(unknown)");
319
0
    iff->vlan_bmap[0] = iff->pvid = 0;
320
0
  }
321
0
}
322
323
/**
324
 * Parse a `link` netlink message.
325
 *
326
 * @param msg  message to be parsed
327
 * @param iff  where to put the result
328
 * return 0 if the interface is worth it, -1 otherwise
329
 */
330
static int
331
netlink_parse_link(struct nlmsghdr *msg, struct interfaces_device *iff)
332
0
{
333
0
  struct ifinfomsg *ifi;
334
0
  struct rtattr *attribute;
335
0
  int len;
336
0
  ifi = NLMSG_DATA(msg);
337
0
  len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
338
339
0
  if (ifi->ifi_type != ARPHRD_ETHER) {
340
0
    log_debug("netlink", "skip non Ethernet interface at index %d",
341
0
        ifi->ifi_index);
342
0
    return -1;
343
0
  }
344
345
0
  iff->index = ifi->ifi_index;
346
0
  iff->flags = ifi->ifi_flags;
347
0
  iff->lower_idx = -1;
348
0
  iff->upper_idx = -1;
349
350
0
  for (attribute = IFLA_RTA(ifi); RTA_OK(attribute, len);
351
0
       attribute = RTA_NEXT(attribute, len)) {
352
0
    switch (attribute->rta_type) {
353
0
    case IFLA_IFNAME:
354
      /* Interface name */
355
0
      iff->name = strdup(RTA_DATA(attribute));
356
0
      break;
357
0
    case IFLA_IFALIAS:
358
      /* Interface alias */
359
0
      iff->alias = strdup(RTA_DATA(attribute));
360
0
      break;
361
0
    case IFLA_ADDRESS:
362
      /* Interface MAC address */
363
0
      iff->address = malloc(RTA_PAYLOAD(attribute));
364
0
      if (iff->address)
365
0
        memcpy(iff->address, RTA_DATA(attribute),
366
0
            RTA_PAYLOAD(attribute));
367
0
      break;
368
0
    case IFLA_LINK:
369
      /* Index of "lower" interface */
370
0
      if (iff->lower_idx == -1) {
371
0
        iff->lower_idx = *(int *)RTA_DATA(attribute);
372
0
        log_debug("netlink", "attribute IFLA_LINK for %s: %d",
373
0
            iff->name ? iff->name : "(unknown)",
374
0
            iff->lower_idx);
375
0
      } else {
376
0
        log_debug("netlink",
377
0
            "attribute IFLA_LINK for %s: %d (ignored)",
378
0
            iff->name ? iff->name : "(unknown)",
379
0
            iff->lower_idx);
380
0
      }
381
0
      break;
382
0
    case IFLA_LINK_NETNSID:
383
      /* Is the lower interface into another namesapce? */
384
0
      iff->lower_idx = -2;
385
0
      log_debug("netlink",
386
0
          "attribute IFLA_LINK_NETNSID received for %s",
387
0
          iff->name ? iff->name : "(unknown)");
388
0
      break;
389
0
    case IFLA_MASTER:
390
      /* Index of master interface */
391
0
      iff->upper_idx = *(int *)RTA_DATA(attribute);
392
0
      break;
393
0
    case IFLA_MTU:
394
      /* Maximum Transmission Unit */
395
0
      iff->mtu = *(int *)RTA_DATA(attribute);
396
0
      break;
397
0
    case IFLA_LINKINFO:
398
0
      netlink_parse_linkinfo(iff, RTA_DATA(attribute),
399
0
          RTA_PAYLOAD(attribute));
400
0
      break;
401
0
    case IFLA_AF_SPEC:
402
0
      if (ifi->ifi_family != AF_BRIDGE) break;
403
0
      netlink_parse_afspec(iff, RTA_DATA(attribute),
404
0
          RTA_PAYLOAD(attribute));
405
0
      break;
406
0
    default:
407
0
      log_debug("netlink",
408
0
          "unhandled link attribute type %d for iface %s",
409
0
          attribute->rta_type, iff->name ? iff->name : "(unknown)");
410
0
      break;
411
0
    }
412
0
  }
413
0
  if (!iff->name || !iff->address) {
414
0
    log_debug("netlink",
415
0
        "interface %d does not have a name or an address, skip",
416
0
        iff->index);
417
0
    return -1;
418
0
  }
419
0
  if (iff->upper_idx == -1) {
420
    /* No upper interface, we cannot be enslaved. We need to clear
421
     * the flag because the appropriate information may come later
422
     * and we don't want to miss it. */
423
0
    iff->flags &= ~IFF_SLAVE;
424
0
  }
425
0
  if (iff->lower_idx == -2) iff->lower_idx = -1;
426
427
0
  if (ifi->ifi_family == AF_BRIDGE && msg->nlmsg_type == RTM_DELLINK &&
428
0
      iff->upper_idx != -1) {
429
0
    log_debug("netlink", "removal of %s from bridge %d", iff->name,
430
0
        iff->upper_idx);
431
0
    msg->nlmsg_type = RTM_NEWLINK;
432
0
    iff->upper_idx = -1;
433
0
  }
434
435
0
  log_debug("netlink", "parsed link %d (%s, flags: %d)", iff->index, iff->name,
436
0
      iff->flags);
437
0
  return 0;
438
0
}
439
440
/**
441
 * Parse a `address` netlink message.
442
 *
443
 * @param msg  message to be parsed
444
 * @param ifa  where to put the result
445
 * return 0 if the address is worth it, -1 otherwise
446
 */
447
static int
448
netlink_parse_address(struct nlmsghdr *msg, struct interfaces_address *ifa)
449
0
{
450
0
  struct ifaddrmsg *ifi;
451
0
  struct rtattr *attribute;
452
0
  int len;
453
0
  ifi = NLMSG_DATA(msg);
454
0
  len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
455
456
0
  ifa->index = ifi->ifa_index;
457
0
  ifa->flags = ifi->ifa_flags;
458
0
  switch (ifi->ifa_family) {
459
0
  case AF_INET:
460
0
  case AF_INET6:
461
0
    break;
462
0
  default:
463
0
    log_debug("netlink", "got a non IP address on if %d (family: %d)",
464
0
        ifa->index, ifi->ifa_family);
465
0
    return -1;
466
0
  }
467
468
0
  for (attribute = IFA_RTA(ifi); RTA_OK(attribute, len);
469
0
       attribute = RTA_NEXT(attribute, len)) {
470
0
    switch (attribute->rta_type) {
471
0
    case IFA_ADDRESS:
472
      /* Address */
473
0
      if (ifi->ifa_family == AF_INET) {
474
0
        struct sockaddr_in ip;
475
0
        memset(&ip, 0, sizeof(struct sockaddr_in));
476
0
        ip.sin_family = AF_INET;
477
0
        memcpy(&ip.sin_addr, RTA_DATA(attribute),
478
0
            sizeof(struct in_addr));
479
0
        memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
480
0
      } else {
481
0
        struct sockaddr_in6 ip6;
482
0
        memset(&ip6, 0, sizeof(struct sockaddr_in6));
483
0
        ip6.sin6_family = AF_INET6;
484
0
        memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
485
0
            sizeof(struct in6_addr));
486
0
        memcpy(&ifa->address, &ip6,
487
0
            sizeof(struct sockaddr_in6));
488
0
      }
489
0
      break;
490
0
    default:
491
0
      log_debug("netlink",
492
0
          "unhandled address attribute type %d for iface %d",
493
0
          attribute->rta_type, ifa->index);
494
0
      break;
495
0
    }
496
0
  }
497
0
  if (ifa->address.ss_family == AF_UNSPEC) {
498
0
    log_debug("netlink", "no IP for interface %d", ifa->index);
499
0
    return -1;
500
0
  }
501
0
  return 0;
502
0
}
503
504
/**
505
 * Merge an old interface with a new one.
506
 *
507
 * Some properties may be absent in the new interface that should be copied over
508
 * from the old one.
509
 */
510
static void
511
netlink_merge(struct interfaces_device *old, struct interfaces_device *new)
512
0
{
513
0
  if (new->alias == NULL) {
514
0
    new->alias = old->alias;
515
0
    old->alias = NULL;
516
0
  }
517
0
  if (new->address == NULL) {
518
0
    new->address = old->address;
519
0
    old->address = NULL;
520
0
  }
521
0
  if (new->mtu == 0) new->mtu = old->mtu;
522
0
  if (new->type == 0) new->type = old->type;
523
524
0
  if (bitmap_isempty(new->vlan_bmap) && new->type == IFACE_VLAN_T)
525
0
    memcpy((void *)new->vlan_bmap, (void *)old->vlan_bmap,
526
0
        sizeof(uint32_t) * VLAN_BITMAP_LEN);
527
528
  /* It's not possible for lower link to change */
529
0
  new->lower_idx = old->lower_idx;
530
0
}
531
532
/**
533
 * Receive netlink answer from the kernel.
534
 *
535
 * @param ifs  list to store interface list or NULL if we don't
536
 * @param ifas list to store address list or NULL if we don't
537
 * @return     0 on success, -1 on error
538
 */
539
static int
540
netlink_recv(struct lldpd *cfg, int s, struct interfaces_device_list *ifs,
541
    struct interfaces_address_list *ifas)
542
0
{
543
0
  int end = 0, ret = 0, flags, retry = 0;
544
0
  struct iovec iov;
545
0
  int link_update = 0;
546
547
0
  struct interfaces_device *ifdold;
548
0
  struct interfaces_device *ifdnew;
549
0
  struct interfaces_address *ifaold;
550
0
  struct interfaces_address *ifanew;
551
0
  char addr[INET6_ADDRSTRLEN + 1];
552
553
0
  iov.iov_len = NETLINK_BUFFER;
554
0
  iov.iov_base = malloc(iov.iov_len);
555
0
  if (!iov.iov_base) {
556
0
    log_warn("netlink", "not enough memory");
557
0
    return -1;
558
0
  }
559
560
0
  while (!end) {
561
0
    ssize_t len;
562
0
    struct nlmsghdr *msg;
563
0
    struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
564
0
    struct msghdr rtnl_reply = { .msg_iov = &iov,
565
0
      .msg_iovlen = 1,
566
0
      .msg_name = &peer,
567
0
      .msg_namelen = sizeof(struct sockaddr_nl) };
568
0
    flags = MSG_PEEK | MSG_TRUNC;
569
0
  retry:
570
0
    len = recvmsg(s, &rtnl_reply, flags);
571
0
    if (len == -1) {
572
0
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
573
0
        if (retry++ == 0) {
574
0
          levent_recv_error(s, "netlink socket");
575
0
          goto retry;
576
0
        }
577
0
        log_warnx("netlink",
578
0
            "should have received something, but didn't");
579
0
        ret = 0;
580
0
        goto out;
581
0
      }
582
0
      int rsize = cfg->g_netlink->nl_socket_recv_size;
583
0
      if (errno == ENOBUFS && rsize > 0 &&
584
0
          rsize < NETLINK_MAX_RECEIVE_BUFSIZE &&
585
0
          s == cfg->g_netlink->nl_socket_changes) {
586
        /* Try to increase buffer size, only for the
587
         * socket used to receive changes */
588
0
        rsize *= 2;
589
0
        if (rsize > NETLINK_MAX_RECEIVE_BUFSIZE) {
590
0
          rsize = NETLINK_MAX_RECEIVE_BUFSIZE;
591
0
        }
592
0
        int rc = netlink_socket_set_buffer_size(s, SO_RCVBUF,
593
0
            "SO_RCVBUF", rsize);
594
0
        if (rc < 0)
595
0
          cfg->g_netlink->nl_socket_recv_size = 0;
596
0
        else
597
0
          cfg->g_netlink->nl_socket_recv_size = rsize;
598
0
        if (rc > 0 || rc == -2) {
599
0
          log_info("netlink",
600
0
              "netlink receive buffer too small, retry with larger one (%d)",
601
0
              rsize);
602
0
          flags = 0;
603
0
          goto retry;
604
0
        }
605
0
      }
606
0
      log_warn("netlink", "unable to receive netlink answer");
607
0
      ret = -1;
608
0
      goto out;
609
0
    }
610
0
    if (!len) {
611
0
      ret = 0;
612
0
      goto out;
613
0
    }
614
615
0
    if (iov.iov_len < len || (rtnl_reply.msg_flags & MSG_TRUNC)) {
616
0
      void *tmp;
617
618
      /* Provided buffer is not large enough, enlarge it
619
       * to size of len (which should be total length of the message)
620
       * and try again. */
621
0
      iov.iov_len = len;
622
0
      tmp = realloc(iov.iov_base, iov.iov_len);
623
0
      if (!tmp) {
624
0
        log_warn("netlink", "not enough memory");
625
0
        ret = -1;
626
0
        goto out;
627
0
      }
628
0
      log_debug("netlink", "enlarge message size to %zu bytes", len);
629
0
      iov.iov_base = tmp;
630
0
      flags = 0;
631
0
      goto retry;
632
0
    }
633
634
0
    if (flags != 0) {
635
      /* Buffer is big enough, do the actual reading */
636
0
      flags = 0;
637
0
      goto retry;
638
0
    }
639
640
0
    for (msg = (struct nlmsghdr *)(void *)(iov.iov_base);
641
0
         NLMSG_OK(msg, len); msg = NLMSG_NEXT(msg, len)) {
642
0
      if (!(msg->nlmsg_flags & NLM_F_MULTI)) end = 1;
643
0
      switch (msg->nlmsg_type) {
644
0
      case NLMSG_DONE:
645
0
        log_debug("netlink", "received done message");
646
0
        end = 1;
647
0
        break;
648
0
      case RTM_NEWLINK:
649
0
      case RTM_DELLINK:
650
0
        if (!ifs) break;
651
0
        log_debug("netlink", "received link information");
652
0
        ifdnew = calloc(1, sizeof(struct interfaces_device));
653
0
        if (ifdnew == NULL) {
654
0
          log_warn("netlink",
655
0
              "not enough memory for another interface, give up what we have");
656
0
          goto end;
657
0
        }
658
0
        if (netlink_parse_link(msg, ifdnew) == 0) {
659
          /* We need to find if we already have this
660
           * interface */
661
0
          TAILQ_FOREACH (ifdold, ifs, next) {
662
0
            if (ifdold->index == ifdnew->index)
663
0
              break;
664
0
          }
665
666
0
          if (msg->nlmsg_type == RTM_NEWLINK) {
667
0
            if (ifdold == NULL) {
668
0
              log_debug("netlink",
669
0
                  "interface %s is new",
670
0
                  ifdnew->name);
671
0
              TAILQ_INSERT_TAIL(ifs, ifdnew,
672
0
                  next);
673
0
            } else {
674
0
              log_debug("netlink",
675
0
                  "interface %s/%s is updated",
676
0
                  ifdold->name, ifdnew->name);
677
0
              netlink_merge(ifdold, ifdnew);
678
0
              TAILQ_INSERT_AFTER(ifs, ifdold,
679
0
                  ifdnew, next);
680
0
              TAILQ_REMOVE(ifs, ifdold, next);
681
0
              interfaces_free_device(ifdold);
682
0
            }
683
0
          } else {
684
0
            if (ifdold == NULL) {
685
0
              log_warnx("netlink",
686
0
                  "removal request for %s, but no knowledge of it",
687
0
                  ifdnew->name);
688
0
            } else {
689
0
              log_debug("netlink",
690
0
                  "interface %s is to be removed",
691
0
                  ifdold->name);
692
0
              TAILQ_REMOVE(ifs, ifdold, next);
693
0
              interfaces_free_device(ifdold);
694
0
            }
695
0
            interfaces_free_device(ifdnew);
696
0
          }
697
0
          link_update = 1;
698
0
        } else {
699
0
          interfaces_free_device(ifdnew);
700
0
        }
701
0
        break;
702
0
      case RTM_NEWADDR:
703
0
      case RTM_DELADDR:
704
0
        if (!ifas) break;
705
0
        log_debug("netlink", "received address information");
706
0
        ifanew = calloc(1, sizeof(struct interfaces_address));
707
0
        if (ifanew == NULL) {
708
0
          log_warn("netlink",
709
0
              "not enough memory for another address, give what we have");
710
0
          goto end;
711
0
        }
712
0
        if (netlink_parse_address(msg, ifanew) == 0) {
713
0
          if (ifanew->address.ss_family == AF_INET6 &&
714
0
              ifanew->flags & IFA_F_TEMPORARY) {
715
0
            interfaces_free_address(ifanew);
716
0
            break;
717
0
          }
718
0
          TAILQ_FOREACH (ifaold, ifas, next) {
719
0
            if ((ifaold->index == ifanew->index) &&
720
0
                !memcmp(&ifaold->address,
721
0
              &ifanew->address,
722
0
              sizeof(ifaold->address)))
723
0
              break;
724
0
          }
725
0
          if (getnameinfo(
726
0
            (struct sockaddr *)&ifanew->address,
727
0
            sizeof(ifanew->address), addr,
728
0
            sizeof(addr), NULL, 0,
729
0
            NI_NUMERICHOST) != 0) {
730
0
            strlcpy(addr, "(unknown)",
731
0
                sizeof(addr));
732
0
          }
733
734
0
          if (msg->nlmsg_type == RTM_NEWADDR) {
735
0
            if (ifaold == NULL) {
736
0
              log_debug("netlink",
737
0
                  "new address %s%%%d", addr,
738
0
                  ifanew->index);
739
0
              TAILQ_INSERT_TAIL(ifas, ifanew,
740
0
                  next);
741
0
            } else {
742
0
              log_debug("netlink",
743
0
                  "updated address %s%%%d",
744
0
                  addr, ifaold->index);
745
0
              TAILQ_INSERT_AFTER(ifas, ifaold,
746
0
                  ifanew, next);
747
0
              TAILQ_REMOVE(ifas, ifaold,
748
0
                  next);
749
0
              interfaces_free_address(ifaold);
750
0
            }
751
0
          } else {
752
0
            if (ifaold == NULL) {
753
0
              log_info("netlink",
754
0
                  "removal request for address of %s%%%d, but no knowledge of it",
755
0
                  addr, ifanew->index);
756
0
            } else {
757
0
              log_debug("netlink",
758
0
                  "address %s%%%d is to be removed",
759
0
                  addr, ifaold->index);
760
0
              TAILQ_REMOVE(ifas, ifaold,
761
0
                  next);
762
0
              interfaces_free_address(ifaold);
763
0
            }
764
0
            interfaces_free_address(ifanew);
765
0
          }
766
0
        } else {
767
0
          interfaces_free_address(ifanew);
768
0
        }
769
0
        break;
770
0
      default:
771
0
        log_debug("netlink",
772
0
            "received unhandled message type %d (len: %d)",
773
0
            msg->nlmsg_type, msg->nlmsg_len);
774
0
      }
775
0
    }
776
0
  }
777
0
end:
778
0
  if (link_update) {
779
    /* Fill out lower/upper */
780
0
    struct interfaces_device *iface1, *iface2;
781
0
    TAILQ_FOREACH (iface1, ifs, next) {
782
0
      if (iface1->upper_idx != -1 &&
783
0
          iface1->upper_idx != iface1->index) {
784
0
        TAILQ_FOREACH (iface2, ifs, next) {
785
0
          if (iface1->upper_idx == iface2->index) {
786
0
            log_debug("netlink",
787
0
                "upper interface for %s is %s",
788
0
                iface1->name, iface2->name);
789
0
            iface1->upper = iface2;
790
0
            break;
791
0
          }
792
0
        }
793
0
        if (iface2 == NULL) iface1->upper = NULL;
794
0
      } else {
795
0
        iface1->upper = NULL;
796
0
      }
797
0
      if (iface1->lower_idx != -1 &&
798
0
          iface1->lower_idx != iface1->index) {
799
0
        TAILQ_FOREACH (iface2, ifs, next) {
800
0
          if (iface1->lower_idx == iface2->index) {
801
            /* Workaround a bug introduced
802
             * in Linux 4.1: a pair of veth
803
             * will be lower interface of
804
             * each other. Do not modify
805
             * index as if one of them is
806
             * updated, we will loose the
807
             * information about the
808
             * loop. */
809
0
            if (iface2->lower_idx ==
810
0
                iface1->index) {
811
0
              iface1->lower = NULL;
812
0
              log_debug("netlink",
813
0
                  "link loop detected between %s(%d) and %s(%d)",
814
0
                  iface1->name, iface1->index,
815
0
                  iface2->name,
816
0
                  iface2->index);
817
0
            } else {
818
0
              log_debug("netlink",
819
0
                  "lower interface for %s is %s",
820
0
                  iface1->name, iface2->name);
821
0
              iface1->lower = iface2;
822
0
            }
823
0
            break;
824
0
          }
825
0
        }
826
0
      } else {
827
0
        iface1->lower = NULL;
828
0
      }
829
0
    }
830
0
  }
831
832
0
out:
833
0
  free(iov.iov_base);
834
0
  return ret;
835
0
}
836
837
static int
838
netlink_group_mask(int group)
839
0
{
840
0
  return group ? (1 << (group - 1)) : 0;
841
0
}
842
843
/**
844
 * Subscribe to link changes.
845
 *
846
 * @return 0 on success, -1 otherwise
847
 */
848
static int
849
netlink_subscribe_changes(struct lldpd *cfg)
850
0
{
851
0
  unsigned int groups;
852
853
0
  log_debug("netlink", "listening on interface changes");
854
855
0
  groups = netlink_group_mask(RTNLGRP_LINK) |
856
0
      netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
857
0
      netlink_group_mask(RTNLGRP_IPV6_IFADDR);
858
859
0
  return netlink_connect(cfg, groups);
860
0
}
861
862
/**
863
 * Receive changes from netlink */
864
static void
865
netlink_change_cb(struct lldpd *cfg)
866
0
{
867
0
  if (cfg->g_netlink == NULL) return;
868
0
  netlink_recv(cfg, cfg->g_netlink->nl_socket_changes, cfg->g_netlink->devices,
869
0
      cfg->g_netlink->addresses);
870
0
}
871
872
/**
873
 * Initialize netlink subsystem.
874
 *
875
 * This can be called several times but will have effect only the first time.
876
 *
877
 * @return 0 on success, -1 otherwise
878
 */
879
static int
880
netlink_initialize(struct lldpd *cfg)
881
0
{
882
0
#ifdef ENABLE_DOT1
883
0
  struct interfaces_device *iff;
884
0
#endif
885
886
0
  if (cfg->g_netlink) return 0;
887
888
0
  log_debug("netlink", "initialize netlink subsystem");
889
0
  if ((cfg->g_netlink = calloc(1, sizeof(struct lldpd_netlink))) == NULL) {
890
0
    log_warn("netlink", "unable to allocate memory for netlink subsystem");
891
0
    goto end;
892
0
  }
893
894
  /* Connect to netlink (by requesting to get notified on updates) and
895
   * request updated information right now */
896
0
  if (netlink_subscribe_changes(cfg) == -1) goto end;
897
898
0
  struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
899
0
      malloc(sizeof(struct interfaces_address_list));
900
0
  if (ifaddrs == NULL) {
901
0
    log_warn("netlink", "not enough memory for address list");
902
0
    goto end;
903
0
  }
904
0
  TAILQ_INIT(ifaddrs);
905
906
0
  struct interfaces_device_list *ifs = cfg->g_netlink->devices =
907
0
      malloc(sizeof(struct interfaces_device_list));
908
0
  if (ifs == NULL) {
909
0
    log_warn("netlink", "not enough memory for interface list");
910
0
    goto end;
911
0
  }
912
0
  TAILQ_INIT(ifs);
913
914
0
  if (netlink_send(cfg->g_netlink->nl_socket_queries, RTM_GETADDR, AF_UNSPEC,
915
0
    1) == -1)
916
0
    goto end;
917
0
  netlink_recv(cfg, cfg->g_netlink->nl_socket_queries, NULL, ifaddrs);
918
0
  if (netlink_send(cfg->g_netlink->nl_socket_queries, RTM_GETLINK, AF_PACKET,
919
0
    2) == -1)
920
0
    goto end;
921
0
  netlink_recv(cfg, cfg->g_netlink->nl_socket_queries, ifs, NULL);
922
0
#ifdef ENABLE_DOT1
923
  /* If we have a bridge, search for VLAN-aware bridges */
924
0
  TAILQ_FOREACH (iff, ifs, next) {
925
0
    if (iff->type & IFACE_BRIDGE_T) {
926
0
      log_debug("netlink",
927
0
          "interface %s is a bridge, check for VLANs", iff->name);
928
0
      if (netlink_send(cfg->g_netlink->nl_socket_queries, RTM_GETLINK,
929
0
        AF_BRIDGE, 3) == -1)
930
0
        goto end;
931
0
      netlink_recv(cfg, cfg->g_netlink->nl_socket_queries, ifs, NULL);
932
0
      break;
933
0
    }
934
0
  }
935
0
#endif
936
937
  /* Listen to any future change */
938
0
  cfg->g_iface_cb = netlink_change_cb;
939
0
  if (levent_iface_subscribe(cfg, cfg->g_netlink->nl_socket_changes) == -1) {
940
0
    goto end;
941
0
  }
942
943
0
  return 0;
944
0
end:
945
0
  netlink_cleanup(cfg);
946
0
  return -1;
947
0
}
948
949
/**
950
 * Cleanup netlink subsystem.
951
 */
952
void
953
netlink_cleanup(struct lldpd *cfg)
954
0
{
955
0
  if (cfg->g_netlink == NULL) return;
956
0
  if (cfg->g_netlink->nl_socket_changes != -1)
957
0
    close(cfg->g_netlink->nl_socket_changes);
958
0
  if (cfg->g_netlink->nl_socket_queries != -1)
959
0
    close(cfg->g_netlink->nl_socket_queries);
960
0
  interfaces_free_devices(cfg->g_netlink->devices);
961
0
  interfaces_free_addresses(cfg->g_netlink->addresses);
962
963
0
  free(cfg->g_netlink);
964
0
  cfg->g_netlink = NULL;
965
0
}
966
967
/**
968
 * Receive the list of interfaces.
969
 *
970
 * @return a list of interfaces.
971
 */
972
struct interfaces_device_list *
973
netlink_get_interfaces(struct lldpd *cfg)
974
0
{
975
0
  if (netlink_initialize(cfg) == -1) return NULL;
976
0
  struct interfaces_device *ifd;
977
0
  TAILQ_FOREACH (ifd, cfg->g_netlink->devices, next) {
978
0
    ifd->ignore = 0;
979
0
  }
980
0
  return cfg->g_netlink->devices;
981
0
}
982
983
/**
984
 * Receive the list of addresses.
985
 *
986
 * @return a list of addresses.
987
 */
988
struct interfaces_address_list *
989
netlink_get_addresses(struct lldpd *cfg)
990
0
{
991
0
  if (netlink_initialize(cfg) == -1) return NULL;
992
0
  return cfg->g_netlink->addresses;
993
0
}