xref: /openbsd/usr.sbin/ldpd/interface.c (revision 5b133f3f)
1 /*	$OpenBSD: interface.c,v 1.52 2023/03/08 04:43:13 guenther Exp $ */
2 
3 /*
4  * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <arpa/inet.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "ldpd.h"
28 #include "ldpe.h"
29 #include "log.h"
30 
31 static struct if_addr	*if_addr_new(struct kaddr *);
32 static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
33 static int		 if_start(struct iface *, int);
34 static int		 if_reset(struct iface *, int);
35 static void		 if_update_af(struct iface_af *, int);
36 static void		 if_hello_timer(int, short, void *);
37 static void		 if_start_hello_timer(struct iface_af *);
38 static void		 if_stop_hello_timer(struct iface_af *);
39 static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
40 static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
41 static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
42 static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
43 
44 struct iface *
if_new(struct kif * kif)45 if_new(struct kif *kif)
46 {
47 	struct iface		*iface;
48 
49 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
50 		fatal("if_new: calloc");
51 
52 	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
53 
54 	/* get type */
55 	if (kif->flags & IFF_POINTOPOINT)
56 		iface->type = IF_TYPE_POINTOPOINT;
57 	if (kif->flags & IFF_BROADCAST &&
58 	    kif->flags & IFF_MULTICAST)
59 		iface->type = IF_TYPE_BROADCAST;
60 
61 	/* get index and flags */
62 	LIST_INIT(&iface->addr_list);
63 	iface->ifindex = kif->ifindex;
64 	iface->rdomain = kif->rdomain;
65 	iface->flags = kif->flags;
66 	iface->linkstate = kif->link_state;
67 	iface->if_type = kif->if_type;
68 
69 	/* ipv4 */
70 	iface->ipv4.af = AF_INET;
71 	iface->ipv4.iface = iface;
72 	iface->ipv4.enabled = 0;
73 	iface->ipv4.state = IF_STA_DOWN;
74 	LIST_INIT(&iface->ipv4.adj_list);
75 
76 	/* ipv6 */
77 	iface->ipv6.af = AF_INET6;
78 	iface->ipv6.iface = iface;
79 	iface->ipv6.enabled = 0;
80 	iface->ipv6.state = IF_STA_DOWN;
81 	LIST_INIT(&iface->ipv6.adj_list);
82 
83 	return (iface);
84 }
85 
86 void
if_exit(struct iface * iface)87 if_exit(struct iface *iface)
88 {
89 	struct if_addr		*if_addr;
90 
91 	log_debug("%s: interface %s", __func__, iface->name);
92 
93 	if (iface->ipv4.state == IF_STA_ACTIVE)
94 		if_reset(iface, AF_INET);
95 	if (iface->ipv6.state == IF_STA_ACTIVE)
96 		if_reset(iface, AF_INET6);
97 
98 	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
99 		LIST_REMOVE(if_addr, entry);
100 		free(if_addr);
101 	}
102 }
103 
104 struct iface *
if_lookup(struct ldpd_conf * xconf,unsigned short ifindex)105 if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
106 {
107 	struct iface *iface;
108 
109 	LIST_FOREACH(iface, &xconf->iface_list, entry)
110 		if (iface->ifindex == ifindex)
111 			return (iface);
112 
113 	return (NULL);
114 }
115 
116 struct iface_af *
iface_af_get(struct iface * iface,int af)117 iface_af_get(struct iface *iface, int af)
118 {
119 	switch (af) {
120 	case AF_INET:
121 		return (&iface->ipv4);
122 	case AF_INET6:
123 		return (&iface->ipv6);
124 	default:
125 		fatalx("iface_af_get: unknown af");
126 	}
127 }
128 
129 static struct if_addr *
if_addr_new(struct kaddr * ka)130 if_addr_new(struct kaddr *ka)
131 {
132 	struct if_addr	*if_addr;
133 
134 	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
135 		fatal(__func__);
136 
137 	if_addr->af = ka->af;
138 	if_addr->addr = ka->addr;
139 	if_addr->prefixlen = ka->prefixlen;
140 	if_addr->dstbrd = ka->dstbrd;
141 
142 	return (if_addr);
143 }
144 
145 static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)146 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
147 {
148 	struct if_addr	*if_addr;
149 	int		 af = ka->af;
150 
151 	LIST_FOREACH(if_addr, addr_list, entry)
152 		if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
153 		    if_addr->prefixlen == ka->prefixlen &&
154 		    !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
155 			return (if_addr);
156 
157 	return (NULL);
158 }
159 
160 void
if_addr_add(struct kaddr * ka)161 if_addr_add(struct kaddr *ka)
162 {
163 	struct iface		*iface;
164 	struct if_addr		*if_addr;
165 	struct nbr		*nbr;
166 
167 	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
168 		if_addr = if_addr_new(ka);
169 
170 		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
171 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
172 			if (nbr->state != NBR_STA_OPER)
173 				continue;
174 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
175 				continue;
176 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
177 				continue;
178 
179 			send_address_single(nbr, if_addr, 0);
180 		}
181 	}
182 
183 	iface = if_lookup(leconf, ka->ifindex);
184 	if (iface) {
185 		if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
186 			iface->linklocal = ka->addr.v6;
187 
188 		if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
189 			if_addr = if_addr_new(ka);
190 			LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
191 			if_update(iface, if_addr->af);
192 		}
193 	}
194 }
195 
196 void
if_addr_del(struct kaddr * ka)197 if_addr_del(struct kaddr *ka)
198 {
199 	struct iface		*iface;
200 	struct if_addr		*if_addr;
201 	struct nbr		*nbr;
202 
203 	iface = if_lookup(leconf, ka->ifindex);
204 	if (iface) {
205 		if (ka->af == AF_INET6 &&
206 		    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
207 			memset(&iface->linklocal, 0, sizeof(iface->linklocal));
208 
209 		if_addr = if_addr_lookup(&iface->addr_list, ka);
210 		if (if_addr) {
211 			LIST_REMOVE(if_addr, entry);
212 			if_update(iface, if_addr->af);
213 			free(if_addr);
214 		}
215 	}
216 
217 	if_addr = if_addr_lookup(&global.addr_list, ka);
218 	if (if_addr) {
219 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
220 			if (nbr->state != NBR_STA_OPER)
221 				continue;
222 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
223 				continue;
224 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
225 				continue;
226 			send_address_single(nbr, if_addr, 1);
227 		}
228 		LIST_REMOVE(if_addr, entry);
229 		free(if_addr);
230 	}
231 }
232 
233 static int
if_start(struct iface * iface,int af)234 if_start(struct iface *iface, int af)
235 {
236 	struct iface_af		*ia;
237 	struct timeval		 now;
238 
239 	log_debug("%s: %s address-family %s", __func__, iface->name,
240 	    af_name(af));
241 
242 	ia = iface_af_get(iface, af);
243 
244 	gettimeofday(&now, NULL);
245 	ia->uptime = now.tv_sec;
246 
247 	switch (af) {
248 	case AF_INET:
249 		if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
250 			return (-1);
251 		break;
252 	case AF_INET6:
253 		if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
254 			return (-1);
255 		break;
256 	default:
257 		fatalx("if_start: unknown af");
258 	}
259 
260 	send_hello(HELLO_LINK, ia, NULL);
261 
262 	evtimer_set(&ia->hello_timer, if_hello_timer, ia);
263 	if_start_hello_timer(ia);
264 	return (0);
265 }
266 
267 static int
if_reset(struct iface * iface,int af)268 if_reset(struct iface *iface, int af)
269 {
270 	struct iface_af		*ia;
271 	struct adj		*adj;
272 
273 	log_debug("%s: %s address-family %s", __func__, iface->name,
274 	    af_name(af));
275 
276 	ia = iface_af_get(iface, af);
277 	if_stop_hello_timer(ia);
278 
279 	while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
280 		adj_del(adj, S_SHUTDOWN);
281 
282 	/* try to cleanup */
283 	switch (af) {
284 	case AF_INET:
285 		if (global.ipv4.ldp_disc_socket != -1)
286 			if_leave_ipv4_group(iface, &global.mcast_addr_v4);
287 		break;
288 	case AF_INET6:
289 		if (global.ipv6.ldp_disc_socket != -1)
290 			if_leave_ipv6_group(iface, &global.mcast_addr_v6);
291 		break;
292 	default:
293 		fatalx("if_start: unknown af");
294 	}
295 
296 	return (0);
297 }
298 
299 static void
if_update_af(struct iface_af * ia,int link_ok)300 if_update_af(struct iface_af *ia, int link_ok)
301 {
302 	int			 addr_ok = 0, socket_ok, rtr_id_ok;
303 	struct if_addr		*if_addr;
304 
305 	switch (ia->af) {
306 	case AF_INET:
307 		/*
308 		 * NOTE: for LDPv4, each interface should have at least one
309 		 * valid IP address otherwise they can not be enabled.
310 		 */
311 		LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
312 			if (if_addr->af == AF_INET) {
313 				addr_ok = 1;
314 				break;
315 			}
316 		}
317 		break;
318 	case AF_INET6:
319 		/* for IPv6 the link-local address is enough. */
320 		if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
321 			addr_ok = 1;
322 		break;
323 	default:
324 		fatalx("if_update_af: unknown af");
325 	}
326 
327 	if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
328 		socket_ok = 1;
329 	else
330 		socket_ok = 0;
331 
332 	if (leconf->rtr_id.s_addr != INADDR_ANY)
333 		rtr_id_ok = 1;
334 	else
335 		rtr_id_ok = 0;
336 
337 	if (ia->state == IF_STA_DOWN) {
338 		if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
339 		    !rtr_id_ok)
340 			return;
341 
342 		ia->state = IF_STA_ACTIVE;
343 		if_start(ia->iface, ia->af);
344 	} else if (ia->state == IF_STA_ACTIVE) {
345 		if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
346 			return;
347 
348 		ia->state = IF_STA_DOWN;
349 		if_reset(ia->iface, ia->af);
350 	}
351 }
352 
353 void
if_update(struct iface * iface,int af)354 if_update(struct iface *iface, int af)
355 {
356 	int			 link_ok;
357 
358 	link_ok = (iface->flags & IFF_UP) &&
359 	    LINK_STATE_IS_UP(iface->linkstate);
360 
361 	if (af == AF_INET || af == AF_UNSPEC)
362 		if_update_af(&iface->ipv4, link_ok);
363 	if (af == AF_INET6 || af == AF_UNSPEC)
364 		if_update_af(&iface->ipv6, link_ok);
365 }
366 
367 void
if_update_all(int af)368 if_update_all(int af)
369 {
370 	struct iface		*iface;
371 
372 	LIST_FOREACH(iface, &leconf->iface_list, entry)
373 		if_update(iface, af);
374 }
375 
376 /* timers */
377 static void
if_hello_timer(int fd,short event,void * arg)378 if_hello_timer(int fd, short event, void *arg)
379 {
380 	struct iface_af		*ia = arg;
381 
382 	send_hello(HELLO_LINK, ia, NULL);
383 	if_start_hello_timer(ia);
384 }
385 
386 static void
if_start_hello_timer(struct iface_af * ia)387 if_start_hello_timer(struct iface_af *ia)
388 {
389 	struct timeval		 tv;
390 
391 	timerclear(&tv);
392 	tv.tv_sec = ia->hello_interval;
393 	if (evtimer_add(&ia->hello_timer, &tv) == -1)
394 		fatal(__func__);
395 }
396 
397 static void
if_stop_hello_timer(struct iface_af * ia)398 if_stop_hello_timer(struct iface_af *ia)
399 {
400 	if (evtimer_pending(&ia->hello_timer, NULL) &&
401 	    evtimer_del(&ia->hello_timer) == -1)
402 		fatal(__func__);
403 }
404 
405 struct ctl_iface *
if_to_ctl(struct iface_af * ia)406 if_to_ctl(struct iface_af *ia)
407 {
408 	static struct ctl_iface	 ictl;
409 	struct timeval		 now;
410 	struct adj		*adj;
411 
412 	ictl.af = ia->af;
413 	memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
414 	ictl.ifindex = ia->iface->ifindex;
415 	ictl.state = ia->state;
416 	ictl.flags = ia->iface->flags;
417 	ictl.linkstate = ia->iface->linkstate;
418 	ictl.type = ia->iface->type;
419 	ictl.if_type = ia->iface->if_type;
420 	ictl.hello_holdtime = ia->hello_holdtime;
421 	ictl.hello_interval = ia->hello_interval;
422 
423 	gettimeofday(&now, NULL);
424 	if (ia->state != IF_STA_DOWN &&
425 	    ia->uptime != 0) {
426 		ictl.uptime = now.tv_sec - ia->uptime;
427 	} else
428 		ictl.uptime = 0;
429 
430 	ictl.adj_cnt = 0;
431 	LIST_FOREACH(adj, &ia->adj_list, ia_entry)
432 		ictl.adj_cnt++;
433 
434 	return (&ictl);
435 }
436 
437 /* multicast membership sockopts */
438 in_addr_t
if_get_ipv4_addr(struct iface * iface)439 if_get_ipv4_addr(struct iface *iface)
440 {
441 	struct if_addr		*if_addr;
442 
443 	LIST_FOREACH(if_addr, &iface->addr_list, entry)
444 		if (if_addr->af == AF_INET)
445 			return (if_addr->addr.v4.s_addr);
446 
447 	return (INADDR_ANY);
448 }
449 
450 static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)451 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
452 {
453 	struct ip_mreq		 mreq;
454 
455 	log_debug("%s: interface %s addr %s", __func__, iface->name,
456 	    inet_ntoa(*addr));
457 
458 	mreq.imr_multiaddr = *addr;
459 	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
460 
461 	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
462 	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
463 		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
464 		     __func__, iface->name, inet_ntoa(*addr));
465 		return (-1);
466 	}
467 	return (0);
468 }
469 
470 static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)471 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
472 {
473 	struct ip_mreq		 mreq;
474 
475 	log_debug("%s: interface %s addr %s", __func__, iface->name,
476 	    inet_ntoa(*addr));
477 
478 	mreq.imr_multiaddr = *addr;
479 	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
480 
481 	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
482 	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
483 		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
484 		    "address %s", __func__, iface->name, inet_ntoa(*addr));
485 		return (-1);
486 	}
487 
488 	return (0);
489 }
490 
491 static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)492 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
493 {
494 	struct ipv6_mreq	 mreq;
495 
496 	log_debug("%s: interface %s addr %s", __func__, iface->name,
497 	    log_in6addr(addr));
498 
499 	mreq.ipv6mr_multiaddr = *addr;
500 	mreq.ipv6mr_interface = iface->ifindex;
501 
502 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
503 	    IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
504 		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
505 		    __func__, iface->name, log_in6addr(addr));
506 		return (-1);
507 	}
508 
509 	return (0);
510 }
511 
512 static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)513 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
514 {
515 	struct ipv6_mreq	 mreq;
516 
517 	log_debug("%s: interface %s addr %s", __func__, iface->name,
518 	    log_in6addr(addr));
519 
520 	mreq.ipv6mr_multiaddr = *addr;
521 	mreq.ipv6mr_interface = iface->ifindex;
522 
523 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
524 	    IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) == -1) {
525 		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
526 		    __func__, iface->name, log_in6addr(addr));
527 		return (-1);
528 	}
529 
530 	return (0);
531 }
532