1 /*	$OpenBSD$ */
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 <zebra.h>
22 
23 #include "ldpd.h"
24 #include "ldpe.h"
25 #include "log.h"
26 
27 #include "sockopt.h"
28 
29 static __inline int	 iface_compare(const struct iface *, const struct iface *);
30 static struct if_addr	*if_addr_new(struct kaddr *);
31 static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
32 static int		 if_start(struct iface *, int);
33 static int		 if_reset(struct iface *, int);
34 static void		 if_update_af(struct iface_af *);
35 static int		 if_hello_timer(struct thread *);
36 static void		 if_start_hello_timer(struct iface_af *);
37 static void		 if_stop_hello_timer(struct iface_af *);
38 static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
39 static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
40 static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
41 static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
42 
RB_GENERATE(iface_head,iface,entry,iface_compare)43 RB_GENERATE(iface_head, iface, entry, iface_compare)
44 
45 static __inline int
46 iface_compare(const struct iface *a, const struct iface *b)
47 {
48 	return if_cmp_name_func(a->name, b->name);
49 }
50 
51 struct iface *
if_new(const char * name)52 if_new(const char *name)
53 {
54 	struct iface		*iface;
55 
56 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
57 		fatal("if_new: calloc");
58 
59 	strlcpy(iface->name, name, sizeof(iface->name));
60 
61 	/* ipv4 */
62 	iface->ipv4.af = AF_INET;
63 	iface->ipv4.iface = iface;
64 	iface->ipv4.enabled = 0;
65 
66 	/* ipv6 */
67 	iface->ipv6.af = AF_INET6;
68 	iface->ipv6.iface = iface;
69 	iface->ipv6.enabled = 0;
70 
71 	return (iface);
72 }
73 
74 void
ldpe_if_init(struct iface * iface)75 ldpe_if_init(struct iface *iface)
76 {
77 	log_debug("%s: interface %s", __func__, iface->name);
78 
79 	LIST_INIT(&iface->addr_list);
80 
81 	/* ipv4 */
82 	iface->ipv4.iface = iface;
83 	iface->ipv4.state = IF_STA_DOWN;
84 	RB_INIT(ia_adj_head, &iface->ipv4.adj_tree);
85 
86 	/* ipv6 */
87 	iface->ipv6.iface = iface;
88 	iface->ipv6.state = IF_STA_DOWN;
89 	RB_INIT(ia_adj_head, &iface->ipv6.adj_tree);
90 }
91 
92 void
ldpe_if_exit(struct iface * iface)93 ldpe_if_exit(struct iface *iface)
94 {
95 	struct if_addr		*if_addr;
96 
97 	log_debug("%s: interface %s", __func__, iface->name);
98 
99 	if (iface->ipv4.state == IF_STA_ACTIVE)
100 		if_reset(iface, AF_INET);
101 	if (iface->ipv6.state == IF_STA_ACTIVE)
102 		if_reset(iface, AF_INET6);
103 
104 	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
105 		LIST_REMOVE(if_addr, entry);
106 		assert(if_addr != LIST_FIRST(&iface->addr_list));
107 		free(if_addr);
108 	}
109 }
110 
111 struct iface *
if_lookup(struct ldpd_conf * xconf,ifindex_t ifindex)112 if_lookup(struct ldpd_conf *xconf, ifindex_t ifindex)
113 {
114 	struct iface *iface;
115 
116 	RB_FOREACH(iface, iface_head, &xconf->iface_tree)
117 		if (iface->ifindex == ifindex)
118 			return (iface);
119 
120 	return (NULL);
121 }
122 
123 struct iface *
if_lookup_name(struct ldpd_conf * xconf,const char * ifname)124 if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
125 {
126 	struct iface     iface;
127 	strlcpy(iface.name, ifname, sizeof(iface.name));
128 	return (RB_FIND(iface_head, &xconf->iface_tree, &iface));
129 }
130 
131 void
if_update_info(struct iface * iface,struct kif * kif)132 if_update_info(struct iface *iface, struct kif *kif)
133 {
134 	/* get type */
135 	if (kif->flags & IFF_POINTOPOINT)
136 		iface->type = IF_TYPE_POINTOPOINT;
137 	if (kif->flags & IFF_BROADCAST &&
138 	    kif->flags & IFF_MULTICAST)
139 		iface->type = IF_TYPE_BROADCAST;
140 
141 	/* get index and flags */
142 	iface->ifindex = kif->ifindex;
143 	iface->operative = kif->operative;
144 }
145 
146 struct iface_af *
iface_af_get(struct iface * iface,int af)147 iface_af_get(struct iface *iface, int af)
148 {
149 	switch (af) {
150 	case AF_INET:
151 		return (&iface->ipv4);
152 	case AF_INET6:
153 		return (&iface->ipv6);
154 	default:
155 		fatalx("iface_af_get: unknown af");
156 	}
157 }
158 
159 static struct if_addr *
if_addr_new(struct kaddr * ka)160 if_addr_new(struct kaddr *ka)
161 {
162 	struct if_addr	*if_addr;
163 
164 	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
165 		fatal(__func__);
166 
167 	if_addr->af = ka->af;
168 	if_addr->addr = ka->addr;
169 	if_addr->prefixlen = ka->prefixlen;
170 	if_addr->dstbrd = ka->dstbrd;
171 
172 	return (if_addr);
173 }
174 
175 static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)176 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
177 {
178 	struct if_addr	*if_addr;
179 	int		 af = ka->af;
180 
181 	LIST_FOREACH(if_addr, addr_list, entry)
182 		if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
183 		    if_addr->prefixlen == ka->prefixlen &&
184 		    !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
185 			return (if_addr);
186 
187 	return (NULL);
188 }
189 
190 void
if_addr_add(struct kaddr * ka)191 if_addr_add(struct kaddr *ka)
192 {
193 	struct iface		*iface;
194 	struct if_addr		*if_addr;
195 	struct nbr		*nbr;
196 
197 	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
198 		if_addr = if_addr_new(ka);
199 
200 		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
201 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
202 			if (nbr->state != NBR_STA_OPER)
203 				continue;
204 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
205 				continue;
206 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
207 				continue;
208 
209 			send_address_single(nbr, if_addr, 0);
210 		}
211 	}
212 
213 	iface = if_lookup_name(leconf, ka->ifname);
214 	if (iface) {
215 		if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
216 			iface->linklocal = ka->addr.v6;
217 
218 		if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
219 			if_addr = if_addr_new(ka);
220 			LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
221 			ldp_if_update(iface, if_addr->af);
222 		}
223 	}
224 }
225 
226 void
if_addr_del(struct kaddr * ka)227 if_addr_del(struct kaddr *ka)
228 {
229 	struct iface		*iface;
230 	struct if_addr		*if_addr;
231 	struct nbr		*nbr;
232 
233 	iface = if_lookup_name(leconf, ka->ifname);
234 	if (iface) {
235 		if (ka->af == AF_INET6 &&
236 		    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
237 			memset(&iface->linklocal, 0, sizeof(iface->linklocal));
238 
239 		if_addr = if_addr_lookup(&iface->addr_list, ka);
240 		if (if_addr) {
241 			LIST_REMOVE(if_addr, entry);
242 			ldp_if_update(iface, if_addr->af);
243 			free(if_addr);
244 		}
245 	}
246 
247 	if_addr = if_addr_lookup(&global.addr_list, ka);
248 	if (if_addr) {
249 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
250 			if (nbr->state != NBR_STA_OPER)
251 				continue;
252 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
253 				continue;
254 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
255 				continue;
256 			send_address_single(nbr, if_addr, 1);
257 		}
258 		LIST_REMOVE(if_addr, entry);
259 		free(if_addr);
260 	}
261 }
262 
263 static int
if_start(struct iface * iface,int af)264 if_start(struct iface *iface, int af)
265 {
266 	struct iface_af		*ia;
267 	struct timeval		 now;
268 
269 	log_debug("%s: %s address-family %s", __func__, iface->name,
270 	    af_name(af));
271 
272 	ia = iface_af_get(iface, af);
273 
274 	gettimeofday(&now, NULL);
275 	ia->uptime = now.tv_sec;
276 
277 	switch (af) {
278 	case AF_INET:
279 		if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
280 			return (-1);
281 		break;
282 	case AF_INET6:
283 		if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
284 			return (-1);
285 		break;
286 	default:
287 		fatalx("if_start: unknown af");
288 	}
289 
290 	send_hello(HELLO_LINK, ia, NULL);
291 	if_start_hello_timer(ia);
292 	ia->state = IF_STA_ACTIVE;
293 
294 	return (0);
295 }
296 
297 static int
if_reset(struct iface * iface,int af)298 if_reset(struct iface *iface, int af)
299 {
300 	struct iface_af		*ia;
301 	struct adj		*adj;
302 
303 	log_debug("%s: %s address-family %s", __func__, iface->name,
304 	    af_name(af));
305 
306 	ia = iface_af_get(iface, af);
307 	if_stop_hello_timer(ia);
308 
309 	while (!RB_EMPTY(ia_adj_head, &ia->adj_tree)) {
310 		adj = RB_ROOT(ia_adj_head, &ia->adj_tree);
311 
312 		adj_del(adj, S_SHUTDOWN);
313 	}
314 
315 	/* try to cleanup */
316 	switch (af) {
317 	case AF_INET:
318 		if (global.ipv4.ldp_disc_socket != -1)
319 			if_leave_ipv4_group(iface, &global.mcast_addr_v4);
320 		break;
321 	case AF_INET6:
322 		if (global.ipv6.ldp_disc_socket != -1)
323 			if_leave_ipv6_group(iface, &global.mcast_addr_v6);
324 		break;
325 	default:
326 		fatalx("if_reset: unknown af");
327 	}
328 
329 	ia->state = IF_STA_DOWN;
330 
331 	return (0);
332 }
333 
334 static void
if_update_af(struct iface_af * ia)335 if_update_af(struct iface_af *ia)
336 {
337 	int			 addr_ok = 0, socket_ok, rtr_id_ok;
338 	struct if_addr		*if_addr;
339 
340 	switch (ia->af) {
341 	case AF_INET:
342 		/*
343 		 * NOTE: for LDPv4, each interface should have at least one
344 		 * valid IP address otherwise they can not be enabled.
345 		 */
346 		LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
347 			if (if_addr->af == AF_INET) {
348 				addr_ok = 1;
349 				break;
350 			}
351 		}
352 		break;
353 	case AF_INET6:
354 		/* for IPv6 the link-local address is enough. */
355 		if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
356 			addr_ok = 1;
357 		break;
358 	default:
359 		fatalx("if_update_af: unknown af");
360 	}
361 
362 	if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
363 		socket_ok = 1;
364 	else
365 		socket_ok = 0;
366 
367 	if (ldp_rtr_id_get(leconf) != INADDR_ANY)
368 		rtr_id_ok = 1;
369 	else
370 		rtr_id_ok = 0;
371 
372 	if (ia->state == IF_STA_DOWN) {
373 		if (!ia->enabled || !ia->iface->operative || !addr_ok ||
374 		    !socket_ok || !rtr_id_ok)
375 			return;
376 
377 		if_start(ia->iface, ia->af);
378 	} else if (ia->state == IF_STA_ACTIVE) {
379 		if (ia->enabled && ia->iface->operative && addr_ok &&
380 		    socket_ok && rtr_id_ok)
381 			return;
382 
383 		if_reset(ia->iface, ia->af);
384 	}
385 }
386 
387 void
ldp_if_update(struct iface * iface,int af)388 ldp_if_update(struct iface *iface, int af)
389 {
390 	if (af == AF_INET || af == AF_UNSPEC)
391 		if_update_af(&iface->ipv4);
392 	if (af == AF_INET6 || af == AF_UNSPEC)
393 		if_update_af(&iface->ipv6);
394 }
395 
396 void
if_update_all(int af)397 if_update_all(int af)
398 {
399 	struct iface		*iface;
400 
401 	RB_FOREACH(iface, iface_head, &leconf->iface_tree)
402 		ldp_if_update(iface, af);
403 }
404 
405 uint16_t
if_get_hello_holdtime(struct iface_af * ia)406 if_get_hello_holdtime(struct iface_af *ia)
407 {
408 	if (ia->hello_holdtime != 0)
409 		return (ia->hello_holdtime);
410 
411 	if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
412 		return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
413 
414 	return (leconf->lhello_holdtime);
415 }
416 
417 uint16_t
if_get_hello_interval(struct iface_af * ia)418 if_get_hello_interval(struct iface_af *ia)
419 {
420 	if (ia->hello_interval != 0)
421 		return (ia->hello_interval);
422 
423 	if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
424 		return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
425 
426 	return (leconf->lhello_interval);
427 }
428 
429 /* timers */
430 /* ARGSUSED */
431 static int
if_hello_timer(struct thread * thread)432 if_hello_timer(struct thread *thread)
433 {
434 	struct iface_af		*ia = THREAD_ARG(thread);
435 
436 	ia->hello_timer = NULL;
437 	send_hello(HELLO_LINK, ia, NULL);
438 	if_start_hello_timer(ia);
439 
440 	return (0);
441 }
442 
443 static void
if_start_hello_timer(struct iface_af * ia)444 if_start_hello_timer(struct iface_af *ia)
445 {
446 	THREAD_TIMER_OFF(ia->hello_timer);
447 	ia->hello_timer = NULL;
448 	thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
449 			 &ia->hello_timer);
450 }
451 
452 static void
if_stop_hello_timer(struct iface_af * ia)453 if_stop_hello_timer(struct iface_af *ia)
454 {
455 	THREAD_TIMER_OFF(ia->hello_timer);
456 }
457 
458 struct ctl_iface *
if_to_ctl(struct iface_af * ia)459 if_to_ctl(struct iface_af *ia)
460 {
461 	static struct ctl_iface	 ictl;
462 	struct timeval		 now;
463 	struct adj		*adj;
464 
465 	ictl.af = ia->af;
466 	memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
467 	ictl.ifindex = ia->iface->ifindex;
468 	ictl.state = ia->state;
469 	ictl.type = ia->iface->type;
470 	ictl.hello_holdtime = if_get_hello_holdtime(ia);
471 	ictl.hello_interval = if_get_hello_interval(ia);
472 
473 	gettimeofday(&now, NULL);
474 	if (ia->state != IF_STA_DOWN &&
475 	    ia->uptime != 0) {
476 		ictl.uptime = now.tv_sec - ia->uptime;
477 	} else
478 		ictl.uptime = 0;
479 
480 	ictl.adj_cnt = 0;
481 	RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
482 		ictl.adj_cnt++;
483 
484 	return (&ictl);
485 }
486 
487 /* multicast membership sockopts */
488 in_addr_t
if_get_ipv4_addr(struct iface * iface)489 if_get_ipv4_addr(struct iface *iface)
490 {
491 	struct if_addr		*if_addr;
492 
493 	LIST_FOREACH(if_addr, &iface->addr_list, entry)
494 		if (if_addr->af == AF_INET)
495 			return (if_addr->addr.v4.s_addr);
496 
497 	return (INADDR_ANY);
498 }
499 
500 static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)501 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
502 {
503 	struct in_addr		 if_addr;
504 
505 	log_debug("%s: interface %s addr %s", __func__, iface->name,
506 	    inet_ntoa(*addr));
507 
508 	if_addr.s_addr = if_get_ipv4_addr(iface);
509 
510 	if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
511 	    IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
512 		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
513 		     __func__, iface->name, inet_ntoa(*addr));
514 		return (-1);
515 	}
516 	return (0);
517 }
518 
519 static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)520 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
521 {
522 	struct in_addr		 if_addr;
523 
524 	log_debug("%s: interface %s addr %s", __func__, iface->name,
525 	    inet_ntoa(*addr));
526 
527 	if_addr.s_addr = if_get_ipv4_addr(iface);
528 
529 	if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
530 	    IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
531 		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s address %s", __func__, iface->name, inet_ntoa(*addr));
532 		return (-1);
533 	}
534 
535 	return (0);
536 }
537 
538 static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)539 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
540 {
541 	struct ipv6_mreq	 mreq;
542 
543 	log_debug("%s: interface %s addr %s", __func__, iface->name,
544 	    log_in6addr(addr));
545 
546 	mreq.ipv6mr_multiaddr = *addr;
547 	mreq.ipv6mr_interface = iface->ifindex;
548 
549 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
550 	    IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
551 		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
552 		    __func__, iface->name, log_in6addr(addr));
553 		return (-1);
554 	}
555 
556 	return (0);
557 }
558 
559 static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)560 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
561 {
562 	struct ipv6_mreq	 mreq;
563 
564 	log_debug("%s: interface %s addr %s", __func__, iface->name,
565 	    log_in6addr(addr));
566 
567 	mreq.ipv6mr_multiaddr = *addr;
568 	mreq.ipv6mr_interface = iface->ifindex;
569 
570 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
571 	    IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
572 		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
573 		    __func__, iface->name, log_in6addr(addr));
574 		return (-1);
575 	}
576 
577 	return (0);
578 }
579