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