xref: /openbsd-src/usr.sbin/ldpd/interface.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: interface.c,v 1.47 2016/07/01 23:29:55 renato 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 *
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->flags = kif->flags;
65 	iface->linkstate = kif->link_state;
66 	iface->if_type = kif->if_type;
67 
68 	/* ipv4 */
69 	iface->ipv4.af = AF_INET;
70 	iface->ipv4.iface = iface;
71 	iface->ipv4.enabled = 0;
72 	iface->ipv4.state = IF_STA_DOWN;
73 	LIST_INIT(&iface->ipv4.adj_list);
74 
75 	/* ipv6 */
76 	iface->ipv6.af = AF_INET6;
77 	iface->ipv6.iface = iface;
78 	iface->ipv6.enabled = 0;
79 	iface->ipv6.state = IF_STA_DOWN;
80 	LIST_INIT(&iface->ipv6.adj_list);
81 
82 	return (iface);
83 }
84 
85 struct iface *
86 if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
87 {
88 	struct iface *iface;
89 
90 	LIST_FOREACH(iface, &xconf->iface_list, entry)
91 		if (iface->ifindex == ifindex)
92 			return (iface);
93 
94 	return (NULL);
95 }
96 
97 void
98 if_exit(struct iface *iface)
99 {
100 	struct if_addr		*if_addr;
101 
102 	log_debug("%s: interface %s", __func__, iface->name);
103 
104 	if (iface->ipv4.state == IF_STA_ACTIVE)
105 		if_reset(iface, AF_INET);
106 	if (iface->ipv6.state == IF_STA_ACTIVE)
107 		if_reset(iface, AF_INET6);
108 
109 	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
110 		LIST_REMOVE(if_addr, entry);
111 		free(if_addr);
112 	}
113 }
114 
115 struct iface_af *
116 iface_af_get(struct iface *iface, int af)
117 {
118 	switch (af) {
119 	case AF_INET:
120 		return (&iface->ipv4);
121 	case AF_INET6:
122 		return (&iface->ipv6);
123 	default:
124 		fatalx("iface_af_get: unknown af");
125 	}
126 }
127 
128 static struct if_addr *
129 if_addr_new(struct kaddr *ka)
130 {
131 	struct if_addr	*if_addr;
132 
133 	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
134 		fatal(__func__);
135 
136 	if_addr->af = ka->af;
137 	if_addr->addr = ka->addr;
138 	if_addr->prefixlen = ka->prefixlen;
139 	if_addr->dstbrd = ka->dstbrd;
140 
141 	return (if_addr);
142 }
143 
144 static struct if_addr *
145 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
146 {
147 	struct if_addr	*if_addr;
148 	int		 af = ka->af;
149 
150 	LIST_FOREACH(if_addr, addr_list, entry)
151 		if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
152 		    if_addr->prefixlen == ka->prefixlen &&
153 		    !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
154 			return (if_addr);
155 
156 	return (NULL);
157 }
158 
159 void
160 if_addr_add(struct kaddr *ka)
161 {
162 	struct iface		*iface;
163 	struct if_addr		*if_addr;
164 	struct nbr		*nbr;
165 
166 	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
167 		if_addr = if_addr_new(ka);
168 
169 		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
170 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
171 			if (nbr->state != NBR_STA_OPER)
172 				continue;
173 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
174 				continue;
175 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
176 				continue;
177 
178 			send_address(nbr, if_addr->af, if_addr, 0);
179 		}
180 	}
181 
182 	iface = if_lookup(leconf, ka->ifindex);
183 	if (iface) {
184 		if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
185 			iface->linklocal = ka->addr.v6;
186 
187 		if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
188 			if_addr = if_addr_new(ka);
189 			LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
190 			if_update(iface, if_addr->af);
191 		}
192 	}
193 }
194 
195 void
196 if_addr_del(struct kaddr *ka)
197 {
198 	struct iface		*iface;
199 	struct if_addr		*if_addr;
200 	struct nbr		*nbr;
201 
202 	iface = if_lookup(leconf, ka->ifindex);
203 	if (iface) {
204 		if (ka->af == AF_INET6 &&
205 		    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
206 			memset(&iface->linklocal, 0, sizeof(iface->linklocal));
207 
208 		if_addr = if_addr_lookup(&iface->addr_list, ka);
209 		if (if_addr) {
210 			LIST_REMOVE(if_addr, entry);
211 			if_update(iface, if_addr->af);
212 			free(if_addr);
213 		}
214 	}
215 
216 	if_addr = if_addr_lookup(&global.addr_list, ka);
217 	if (if_addr) {
218 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
219 			if (nbr->state != NBR_STA_OPER)
220 				continue;
221 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
222 				continue;
223 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
224 				continue;
225 			send_address(nbr, if_addr->af, if_addr, 1);
226 		}
227 		LIST_REMOVE(if_addr, entry);
228 		free(if_addr);
229 	}
230 }
231 
232 static int
233 if_start(struct iface *iface, int af)
234 {
235 	struct iface_af		*ia;
236 	struct timeval		 now;
237 
238 	log_debug("%s: %s address-family %s", __func__, iface->name,
239 	    af_name(af));
240 
241 	ia = iface_af_get(iface, af);
242 
243 	gettimeofday(&now, NULL);
244 	ia->uptime = now.tv_sec;
245 
246 	switch (af) {
247 	case AF_INET:
248 		if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
249 			return (-1);
250 		break;
251 	case AF_INET6:
252 		if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
253 			return (-1);
254 		break;
255 	default:
256 		fatalx("if_start: unknown af");
257 	}
258 
259 	send_hello(HELLO_LINK, ia, NULL);
260 
261 	evtimer_set(&ia->hello_timer, if_hello_timer, ia);
262 	if_start_hello_timer(ia);
263 	return (0);
264 }
265 
266 static int
267 if_reset(struct iface *iface, int af)
268 {
269 	struct iface_af		*ia;
270 	struct adj		*adj;
271 
272 	log_debug("%s: %s address-family %s", __func__, iface->name,
273 	    af_name(af));
274 
275 	ia = iface_af_get(iface, af);
276 	if_stop_hello_timer(ia);
277 
278 	while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
279 		adj_del(adj, S_SHUTDOWN);
280 
281 	/* try to cleanup */
282 	switch (af) {
283 	case AF_INET:
284 		if (global.ipv4.ldp_disc_socket != -1)
285 			if_leave_ipv4_group(iface, &global.mcast_addr_v4);
286 		break;
287 	case AF_INET6:
288 		if (global.ipv6.ldp_disc_socket != -1)
289 			if_leave_ipv6_group(iface, &global.mcast_addr_v6);
290 		break;
291 	default:
292 		fatalx("if_start: unknown af");
293 	}
294 
295 	return (0);
296 }
297 
298 static void
299 if_update_af(struct iface_af *ia, int link_ok)
300 {
301 	int			 addr_ok = 0, socket_ok, rtr_id_ok;
302 	struct if_addr		*if_addr;
303 
304 	switch (ia->af) {
305 	case AF_INET:
306 		/*
307 		 * NOTE: for LDPv4, each interface should have at least one
308 		 * valid IP address otherwise they can not be enabled.
309 		 */
310 		LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
311 			if (if_addr->af == AF_INET) {
312 				addr_ok = 1;
313 				break;
314 			}
315 		}
316 		break;
317 	case AF_INET6:
318 		/* for IPv6 the link-local address is enough. */
319 		if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
320 			addr_ok = 1;
321 		break;
322 	default:
323 		fatalx("if_update_af: unknown af");
324 	}
325 
326 	if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
327 		socket_ok = 1;
328 	else
329 		socket_ok = 0;
330 
331 	if (leconf->rtr_id.s_addr != INADDR_ANY)
332 		rtr_id_ok = 1;
333 	else
334 		rtr_id_ok = 0;
335 
336 	if (ia->state == IF_STA_DOWN) {
337 		if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
338 		    !rtr_id_ok)
339 			return;
340 
341 		ia->state = IF_STA_ACTIVE;
342 		if_start(ia->iface, ia->af);
343 	} else if (ia->state == IF_STA_ACTIVE) {
344 		if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
345 			return;
346 
347 		ia->state = IF_STA_DOWN;
348 		if_reset(ia->iface, ia->af);
349 	}
350 }
351 
352 void
353 if_update(struct iface *iface, int af)
354 {
355 	int			 link_ok;
356 
357 	link_ok = (iface->flags & IFF_UP) &&
358 	    LINK_STATE_IS_UP(iface->linkstate);
359 
360 	if (af == AF_INET || af == AF_UNSPEC)
361 		if_update_af(&iface->ipv4, link_ok);
362 	if (af == AF_INET6 || af == AF_UNSPEC)
363 		if_update_af(&iface->ipv6, link_ok);
364 }
365 
366 void
367 if_update_all(int af)
368 {
369 	struct iface		*iface;
370 
371 	LIST_FOREACH(iface, &leconf->iface_list, entry)
372 		if_update(iface, af);
373 }
374 
375 /* timers */
376 /* ARGSUSED */
377 static void
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
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
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 *
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
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
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)) < 0) {
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
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)) < 0) {
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
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)) < 0) {
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
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)) < 0) {
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