]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces.c
interfaces: enforce redefinition of IN_IS_ADDR_* macros
[thirdparty/lldpd.git] / src / daemon / interfaces.c
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 #include "lldpd.h"
19 #include "trace.h"
20
21 #include <stddef.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <arpa/inet.h>
26
27 /* Generic ethernet interface initialization */
28 /**
29 * Enable multicast on the given interface.
30 */
31 void
32 interfaces_setup_multicast(struct lldpd *cfg, const char *name,
33 int remove)
34 {
35 int i, rc;
36
37 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
38 if (!cfg->g_protocols[i].enabled) continue;
39 if ((rc = priv_iface_multicast(name,
40 cfg->g_protocols[i].mac, !remove)) != 0) {
41 errno = rc;
42 if (errno != ENOENT)
43 log_debug("interfaces",
44 "unable to %s %s address to multicast filter for %s (%s)",
45 (remove)?"delete":"add",
46 cfg->g_protocols[i].name,
47 name, strerror(rc));
48 }
49 }
50 }
51
52 /**
53 * Free an interface.
54 *
55 * @param iff interface to be freed
56 */
57 void
58 interfaces_free_device(struct interfaces_device *iff)
59 {
60 if (!iff) return;
61 free(iff->name);
62 free(iff->alias);
63 free(iff->address);
64 free(iff->driver);
65 free(iff);
66 }
67
68 /**
69 * Free a list of interfaces.
70 *
71 * @param ifs list of interfaces to be freed
72 */
73 void
74 interfaces_free_devices(struct interfaces_device_list *ifs)
75 {
76 struct interfaces_device *iff, *iff_next;
77 if (!ifs) return;
78 for (iff = TAILQ_FIRST(ifs);
79 iff != NULL;
80 iff = iff_next) {
81 iff_next = TAILQ_NEXT(iff, next);
82 interfaces_free_device(iff);
83 }
84 free(ifs);
85 }
86
87 /**
88 * Free one address
89 *
90 * @param ifaddr Address to be freed
91 */
92 void
93 interfaces_free_address(struct interfaces_address *ifaddr)
94 {
95 free(ifaddr);
96 }
97
98 /**
99 * Free a list of addresses.
100 *
101 * @param ifaddrs list of addresses
102 */
103 void
104 interfaces_free_addresses(struct interfaces_address_list *ifaddrs)
105 {
106 struct interfaces_address *ifa, *ifa_next;
107 if (!ifaddrs) return;
108 for (ifa = TAILQ_FIRST(ifaddrs);
109 ifa != NULL;
110 ifa = ifa_next) {
111 ifa_next = TAILQ_NEXT(ifa, next);
112 interfaces_free_address(ifa);
113 }
114 free(ifaddrs);
115 }
116
117 /**
118 * Find the appropriate interface from the name.
119 *
120 * @param interfaces List of available interfaces
121 * @param device Name of the device we search for
122 * @return The interface or NULL if not found
123 */
124 struct interfaces_device*
125 interfaces_nametointerface(struct interfaces_device_list *interfaces,
126 const char *device)
127 {
128 struct interfaces_device *iface;
129 TAILQ_FOREACH(iface, interfaces, next) {
130 if (!strncmp(iface->name, device, IFNAMSIZ))
131 return iface;
132 }
133 log_debug("interfaces", "cannot get interface for index %s",
134 device);
135 return NULL;
136 }
137
138 /**
139 * Find the appropriate interface from the index.
140 *
141 * @param interfaces List of available interfaces
142 * @param index Index of the device we search for
143 * @return The interface or NULL if not found
144 */
145 struct interfaces_device*
146 interfaces_indextointerface(struct interfaces_device_list *interfaces,
147 int index)
148 {
149 struct interfaces_device *iface;
150 TAILQ_FOREACH(iface, interfaces, next) {
151 if (iface->index == index)
152 return iface;
153 }
154 log_debug("interfaces", "cannot get interface for index %d",
155 index);
156 return NULL;
157 }
158
159 void
160 interfaces_helper_whitelist(struct lldpd *cfg,
161 struct interfaces_device_list *interfaces)
162 {
163 struct interfaces_device *iface;
164
165 if (!cfg->g_config.c_iface_pattern)
166 return;
167
168 TAILQ_FOREACH(iface, interfaces, next) {
169 int m = pattern_match(iface->name, cfg->g_config.c_iface_pattern, 0);
170 switch (m) {
171 case 0:
172 log_debug("interfaces", "blacklist %s", iface->name);
173 iface->flags = 0;
174 continue;
175 case 2:
176 log_debug("interfaces", "whitelist %s (consider it as a physical interface)",
177 iface->name);
178 iface->type |= IFACE_PHYSICAL_T;
179 continue;
180 }
181 }
182 }
183
184 #ifdef ENABLE_DOT1
185 static void
186 iface_append_vlan(struct lldpd *cfg,
187 struct interfaces_device *vlan,
188 struct interfaces_device *lower)
189 {
190 struct lldpd_hardware *hardware =
191 lldpd_get_hardware(cfg, lower->name, lower->index, NULL);
192 struct lldpd_port *port;
193 struct lldpd_vlan *v;
194
195 if (hardware == NULL) {
196 log_debug("interfaces",
197 "cannot find real interface %s for VLAN %s",
198 lower->name, vlan->name);
199 return;
200 }
201
202 /* Check if the VLAN is already here. */
203 port = &hardware->h_lport;
204 TAILQ_FOREACH(v, &port->p_vlans, v_entries)
205 if (strncmp(vlan->name, v->v_name, IFNAMSIZ) == 0)
206 return;
207 if ((v = (struct lldpd_vlan *)
208 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
209 return;
210 if ((v->v_name = strdup(vlan->name)) == NULL) {
211 free(v);
212 return;
213 }
214 v->v_vid = vlan->vlanid;
215 log_debug("interfaces", "append VLAN %s for %s",
216 v->v_name,
217 hardware->h_ifname);
218 TAILQ_INSERT_TAIL(&port->p_vlans, v, v_entries);
219 }
220
221 /**
222 * Append VLAN to the lowest possible interface.
223 *
224 * @param vlan The VLAN interface (used to get VLAN ID).
225 * @param upper The upper interface we are currently examining.
226 *
227 * Initially, upper == vlan. This function will be called recursively.
228 */
229 static void
230 iface_append_vlan_to_lower(struct lldpd *cfg,
231 struct interfaces_device_list *interfaces,
232 struct interfaces_device *vlan,
233 struct interfaces_device *upper)
234 {
235 struct interfaces_device *lower;
236 log_debug("interfaces",
237 "looking to apply VLAN %s to physical interface behind %s",
238 vlan->name, upper->name);
239
240 /* Easy: check if we have a lower interface. */
241 if (upper->lower) {
242 log_debug("interfaces", "VLAN %s on lower interface %s",
243 vlan->name, upper->name);
244 iface_append_vlan_to_lower(cfg,
245 interfaces, vlan,
246 upper->lower);
247 return;
248 }
249
250 /* Other easy case, we have a physical interface. */
251 if (upper->type & IFACE_PHYSICAL_T) {
252 log_debug("interfaces", "VLAN %s on physical interface %s",
253 vlan->name, upper->name);
254 iface_append_vlan(cfg, vlan, upper);
255 return;
256 }
257
258 /* We can now search for interfaces that have our interface as an upper
259 * interface. */
260 TAILQ_FOREACH(lower, interfaces, next) {
261 if (lower->upper != upper) continue;
262 log_debug("interfaces", "VLAN %s on lower interface %s",
263 vlan->name, upper->name);
264 iface_append_vlan_to_lower(cfg,
265 interfaces, vlan, lower);
266 }
267 }
268
269 void
270 interfaces_helper_vlan(struct lldpd *cfg,
271 struct interfaces_device_list *interfaces)
272 {
273 struct interfaces_device *iface;
274
275 TAILQ_FOREACH(iface, interfaces, next) {
276 if (!iface->flags)
277 continue;
278 if (!(iface->type & IFACE_VLAN_T))
279 continue;
280
281 /* We need to find the physical interfaces of this
282 vlan, through bonds and bridges. */
283 log_debug("interfaces", "search physical interface for VLAN interface %s",
284 iface->name);
285 iface_append_vlan_to_lower(cfg, interfaces,
286 iface, iface);
287 }
288 }
289 #endif
290
291 /* Fill out chassis ID if not already done. Only physical interfaces are
292 * considered. */
293 void
294 interfaces_helper_chassis(struct lldpd *cfg,
295 struct interfaces_device_list *interfaces)
296 {
297 struct interfaces_device *iface;
298 struct lldpd_hardware *hardware;
299 char *name = NULL;
300
301 LOCAL_CHASSIS(cfg)->c_cap_enabled &=
302 ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
303 TAILQ_FOREACH(iface, interfaces, next) {
304 if (iface->type & IFACE_BRIDGE_T)
305 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
306 if (iface->type & IFACE_WIRELESS_T)
307 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
308 }
309 if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
310 (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
311 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
312
313 if (LOCAL_CHASSIS(cfg)->c_id != NULL &&
314 LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR)
315 return; /* We already have one */
316
317 TAILQ_FOREACH(iface, interfaces, next) {
318 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
319 if (cfg->g_config.c_cid_pattern &&
320 !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
321
322 if ((hardware = lldpd_get_hardware(cfg,
323 iface->name,
324 iface->index,
325 NULL)) == NULL)
326 /* That's odd. Let's skip. */
327 continue;
328
329 name = malloc(ETHER_ADDR_LEN);
330 if (!name) {
331 log_warn("interfaces", "not enough memory for chassis ID");
332 return;
333 }
334 free(LOCAL_CHASSIS(cfg)->c_id);
335 memcpy(name, hardware->h_lladdr, ETHER_ADDR_LEN);
336 LOCAL_CHASSIS(cfg)->c_id = name;
337 LOCAL_CHASSIS(cfg)->c_id_len = ETHER_ADDR_LEN;
338 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
339 return;
340 }
341 }
342
343 #undef IN_IS_ADDR_LOOPBACK
344 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
345 #undef IN_IS_ADDR_ANY
346 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
347 #undef IN_IS_ADDR_GLOBAL
348 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a))
349 #undef IN6_IS_ADDR_GLOBAL
350 #define IN6_IS_ADDR_GLOBAL(a) \
351 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
352
353 /* Find a management address in all available interfaces, even those that were
354 already handled. This is a special interface handler because it does not
355 really handle interface related information (management address is attached
356 to the local chassis). */
357 void
358 interfaces_helper_mgmt(struct lldpd *cfg,
359 struct interfaces_address_list *addrs)
360 {
361 struct interfaces_address *addr;
362 char addrstrbuf[INET6_ADDRSTRLEN];
363 struct lldpd_mgmt *mgmt;
364 void *sin_addr_ptr;
365 size_t sin_addr_size;
366 int af;
367 int allnegative = 0;
368
369 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
370
371 /* Is the pattern provided all negative? */
372 if (cfg->g_config.c_mgmt_pattern == NULL) allnegative = 1;
373 else if (cfg->g_config.c_mgmt_pattern[0] == '!') {
374 /* If each comma is followed by '!', its an all
375 negative pattern */
376 char *sep = cfg->g_config.c_mgmt_pattern;
377 while ((sep = strchr(sep, ',')) &&
378 (*(++sep) == '!'));
379 if (sep == NULL) allnegative = 1;
380 }
381
382 /* Find management addresses */
383 for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
384 /* We only take one of each address family, unless a
385 pattern is provided and is not all negative. For
386 example !*:*,!10.* will only blacklist
387 addresses. We will pick the first IPv4 address not
388 matching 10.*. */
389 TAILQ_FOREACH(addr, addrs, next) {
390 if (addr->address.ss_family != lldpd_af(af))
391 continue;
392
393 switch (af) {
394 case LLDPD_AF_IPV4:
395 sin_addr_ptr = &((struct sockaddr_in *)&addr->address)->sin_addr;
396 sin_addr_size = sizeof(struct in_addr);
397 if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
398 continue;
399 break;
400 case LLDPD_AF_IPV6:
401 sin_addr_ptr = &((struct sockaddr_in6 *)&addr->address)->sin6_addr;
402 sin_addr_size = sizeof(struct in6_addr);
403 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
404 continue;
405 break;
406 default:
407 assert(0);
408 continue;
409 }
410 if (inet_ntop(lldpd_af(af), sin_addr_ptr,
411 addrstrbuf, sizeof(addrstrbuf)) == NULL) {
412 log_warn("interfaces", "unable to convert IP address to a string");
413 continue;
414 }
415 if (cfg->g_config.c_mgmt_pattern == NULL ||
416 pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative)) {
417 mgmt = lldpd_alloc_mgmt(af, sin_addr_ptr, sin_addr_size,
418 addr->index);
419 if (mgmt == NULL) {
420 assert(errno == ENOMEM); /* anything else is a bug */
421 log_warn("interfaces", "out of memory error");
422 return;
423 }
424 log_debug("interfaces", "add management address %s", addrstrbuf);
425 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
426
427 /* Don't take additional address if the pattern is all negative. */
428 if (allnegative) break;
429 }
430 }
431 }
432 }
433
434 /* Fill up port name and description */
435 void
436 interfaces_helper_port_name_desc(struct lldpd *cfg,
437 struct lldpd_hardware *hardware,
438 struct interfaces_device *iface)
439 {
440 struct lldpd_port *port = &hardware->h_lport;
441
442 /* We need to set the portid to what the client configured.
443 This can be done from the CLI.
444 */
445 switch (cfg->g_config.c_lldp_portid_type) {
446 case LLDP_PORTID_SUBTYPE_IFNAME:
447 log_debug("interfaces", "use ifname for %s",
448 hardware->h_ifname);
449 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
450 port->p_id_len = strlen(hardware->h_ifname);
451 if (port->p_id != NULL) {
452 free(port->p_id);
453 }
454 if ((port->p_id = calloc(1, port->p_id_len)) == NULL)
455 fatal("interfaces", NULL);
456 memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
457 break;
458 case LLDP_PORTID_SUBTYPE_LLADDR:
459 /* fall through so we use the mac address */
460 default:
461 log_debug("interfaces", "use MAC address for %s",
462 hardware->h_ifname);
463 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
464 if (port->p_id != NULL) {
465 free(port->p_id);
466 }
467 if ((port->p_id = calloc(1, ETHER_ADDR_LEN)) == NULL)
468 fatal("interfaces", NULL);
469 memcpy(port->p_id, hardware->h_lladdr, ETHER_ADDR_LEN);
470 port->p_id_len = ETHER_ADDR_LEN;
471 }
472
473 if (iface->alias != NULL && strlen(iface->alias) != 0) {
474 /* use the actual alias in the port description */
475 log_debug("interfaces", "using alias in description for %s",
476 hardware->h_ifname);
477 if (port->p_descr != NULL) {
478 free(port->p_descr);
479 }
480 port->p_descr = strdup(iface->alias);
481 } else {
482 /* use the ifname in the port description until alias is set */
483 log_debug("interfaces", "using ifname in description for %s",
484 hardware->h_ifname);
485 if (port->p_descr != NULL) {
486 free(port->p_descr);
487 }
488 port->p_descr = strdup(hardware->h_ifname);
489 }
490 }
491
492 void
493 interfaces_helper_add_hardware(struct lldpd *cfg,
494 struct lldpd_hardware *hardware)
495 {
496 TRACE(LLDPD_INTERFACES_NEW(hardware->h_ifname));
497 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
498 }
499
500 void
501 interfaces_helper_physical(struct lldpd *cfg,
502 struct interfaces_device_list *interfaces,
503 struct lldpd_ops *ops,
504 int(*init)(struct lldpd *, struct lldpd_hardware *))
505 {
506 struct interfaces_device *iface;
507 struct lldpd_hardware *hardware;
508
509 TAILQ_FOREACH(iface, interfaces, next) {
510 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
511 if (!iface->flags) continue;
512
513 log_debug("interfaces", "%s is an acceptable ethernet device",
514 iface->name);
515 if ((hardware = lldpd_get_hardware(cfg,
516 iface->name,
517 iface->index,
518 ops)) == NULL) {
519 if ((hardware = lldpd_alloc_hardware(cfg,
520 iface->name,
521 iface->index)) == NULL) {
522 log_warnx("interfaces", "Unable to allocate space for %s",
523 iface->name);
524 continue;
525 }
526 if (init(cfg, hardware) != 0) {
527 log_warnx("interfaces",
528 "unable to initialize %s",
529 hardware->h_ifname);
530 lldpd_hardware_cleanup(cfg, hardware);
531 continue;
532 }
533 hardware->h_ops = ops;
534 hardware->h_mangle = (iface->upper &&
535 iface->upper->type & IFACE_BOND_T);
536 interfaces_helper_add_hardware(cfg, hardware);
537 } else {
538 if (hardware->h_flags) continue; /* Already seen this time */
539 lldpd_port_cleanup(&hardware->h_lport, 0);
540 }
541
542 hardware->h_flags = iface->flags; /* Should be non-zero */
543 iface->flags = 0; /* Future handlers
544 don't have to
545 care about this
546 interface. */
547
548 /* Get local address */
549 memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
550
551 /* Fill information about port */
552 interfaces_helper_port_name_desc(cfg, hardware, iface);
553
554 /* Fill additional info */
555 hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
556
557 #ifdef ENABLE_DOT3
558 if (iface->upper && iface->upper->type & IFACE_BOND_T)
559 hardware->h_lport.p_aggregid = iface->upper->index;
560 #endif
561 }
562 }
563
564 void
565 interfaces_helper_promisc(struct lldpd *cfg,
566 struct lldpd_hardware *hardware)
567 {
568 if (!cfg->g_config.c_promisc) return;
569 if (priv_iface_promisc(hardware->h_ifname) != 0) {
570 log_warnx("interfaces",
571 "unable to enable promiscuous mode for %s",
572 hardware->h_ifname);
573 }
574 }
575
576 /**
577 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
578 *
579 * With bonds, we have duplicate MAC address on different physical
580 * interfaces. We need to alter the source MAC address when we send on an
581 * inactive slave. The `h_mangle` flah is used to know if we need to do
582 * something like that.
583 */
584 int
585 interfaces_send_helper(struct lldpd *cfg,
586 struct lldpd_hardware *hardware,
587 char *buffer, size_t size)
588 {
589 if (size < 2 * ETHER_ADDR_LEN) {
590 log_warnx("interfaces",
591 "packet to send on %s is too small!",
592 hardware->h_ifname);
593 return 0;
594 }
595 if (hardware->h_mangle) {
596 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
597 char *src_mac = buffer + ETHER_ADDR_LEN;
598 char arbitrary[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
599
600 switch (cfg->g_config.c_bond_slave_src_mac_type) {
601 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED:
602 if (!(*src_mac & MAC_UL_ADMINISTERED_BIT_MASK)) {
603 *src_mac |= MAC_UL_ADMINISTERED_BIT_MASK;
604 break;
605 }
606 /* Fallback to fixed value */
607 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED:
608 memcpy(src_mac, arbitrary, ETHER_ADDR_LEN);
609 break;
610 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO:
611 memset(src_mac, 0, ETHER_ADDR_LEN);
612 break;
613 }
614 }
615 return hardware->h_ops->send(cfg, hardware, buffer, size);
616 }