xref: /openbsd-src/usr.sbin/ospf6d/kroute.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: kroute.c,v 1.67 2023/03/08 04:43:14 guenther Exp $ */
2 
3 /*
4  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/sysctl.h>
23 #include <sys/tree.h>
24 #include <sys/uio.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_types.h>
30 #include <net/route.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <limits.h>
39 
40 #include "ospf6d.h"
41 #include "ospfe.h"
42 #include "log.h"
43 
44 struct {
45 	u_int32_t		rtseq;
46 	pid_t			pid;
47 	int			fib_sync;
48 	u_int8_t		fib_prio;
49 	int			fd;
50 	struct event		ev;
51 	u_int			rdomain;
52 } kr_state;
53 
54 struct kroute_node {
55 	RB_ENTRY(kroute_node)	 entry;
56 	struct kroute_node	*next;
57 	struct kroute		 r;
58 };
59 
60 void	kr_redist_remove(struct kroute_node *, struct kroute_node *);
61 int	kr_redist_eval(struct kroute *, struct kroute *);
62 void	kr_redistribute(struct kroute_node *);
63 int	kroute_compare(struct kroute_node *, struct kroute_node *);
64 int	kr_change_fib(struct kroute_node *, struct kroute *, int, int);
65 int	kr_delete_fib(struct kroute_node *);
66 
67 struct kroute_node	*kroute_find(const struct in6_addr *, u_int8_t,
68 			    u_int8_t);
69 struct kroute_node	*kroute_matchgw(struct kroute_node *,
70 			    struct in6_addr *, unsigned int);
71 int			 kroute_insert(struct kroute_node *);
72 int			 kroute_remove(struct kroute_node *);
73 void			 kroute_clear(void);
74 
75 struct iface		*kif_update(u_short, int, struct if_data *,
76 			   struct sockaddr_dl *);
77 int			 kif_validate(u_short);
78 
79 struct kroute_node	*kroute_match(struct in6_addr *);
80 
81 int		protect_lo(void);
82 void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
83 void		if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
84 void		if_newaddr(u_short, struct sockaddr_in6 *,
85 		    struct sockaddr_in6 *, struct sockaddr_in6 *);
86 void		if_deladdr(u_short, struct sockaddr_in6 *,
87 		    struct sockaddr_in6 *, struct sockaddr_in6 *);
88 void		if_announce(void *);
89 
90 int		send_rtmsg(int, int, struct kroute *);
91 int		dispatch_rtmsg(void);
92 int		fetchtable(void);
93 int		rtmsg_process(char *, size_t);
94 
95 RB_HEAD(kroute_tree, kroute_node)	krt;
96 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
97 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
98 
99 int
100 kr_init(int fs, u_int rdomain, int redis_label_or_prefix, u_int8_t fib_prio)
101 {
102 	int		opt = 0, rcvbuf, default_rcvbuf;
103 	socklen_t	optlen;
104 	int		filter_prio = fib_prio;
105 	int		filter_flags = RTF_LLINFO | RTF_BROADCAST;
106 
107 	kr_state.fib_sync = fs;
108 	kr_state.rdomain = rdomain;
109 	kr_state.fib_prio = fib_prio;
110 
111 	if ((kr_state.fd = socket(AF_ROUTE,
112 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, AF_INET6)) == -1) {
113 		log_warn("kr_init: socket");
114 		return (-1);
115 	}
116 
117 	/* not interested in my own messages */
118 	if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
119 	    &opt, sizeof(opt)) == -1)
120 		log_warn("kr_init: setsockopt");	/* not fatal */
121 
122 	if (redis_label_or_prefix) {
123 		filter_prio = 0;
124 		log_info("%s: priority filter disabled", __func__);
125 	} else
126 		log_debug("%s: priority filter enabled", __func__);
127 
128 	if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_PRIOFILTER, &filter_prio,
129 	    sizeof(filter_prio)) == -1) {
130 		log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__);
131 		/* not fatal */
132 	}
133 
134 	if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_FLAGFILTER, &filter_flags,
135 	    sizeof(filter_flags)) == -1) {
136 		log_warn("%s: setsockopt AF_ROUTE ROUTE_FLAGFILTER", __func__);
137 		/* not fatal */
138 	}
139 
140 	/* grow receive buffer, don't wanna miss messages */
141 	optlen = sizeof(default_rcvbuf);
142 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
143 	    &default_rcvbuf, &optlen) == -1)
144 		log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
145 	else
146 		for (rcvbuf = MAX_RTSOCK_BUF;
147 		    rcvbuf > default_rcvbuf &&
148 		    setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
149 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
150 		    rcvbuf /= 2)
151 			;	/* nothing */
152 
153 	kr_state.pid = getpid();
154 	kr_state.rtseq = 1;
155 
156 	RB_INIT(&krt);
157 
158 	if (fetchtable() == -1)
159 		return (-1);
160 
161 	if (protect_lo() == -1)
162 		return (-1);
163 
164 	event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST,
165 	    kr_dispatch_msg, NULL);
166 	event_add(&kr_state.ev, NULL);
167 
168 	return (0);
169 }
170 
171 int
172 kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int krcount,
173     int action)
174 {
175 	int			 i;
176 	struct kroute_node	*kn, *nkn;
177 
178 	if (action == RTM_ADD) {
179 		/*
180 		 * First remove all stale multipath routes.
181 		 * This step must be skipped when the action is RTM_CHANGE
182 		 * because it is already a single path route that will be
183 		 * changed.
184 		 */
185 		for (kn = kr; kn != NULL; kn = nkn) {
186 			for (i = 0; i < krcount; i++) {
187 				if (kn->r.scope == kroute[i].scope &&
188 				    IN6_ARE_ADDR_EQUAL(&kn->r.nexthop,
189 				    &kroute[i].nexthop))
190 					break;
191 			}
192 			nkn = kn->next;
193 			if (i == krcount) {
194 				/* stale route */
195 				if (kr_delete_fib(kn) == -1)
196 					log_warnx("kr_delete_fib failed");
197 				/*
198 				 * if head element was removed we need to adjust
199 				 * the head
200 				 */
201 				if (kr == kn)
202 					kr = nkn;
203 			}
204 		}
205 	}
206 
207 	/*
208 	 * now add or change the route
209 	 */
210 	for (i = 0; i < krcount; i++) {
211 		/* nexthop ::1 -> ignore silently */
212 		if (IN6_IS_ADDR_LOOPBACK(&kroute[i].nexthop))
213 			continue;
214 
215 		if (action == RTM_ADD && kr) {
216 			for (kn = kr; kn != NULL; kn = kn->next) {
217 				if (kn->r.scope == kroute[i].scope &&
218 				    IN6_ARE_ADDR_EQUAL(&kn->r.nexthop,
219 				    &kroute[i].nexthop))
220 					break;
221 			}
222 
223 			if (kn != NULL)
224 				/* nexthop already present, skip it */
225 				continue;
226 		} else
227 			/* modify first entry */
228 			kn = kr;
229 
230 		/* send update */
231 		if (send_rtmsg(kr_state.fd, action, &kroute[i]) == -1)
232 			return (-1);
233 
234 		/* create new entry unless we are changing the first entry */
235 		if (action == RTM_ADD)
236 			if ((kn = calloc(1, sizeof(*kn))) == NULL)
237 				fatal(NULL);
238 
239 		kn->r.prefix = kroute[i].prefix;
240 		kn->r.prefixlen = kroute[i].prefixlen;
241 		kn->r.nexthop = kroute[i].nexthop;
242 		kn->r.scope = kroute[i].scope;
243 		kn->r.flags = kroute[i].flags | F_OSPFD_INSERTED;
244 		kn->r.priority = kr_state.fib_prio;
245 		kn->r.ext_tag = kroute[i].ext_tag;
246 		rtlabel_unref(kn->r.rtlabel);	/* for RTM_CHANGE */
247 		kn->r.rtlabel = kroute[i].rtlabel;
248 
249 		if (action == RTM_ADD)
250 			if (kroute_insert(kn) == -1) {
251 				log_debug("kr_update_fib: cannot insert %s",
252 				    log_in6addr(&kn->r.nexthop));
253 				free(kn);
254 			}
255 		action = RTM_ADD;
256 	}
257 	return  (0);
258 }
259 
260 int
261 kr_change(struct kroute *kroute, int krcount)
262 {
263 	struct kroute_node	*kr;
264 	int			 action = RTM_ADD;
265 
266 	kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag);
267 
268 	kr = kroute_find(&kroute->prefix, kroute->prefixlen, kr_state.fib_prio);
269 	if (kr != NULL && kr->next == NULL && krcount == 1) {
270 		/*
271 		 * single path OSPF route.
272 		 * The kernel does not allow to change a gateway route to a
273 		 * cloning route or contrary. In this case remove and add the
274 		 * route, otherwise change the existing one.
275 		 */
276 		if ((IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop) &&
277 		    !IN6_IS_ADDR_UNSPECIFIED(&kr->r.nexthop)) ||
278 		    (!IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop) &&
279 		    IN6_IS_ADDR_UNSPECIFIED(&kr->r.nexthop))) {
280 			if (kr_delete_fib(kr) == 0)
281 				kr = NULL;
282 			else {
283 				log_warn("kr_change: failed to remove route: "
284 				    "%s/%d", log_in6addr(&kr->r.prefix),
285 				    kr->r.prefixlen);
286 				return (-1);
287 			}
288 		} else
289 			action = RTM_CHANGE;
290 	}
291 
292 	return (kr_change_fib(kr, kroute, krcount, action));
293 }
294 
295 int
296 kr_delete_fib(struct kroute_node *kr)
297 {
298 	if (kr->r.priority != kr_state.fib_prio)
299 		log_warn("kr_delete_fib: %s/%d has wrong priority %d",
300 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen,
301 		    kr->r.priority);
302 
303 	if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r) == -1)
304 		return (-1);
305 
306 	if (kroute_remove(kr) == -1)
307 		return (-1);
308 
309 	return (0);
310 }
311 
312 int
313 kr_delete(struct kroute *kroute)
314 {
315 	struct kroute_node	*kr, *nkr;
316 
317 	if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen,
318 	    kr_state.fib_prio)) == NULL)
319 		return (0);
320 
321 	while (kr != NULL) {
322 		nkr = kr->next;
323 		if (kr_delete_fib(kr) == -1)
324 			return (-1);
325 		kr = nkr;
326 	}
327 
328 	return (0);
329 }
330 
331 void
332 kr_shutdown(void)
333 {
334 	kr_fib_decouple();
335 	kroute_clear();
336 }
337 
338 void
339 kr_fib_couple(void)
340 {
341 	struct kroute_node	*kr;
342 	struct kroute_node	*kn;
343 
344 	if (kr_state.fib_sync == 1)	/* already coupled */
345 		return;
346 
347 	kr_state.fib_sync = 1;
348 
349 	RB_FOREACH(kr, kroute_tree, &krt)
350 		if (kr->r.priority == kr_state.fib_prio)
351 			for (kn = kr; kn != NULL; kn = kn->next)
352 				send_rtmsg(kr_state.fd, RTM_ADD, &kn->r);
353 
354 	log_info("kernel routing table coupled");
355 }
356 
357 void
358 kr_fib_decouple(void)
359 {
360 	struct kroute_node	*kr;
361 	struct kroute_node	*kn;
362 
363 	if (kr_state.fib_sync == 0)	/* already decoupled */
364 		return;
365 
366 	RB_FOREACH(kr, kroute_tree, &krt)
367 		if (kr->r.priority == kr_state.fib_prio)
368 			for (kn = kr; kn != NULL; kn = kn->next)
369 				send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r);
370 
371 	kr_state.fib_sync = 0;
372 
373 	log_info("kernel routing table decoupled");
374 }
375 
376 void
377 kr_fib_update_prio(u_int8_t fib_prio)
378 {
379 	struct kroute_node	*kr;
380 
381 	RB_FOREACH(kr, kroute_tree, &krt)
382 		if ((kr->r.flags & F_OSPFD_INSERTED))
383 			kr->r.priority = fib_prio;
384 
385 	log_info("fib priority changed from %hhu to %hhu", kr_state.fib_prio,
386 	    fib_prio);
387 
388 	kr_state.fib_prio = fib_prio;
389 }
390 
391 void
392 kr_dispatch_msg(int fd, short event, void *bula)
393 {
394 	/* XXX this is stupid */
395 	dispatch_rtmsg();
396 }
397 
398 void
399 kr_show_route(struct imsg *imsg)
400 {
401 	struct kroute_node	*kr;
402 	struct kroute_node	*kn;
403 	int			 flags;
404 	struct in6_addr		 addr;
405 
406 	switch (imsg->hdr.type) {
407 	case IMSG_CTL_KROUTE:
408 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) {
409 			log_warnx("kr_show_route: wrong imsg len");
410 			return;
411 		}
412 		memcpy(&flags, imsg->data, sizeof(flags));
413 		RB_FOREACH(kr, kroute_tree, &krt)
414 			if (!flags || kr->r.flags & flags) {
415 				kn = kr;
416 				do {
417 					main_imsg_compose_ospfe(IMSG_CTL_KROUTE,
418 					    imsg->hdr.pid,
419 					    &kn->r, sizeof(kn->r));
420 				} while ((kn = kn->next) != NULL);
421 			}
422 		break;
423 	case IMSG_CTL_KROUTE_ADDR:
424 		if (imsg->hdr.len != IMSG_HEADER_SIZE +
425 		    sizeof(struct in6_addr)) {
426 			log_warnx("kr_show_route: wrong imsg len");
427 			return;
428 		}
429 		memcpy(&addr, imsg->data, sizeof(addr));
430 		kr = kroute_match(&addr);
431 		if (kr != NULL)
432 			main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid,
433 			    &kr->r, sizeof(kr->r));
434 		break;
435 	default:
436 		log_debug("kr_show_route: error handling imsg");
437 		break;
438 	}
439 
440 	main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
441 }
442 
443 void
444 kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn)
445 {
446 	struct kroute	 *kr;
447 
448 	/* was the route redistributed? */
449 	if ((kn->r.flags & F_REDISTRIBUTED) == 0)
450 		return;
451 
452 	/* remove redistributed flag */
453 	kn->r.flags &= ~F_REDISTRIBUTED;
454 	kr = &kn->r;
455 
456 	/* probably inform the RDE (check if no other path is redistributed) */
457 	for (kn = kh; kn; kn = kn->next)
458 		if (kn->r.flags & F_REDISTRIBUTED)
459 			break;
460 
461 	if (kn == NULL)
462 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr,
463 		    sizeof(struct kroute));
464 }
465 
466 int
467 kr_redist_eval(struct kroute *kr, struct kroute *new_kr)
468 {
469 	u_int32_t	 metric = 0;
470 
471 	/* Only non-ospfd routes are considered for redistribution. */
472 	if (!(kr->flags & F_KERNEL))
473 		goto dont_redistribute;
474 
475 	/* Dynamic routes are not redistributable. */
476 	if (kr->flags & F_DYNAMIC)
477 		goto dont_redistribute;
478 
479 	/* interface is not up and running so don't announce */
480 	if (kr->flags & F_DOWN)
481 		goto dont_redistribute;
482 
483 	/*
484 	 * We consider loopback, multicast, link- and site-local,
485 	 * IPv4 mapped and IPv4 compatible addresses as not redistributable.
486 	 */
487 	if (IN6_IS_ADDR_LOOPBACK(&kr->prefix) ||
488 	    IN6_IS_ADDR_MULTICAST(&kr->prefix) ||
489 	    IN6_IS_ADDR_LINKLOCAL(&kr->prefix) ||
490 	    IN6_IS_ADDR_SITELOCAL(&kr->prefix) ||
491 	    IN6_IS_ADDR_V4MAPPED(&kr->prefix) ||
492 	    IN6_IS_ADDR_V4COMPAT(&kr->prefix))
493 		goto dont_redistribute;
494 	/*
495 	 * Consider networks with nexthop loopback as not redistributable
496 	 * unless it is a reject or blackhole route.
497 	 */
498 	if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop) &&
499 	    !(kr->flags & (F_BLACKHOLE|F_REJECT)))
500 		goto dont_redistribute;
501 
502 	/* Should we redistribute this route? */
503 	if (!ospf_redistribute(kr, &metric))
504 		goto dont_redistribute;
505 
506 	/* prefix should be redistributed */
507 	kr->flags |= F_REDISTRIBUTED;
508 	/*
509 	 * only one of all multipath routes can be redistributed so
510 	 * redistribute the best one.
511 	 */
512 	if (new_kr->metric > metric) {
513 		*new_kr = *kr;
514 		new_kr->metric = metric;
515 	}
516 
517 	return (1);
518 
519 dont_redistribute:
520 	/* was the route redistributed? */
521 	if ((kr->flags & F_REDISTRIBUTED) == 0)
522 		return (0);
523 
524 	kr->flags &= ~F_REDISTRIBUTED;
525 	return (1);
526 }
527 
528 void
529 kr_redistribute(struct kroute_node *kh)
530 {
531 	struct kroute_node	*kn;
532 	struct kroute		 kr;
533 	int			 redistribute = 0;
534 
535 	/* only the highest prio route can be redistributed */
536 	if (kroute_find(&kh->r.prefix, kh->r.prefixlen, RTP_ANY) != kh)
537 		return;
538 
539 	bzero(&kr, sizeof(kr));
540 	kr.metric = UINT_MAX;
541 	for (kn = kh; kn; kn = kn->next)
542 		if (kr_redist_eval(&kn->r, &kr))
543 			redistribute = 1;
544 
545 	if (!redistribute)
546 		return;
547 
548 	if (kr.flags & F_REDISTRIBUTED) {
549 		main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &kr,
550 		    sizeof(struct kroute));
551 	} else {
552 		kr = kh->r;
553 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &kr,
554 		    sizeof(struct kroute));
555 	}
556 }
557 
558 void
559 kr_reload(int redis_label_or_prefix)
560 {
561 	struct kroute_node	*kr, *kn;
562 	u_int32_t		 dummy;
563 	int			 r;
564 	int			 filter_prio = kr_state.fib_prio;
565 
566 	/* update the priority filter */
567 	if (redis_label_or_prefix) {
568 		filter_prio = 0;
569 		log_info("%s: priority filter disabled", __func__);
570 	} else
571 		log_debug("%s: priority filter enabled", __func__);
572 
573 	if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_PRIOFILTER, &filter_prio,
574 	    sizeof(filter_prio)) == -1) {
575 		log_warn("%s: setsockopt AF_ROUTE ROUTE_PRIOFILTER", __func__);
576 		/* not fatal */
577 	}
578 
579 	RB_FOREACH(kr, kroute_tree, &krt) {
580 		for (kn = kr; kn; kn = kn->next) {
581 			r = ospf_redistribute(&kn->r, &dummy);
582 			/*
583 			 * if it is redistributed, redistribute again metric
584 			 * may have changed.
585 			 */
586 			if ((kn->r.flags & F_REDISTRIBUTED && !r) || r)
587 				break;
588 		}
589 		if (kn) {
590 			/*
591 			 * kr_redistribute copes with removes and RDE with
592 			 * duplicates
593 			 */
594 			kr_redistribute(kr);
595 		}
596 	}
597 }
598 
599 /* rb-tree compare */
600 int
601 kroute_compare(struct kroute_node *a, struct kroute_node *b)
602 {
603 	int	i;
604 
605 	/* XXX maybe switch a & b */
606 	i = memcmp(&a->r.prefix, &b->r.prefix, sizeof(a->r.prefix));
607 	if (i)
608 		return (i);
609 	if (a->r.prefixlen < b->r.prefixlen)
610 		return (-1);
611 	if (a->r.prefixlen > b->r.prefixlen)
612 		return (1);
613 
614 	/* if the priority is RTP_ANY finish on the first address hit */
615 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
616 		return (0);
617 	if (a->r.priority < b->r.priority)
618 		return (-1);
619 	if (a->r.priority > b->r.priority)
620 		return (1);
621 	return (0);
622 }
623 
624 /* tree management */
625 struct kroute_node *
626 kroute_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio)
627 {
628 	struct kroute_node	s;
629 	struct kroute_node	*kn, *tmp;
630 
631 	s.r.prefix = *prefix;
632 	s.r.prefixlen = prefixlen;
633 	s.r.priority = prio;
634 
635 	kn = RB_FIND(kroute_tree, &krt, &s);
636 	if (kn && prio == RTP_ANY) {
637 		tmp = RB_PREV(kroute_tree, &krt, kn);
638 		while (tmp) {
639 			if (kroute_compare(&s, tmp) == 0)
640 				kn = tmp;
641 			else
642 				break;
643 			tmp = RB_PREV(kroute_tree, &krt, kn);
644 		}
645 	}
646 	return (kn);
647 }
648 
649 struct kroute_node *
650 kroute_matchgw(struct kroute_node *kr, struct in6_addr *nh, unsigned int scope)
651 {
652 	while (kr) {
653 		if (scope == kr->r.scope &&
654 		    IN6_ARE_ADDR_EQUAL(&kr->r.nexthop, nh))
655 			return (kr);
656 		kr = kr->next;
657 	}
658 
659 	return (NULL);
660 }
661 
662 int
663 kroute_insert(struct kroute_node *kr)
664 {
665 	struct kroute_node	*krm, *krh;
666 
667 	if ((krh = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
668 		/*
669 		 * Multipath route, add at end of list.
670 		 */
671 		krm = krh;
672 		while (krm->next != NULL)
673 			krm = krm->next;
674 		krm->next = kr;
675 		kr->next = NULL; /* to be sure */
676 	} else
677 		krh = kr;
678 
679 	if (!(kr->r.flags & F_KERNEL)) {
680 		/* don't validate or redistribute ospf route */
681 		kr->r.flags &= ~F_DOWN;
682 		return (0);
683 	}
684 
685 	if (kif_validate(kr->r.ifindex))
686 		kr->r.flags &= ~F_DOWN;
687 	else
688 		kr->r.flags |= F_DOWN;
689 
690 	kr_redistribute(krh);
691 	return (0);
692 }
693 
694 int
695 kroute_remove(struct kroute_node *kr)
696 {
697 	struct kroute_node	*krm;
698 
699 	if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) {
700 		log_warnx("kroute_remove failed to find %s/%u",
701 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
702 		return (-1);
703 	}
704 
705 	if (krm == kr) {
706 		/* head element */
707 		if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) {
708 			log_warnx("kroute_remove failed for %s/%u",
709 			    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
710 			return (-1);
711 		}
712 		if (kr->next != NULL) {
713 			if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) {
714 				log_warnx("kroute_remove failed to add %s/%u",
715 				    log_in6addr(&kr->r.prefix),
716 				    kr->r.prefixlen);
717 				return (-1);
718 			}
719 		}
720 	} else {
721 		/* somewhere in the list */
722 		while (krm->next != kr && krm->next != NULL)
723 			krm = krm->next;
724 		if (krm->next == NULL) {
725 			log_warnx("kroute_remove multipath list corrupted "
726 			    "for %s/%u", log_in6addr(&kr->r.prefix),
727 			    kr->r.prefixlen);
728 			return (-1);
729 		}
730 		krm->next = kr->next;
731 	}
732 
733 	kr_redist_remove(krm, kr);
734 	rtlabel_unref(kr->r.rtlabel);
735 
736 	free(kr);
737 	return (0);
738 }
739 
740 void
741 kroute_clear(void)
742 {
743 	struct kroute_node	*kr;
744 
745 	while ((kr = RB_MIN(kroute_tree, &krt)) != NULL)
746 		kroute_remove(kr);
747 }
748 
749 struct iface *
750 kif_update(u_short ifindex, int flags, struct if_data *ifd,
751     struct sockaddr_dl *sdl)
752 {
753 	struct iface	*iface;
754 	char		 ifname[IF_NAMESIZE];
755 
756 	if ((iface = if_find(ifindex)) == NULL) {
757 		bzero(ifname, sizeof(ifname));
758 		if (sdl && sdl->sdl_family == AF_LINK) {
759 			if (sdl->sdl_nlen >= sizeof(ifname))
760 				memcpy(ifname, sdl->sdl_data,
761 				    sizeof(ifname) - 1);
762 			else if (sdl->sdl_nlen > 0)
763 				memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
764 			else
765 				return (NULL);
766 		} else
767 			return (NULL);
768 		if ((iface = if_new(ifindex, ifname)) == NULL)
769 			return (NULL);
770 	}
771 
772 	if_update(iface, ifd->ifi_mtu, flags, ifd->ifi_type,
773 	    ifd->ifi_link_state, ifd->ifi_baudrate, ifd->ifi_rdomain);
774 
775 	return (iface);
776 }
777 
778 int
779 kif_validate(u_short ifindex)
780 {
781 	struct iface	*iface;
782 
783 	if ((iface = if_find(ifindex)) == NULL) {
784 		log_warnx("interface with index %u not found", ifindex);
785 		return (-1);
786 	}
787 
788 	return ((iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate));
789 }
790 
791 struct kroute_node *
792 kroute_match(struct in6_addr *key)
793 {
794 	int			 i;
795 	struct kroute_node	*kr;
796 	struct in6_addr		 ina;
797 
798 	/* we will never match the default route */
799 	for (i = 128; i > 0; i--) {
800 		inet6applymask(&ina, key, i);
801 		if ((kr = kroute_find(&ina, i, RTP_ANY)) != NULL)
802 			return (kr);
803 	}
804 
805 	/* if we don't have a match yet, try to find a default route */
806 	if ((kr = kroute_find(&in6addr_any, 0, RTP_ANY)) != NULL)
807 			return (kr);
808 
809 	return (NULL);
810 }
811 
812 /* misc */
813 int
814 protect_lo(void)
815 {
816 	struct kroute_node	*kr;
817 
818 	/* special protection for loopback */
819 	if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
820 		log_warn("protect_lo");
821 		return (-1);
822 	}
823 	memcpy(&kr->r.prefix, &in6addr_loopback, sizeof(kr->r.prefix));
824 	kr->r.prefixlen = 128;
825 	kr->r.flags = F_KERNEL|F_CONNECTED;
826 
827 	if (RB_INSERT(kroute_tree, &krt, kr) != NULL)
828 		free(kr);	/* kernel route already there, no problem */
829 
830 	return (0);
831 }
832 
833 #define ROUNDUP(a) \
834 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
835 
836 void
837 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
838 {
839 	int	i;
840 
841 	for (i = 0; i < RTAX_MAX; i++) {
842 		if (addrs & (1 << i)) {
843 			rti_info[i] = sa;
844 			sa = (struct sockaddr *)((char *)(sa) +
845 			    ROUNDUP(sa->sa_len));
846 		} else
847 			rti_info[i] = NULL;
848 	}
849 }
850 
851 void
852 if_change(u_short ifindex, int flags, struct if_data *ifd,
853     struct sockaddr_dl *sdl)
854 {
855 	struct kroute_node	*kr, *tkr;
856 	struct iface		*iface;
857 	u_int8_t		 wasvalid, isvalid;
858 
859 	wasvalid = kif_validate(ifindex);
860 
861 	if ((iface = kif_update(ifindex, flags, ifd, sdl)) == NULL) {
862 		log_warn("if_change: kif_update(%u)", ifindex);
863 		return;
864 	}
865 
866 	/* inform engine and rde about state change */
867 	main_imsg_compose_rde(IMSG_IFINFO, 0, iface, sizeof(struct iface));
868 	main_imsg_compose_ospfe(IMSG_IFINFO, 0, iface, sizeof(struct iface));
869 
870 	isvalid = (iface->flags & IFF_UP) &&
871 	    LINK_STATE_IS_UP(iface->linkstate);
872 
873 	if (wasvalid == isvalid)
874 		return;		/* nothing changed wrt validity */
875 
876 	/* update redistribute list */
877 	RB_FOREACH(kr, kroute_tree, &krt) {
878 		for (tkr = kr; tkr != NULL; tkr = tkr->next) {
879 			if (tkr->r.ifindex == ifindex) {
880 				if (isvalid)
881 					tkr->r.flags &= ~F_DOWN;
882 				else
883 					tkr->r.flags |= F_DOWN;
884 
885 			}
886 		}
887 		kr_redistribute(kr);
888 	}
889 }
890 
891 void
892 if_newaddr(u_short ifindex, struct sockaddr_in6 *ifa, struct sockaddr_in6 *mask,
893     struct sockaddr_in6 *brd)
894 {
895 	struct iface		*iface;
896 	struct iface_addr	*ia;
897 	struct ifaddrchange	 ifc;
898 
899 	if (ifa == NULL || ifa->sin6_family != AF_INET6)
900 		return;
901 	if ((iface = if_find(ifindex)) == NULL) {
902 		log_warnx("if_newaddr: corresponding if %d not found", ifindex);
903 		return;
904 	}
905 
906 	/* We only care about link-local and global-scope. */
907 	if (IN6_IS_ADDR_UNSPECIFIED(&ifa->sin6_addr) ||
908 	    IN6_IS_ADDR_LOOPBACK(&ifa->sin6_addr) ||
909 	    IN6_IS_ADDR_MULTICAST(&ifa->sin6_addr) ||
910 	    IN6_IS_ADDR_SITELOCAL(&ifa->sin6_addr) ||
911 	    IN6_IS_ADDR_V4MAPPED(&ifa->sin6_addr) ||
912 	    IN6_IS_ADDR_V4COMPAT(&ifa->sin6_addr))
913 		return;
914 
915 	clearscope(&ifa->sin6_addr);
916 
917 	if (IN6_IS_ADDR_LINKLOCAL(&ifa->sin6_addr) ||
918 	    iface->flags & IFF_LOOPBACK)
919 		iface->addr = ifa->sin6_addr;
920 
921 	if ((ia = calloc(1, sizeof(struct iface_addr))) == NULL)
922 		fatal("if_newaddr");
923 
924 	ia->addr = ifa->sin6_addr;
925 
926 	if (mask)
927 		ia->prefixlen = mask2prefixlen(mask);
928 	else
929 		ia->prefixlen = 0;
930 	if (brd && brd->sin6_family == AF_INET6)
931 		ia->dstbrd = brd->sin6_addr;
932 	else
933 		bzero(&ia->dstbrd, sizeof(ia->dstbrd));
934 
935 	switch (iface->type) {
936 	case IF_TYPE_BROADCAST:
937 	case IF_TYPE_NBMA:
938 		log_debug("if_newaddr: ifindex %u, addr %s/%d",
939 		    ifindex, log_in6addr(&ia->addr), ia->prefixlen);
940 		break;
941 	case IF_TYPE_VIRTUALLINK:	/* FIXME */
942 		break;
943 	case IF_TYPE_POINTOPOINT:
944 	case IF_TYPE_POINTOMULTIPOINT:
945 		log_debug("if_newaddr: ifindex %u, addr %s/%d, "
946 		    "dest %s", ifindex, log_in6addr(&ia->addr),
947 		    ia->prefixlen, log_in6addr(&ia->dstbrd));
948 		break;
949 	default:
950 		fatalx("if_newaddr: unknown interface type");
951 	}
952 
953 	TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry);
954 	/* inform engine and rde if interface is used */
955 	if (iface->cflags & F_IFACE_CONFIGURED) {
956 		ifc.addr = ia->addr;
957 		ifc.dstbrd = ia->dstbrd;
958 		ifc.prefixlen = ia->prefixlen;
959 		ifc.ifindex = ifindex;
960 		main_imsg_compose_ospfe(IMSG_IFADDRNEW, 0, &ifc, sizeof(ifc));
961 		main_imsg_compose_rde(IMSG_IFADDRNEW, 0, &ifc, sizeof(ifc));
962 	}
963 }
964 
965 void
966 if_deladdr(u_short ifindex, struct sockaddr_in6 *ifa, struct sockaddr_in6 *mask,
967     struct sockaddr_in6 *brd)
968 {
969 	struct iface		*iface;
970 	struct iface_addr	*ia, *nia;
971 	struct ifaddrchange	 ifc;
972 
973 	if (ifa == NULL || ifa->sin6_family != AF_INET6)
974 		return;
975 	if ((iface = if_find(ifindex)) == NULL) {
976 		log_warnx("if_deladdr: corresponding if %d not found", ifindex);
977 		return;
978 	}
979 
980 	/* We only care about link-local and global-scope. */
981 	if (IN6_IS_ADDR_UNSPECIFIED(&ifa->sin6_addr) ||
982 	    IN6_IS_ADDR_LOOPBACK(&ifa->sin6_addr) ||
983 	    IN6_IS_ADDR_MULTICAST(&ifa->sin6_addr) ||
984 	    IN6_IS_ADDR_SITELOCAL(&ifa->sin6_addr) ||
985 	    IN6_IS_ADDR_V4MAPPED(&ifa->sin6_addr) ||
986 	    IN6_IS_ADDR_V4COMPAT(&ifa->sin6_addr))
987 		return;
988 
989 	clearscope(&ifa->sin6_addr);
990 
991 	for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL; ia = nia) {
992 		nia = TAILQ_NEXT(ia, entry);
993 
994 		if (IN6_ARE_ADDR_EQUAL(&ia->addr, &ifa->sin6_addr)) {
995 			log_debug("if_deladdr: ifindex %u, addr %s/%d",
996 			    ifindex, log_in6addr(&ia->addr), ia->prefixlen);
997 			TAILQ_REMOVE(&iface->ifa_list, ia, entry);
998 			/* inform engine and rde if interface is used */
999 			if (iface->cflags & F_IFACE_CONFIGURED) {
1000 				ifc.addr = ia->addr;
1001 				ifc.dstbrd = ia->dstbrd;
1002 				ifc.prefixlen = ia->prefixlen;
1003 				ifc.ifindex = ifindex;
1004 				main_imsg_compose_ospfe(IMSG_IFADDRDEL, 0, &ifc,
1005 				    sizeof(ifc));
1006 				main_imsg_compose_rde(IMSG_IFADDRDEL, 0, &ifc,
1007 				    sizeof(ifc));
1008 			}
1009 			free(ia);
1010 			return;
1011 		}
1012 	}
1013 }
1014 
1015 void
1016 if_announce(void *msg)
1017 {
1018 	struct if_announcemsghdr	*ifan;
1019 	struct iface			*iface;
1020 
1021 	ifan = msg;
1022 
1023 	switch (ifan->ifan_what) {
1024 	case IFAN_ARRIVAL:
1025 		if ((iface = if_new(ifan->ifan_index, ifan->ifan_name)) == NULL)
1026 			fatal("if_announce failed");
1027 		break;
1028 	case IFAN_DEPARTURE:
1029 		iface = if_find(ifan->ifan_index);
1030 		if_del(iface);
1031 		break;
1032 	}
1033 }
1034 
1035 /* rtsock */
1036 int
1037 send_rtmsg(int fd, int action, struct kroute *kroute)
1038 {
1039 	struct iovec		iov[5];
1040 	struct rt_msghdr	hdr;
1041 	struct pad {
1042 		struct sockaddr_in6	addr;
1043 		char			pad[sizeof(long)]; /* thank you IPv6 */
1044 	} prefix, nexthop, mask;
1045 	struct {
1046 		struct sockaddr_dl	addr;
1047 		char			pad[sizeof(long)];
1048 	} ifp;
1049 	struct sockaddr_rtlabel	sa_rl;
1050 	int			iovcnt = 0;
1051 	const char		*label;
1052 
1053 	if (kr_state.fib_sync == 0)
1054 		return (0);
1055 
1056 	/* initialize header */
1057 	bzero(&hdr, sizeof(hdr));
1058 	hdr.rtm_version = RTM_VERSION;
1059 	hdr.rtm_type = action;
1060 	hdr.rtm_priority = kr_state.fib_prio;
1061 	hdr.rtm_tableid = kr_state.rdomain;	/* rtableid */
1062 	if (action == RTM_CHANGE)
1063 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
1064 	else
1065 		hdr.rtm_flags = RTF_MPATH;
1066 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
1067 	hdr.rtm_hdrlen = sizeof(hdr);
1068 	hdr.rtm_msglen = sizeof(hdr);
1069 	/* adjust iovec */
1070 	iov[iovcnt].iov_base = &hdr;
1071 	iov[iovcnt++].iov_len = sizeof(hdr);
1072 
1073 	bzero(&prefix, sizeof(prefix));
1074 	prefix.addr.sin6_len = sizeof(struct sockaddr_in6);
1075 	prefix.addr.sin6_family = AF_INET6;
1076 	prefix.addr.sin6_addr = kroute->prefix;
1077 	/* adjust header */
1078 	hdr.rtm_addrs |= RTA_DST;
1079 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
1080 	/* adjust iovec */
1081 	iov[iovcnt].iov_base = &prefix;
1082 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
1083 
1084 	if (!IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop)) {
1085 		bzero(&nexthop, sizeof(nexthop));
1086 		nexthop.addr.sin6_len = sizeof(struct sockaddr_in6);
1087 		nexthop.addr.sin6_family = AF_INET6;
1088 		nexthop.addr.sin6_addr = kroute->nexthop;
1089 		nexthop.addr.sin6_scope_id = kroute->scope;
1090 		/*
1091 		 * XXX we should set the sin6_scope_id but the kernel
1092 		 * XXX does not expect it that way. It must be fiddled
1093 		 * XXX into the sin6_addr. Welcome to the typical
1094 		 * XXX IPv6 insanity and all without wine bottles.
1095 		 */
1096 		embedscope(&nexthop.addr);
1097 
1098 		/* adjust header */
1099 		hdr.rtm_flags |= RTF_GATEWAY;
1100 		hdr.rtm_addrs |= RTA_GATEWAY;
1101 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
1102 		/* adjust iovec */
1103 		iov[iovcnt].iov_base = &nexthop;
1104 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
1105 	} else if (kroute->ifindex) {
1106 		/*
1107 		 * We don't have an interface address in that network,
1108 		 * so we install a cloning route.  The kernel will then
1109 		 * do neighbor discovery.
1110 		 */
1111 		bzero(&ifp, sizeof(ifp));
1112 		ifp.addr.sdl_len = sizeof(struct sockaddr_dl);
1113 		ifp.addr.sdl_family = AF_LINK;
1114 
1115 		ifp.addr.sdl_index  = kroute->ifindex;
1116 		/* adjust header */
1117 		hdr.rtm_flags |= RTF_CLONING;
1118 		hdr.rtm_addrs |= RTA_GATEWAY;
1119 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
1120 		/* adjust iovec */
1121 		iov[iovcnt].iov_base = &ifp;
1122 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
1123 	}
1124 
1125 	bzero(&mask, sizeof(mask));
1126 	mask.addr.sin6_len = sizeof(struct sockaddr_in6);
1127 	mask.addr.sin6_family = AF_INET6;
1128 	mask.addr.sin6_addr = *prefixlen2mask(kroute->prefixlen);
1129 	/* adjust header */
1130 	if (kroute->prefixlen == 128)
1131 		hdr.rtm_flags |= RTF_HOST;
1132 	hdr.rtm_addrs |= RTA_NETMASK;
1133 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
1134 	/* adjust iovec */
1135 	iov[iovcnt].iov_base = &mask;
1136 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
1137 
1138 	if (kroute->rtlabel != 0) {
1139 		sa_rl.sr_len = sizeof(sa_rl);
1140 		sa_rl.sr_family = AF_UNSPEC;
1141 		label = rtlabel_id2name(kroute->rtlabel);
1142 		if (strlcpy(sa_rl.sr_label, label,
1143 		    sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) {
1144 			log_warnx("send_rtmsg: invalid rtlabel");
1145 			return (-1);
1146 		}
1147 		/* adjust header */
1148 		hdr.rtm_addrs |= RTA_LABEL;
1149 		hdr.rtm_msglen += sizeof(sa_rl);
1150 		/* adjust iovec */
1151 		iov[iovcnt].iov_base = &sa_rl;
1152 		iov[iovcnt++].iov_len = sizeof(sa_rl);
1153 	}
1154 
1155 retry:
1156 	if (writev(fd, iov, iovcnt) == -1) {
1157 		if (errno == ESRCH) {
1158 			if (hdr.rtm_type == RTM_CHANGE) {
1159 				hdr.rtm_type = RTM_ADD;
1160 				goto retry;
1161 			} else if (hdr.rtm_type == RTM_DELETE) {
1162 				log_info("route %s/%u vanished before delete",
1163 				    log_sockaddr(&prefix), kroute->prefixlen);
1164 				return (0);
1165 			}
1166 		}
1167 		log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type,
1168 		    log_sockaddr(&prefix), kroute->prefixlen);
1169 		return (0);
1170 	}
1171 
1172 	return (0);
1173 }
1174 
1175 int
1176 fetchtable(void)
1177 {
1178 	size_t			 len;
1179 	int			 mib[7];
1180 	char			*buf;
1181 	int			 rv;
1182 
1183 	mib[0] = CTL_NET;
1184 	mib[1] = PF_ROUTE;
1185 	mib[2] = 0;
1186 	mib[3] = AF_INET6;
1187 	mib[4] = NET_RT_DUMP;
1188 	mib[5] = 0;
1189 	mib[6] = kr_state.rdomain;	/* rtableid */
1190 
1191 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1192 		log_warn("sysctl");
1193 		return (-1);
1194 	}
1195 	if ((buf = malloc(len)) == NULL) {
1196 		log_warn("fetchtable");
1197 		return (-1);
1198 	}
1199 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1200 		log_warn("sysctl");
1201 		free(buf);
1202 		return (-1);
1203 	}
1204 
1205 	rv = rtmsg_process(buf, len);
1206 	free(buf);
1207 
1208 	return (rv);
1209 }
1210 
1211 int
1212 fetchifs(u_short ifindex)
1213 {
1214 	size_t			 len;
1215 	int			 mib[6];
1216 	char			*buf;
1217 	int			 rv;
1218 
1219 	mib[0] = CTL_NET;
1220 	mib[1] = PF_ROUTE;
1221 	mib[2] = 0;
1222 	mib[3] = AF_INET6;
1223 	mib[4] = NET_RT_IFLIST;
1224 	mib[5] = ifindex;
1225 
1226 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
1227 		log_warn("sysctl");
1228 		return (-1);
1229 	}
1230 	if ((buf = malloc(len)) == NULL) {
1231 		log_warn("fetchifs");
1232 		return (-1);
1233 	}
1234 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
1235 		log_warn("sysctl");
1236 		free(buf);
1237 		return (-1);
1238 	}
1239 
1240 	rv = rtmsg_process(buf, len);
1241 	free(buf);
1242 
1243 	return (rv);
1244 }
1245 
1246 int
1247 dispatch_rtmsg(void)
1248 {
1249 	char			 buf[RT_BUF_SIZE];
1250 	ssize_t			 n;
1251 
1252 	if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1253 		if (errno == EAGAIN || errno == EINTR)
1254 			return (0);
1255 		log_warn("dispatch_rtmsg: read error");
1256 		return (-1);
1257 	}
1258 
1259 	if (n == 0) {
1260 		log_warnx("routing socket closed");
1261 		return (-1);
1262 	}
1263 
1264 	return (rtmsg_process(buf, n));
1265 }
1266 
1267 int
1268 rtmsg_process(char *buf, size_t len)
1269 {
1270 	struct rt_msghdr	*rtm;
1271 	struct if_msghdr	 ifm;
1272 	struct ifa_msghdr	*ifam;
1273 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1274 	struct sockaddr_in6	*sa_in6;
1275 	struct sockaddr_rtlabel	*label;
1276 	struct kroute_node	*kr, *okr;
1277 	struct in6_addr		 prefix, nexthop;
1278 	u_int8_t		 prefixlen, prio;
1279 	int			 flags, mpath;
1280 	unsigned int		 scope;
1281 	u_short			 ifindex = 0;
1282 	int			 rv;
1283 	size_t			 offset;
1284 	char			*next;
1285 
1286 	for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
1287 		next = buf + offset;
1288 		rtm = (struct rt_msghdr *)next;
1289 		if (len < offset + sizeof(u_short) ||
1290 		    len < offset + rtm->rtm_msglen)
1291 			fatalx("rtmsg_process: partial rtm in buffer");
1292 		if (rtm->rtm_version != RTM_VERSION)
1293 			continue;
1294 
1295 		bzero(&prefix, sizeof(prefix));
1296 		bzero(&nexthop, sizeof(nexthop));
1297 		scope = 0;
1298 		prefixlen = 0;
1299 		flags = F_KERNEL;
1300 		mpath = 0;
1301 		prio = 0;
1302 
1303 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1304 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1305 
1306 		switch (rtm->rtm_type) {
1307 		case RTM_ADD:
1308 		case RTM_GET:
1309 		case RTM_CHANGE:
1310 		case RTM_DELETE:
1311 			if (rtm->rtm_errno)		/* failed attempts... */
1312 				continue;
1313 
1314 			if (rtm->rtm_tableid != kr_state.rdomain)
1315 				continue;
1316 
1317 			if (rtm->rtm_type == RTM_GET &&
1318 			    rtm->rtm_pid != kr_state.pid) /* caused by us */
1319 				continue;
1320 
1321 			if ((sa = rti_info[RTAX_DST]) == NULL)
1322 				continue;
1323 
1324 			/* Skip ARP/ND cache and broadcast routes. */
1325 			if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
1326 				continue;
1327 
1328 			if (rtm->rtm_flags & RTF_MPATH)
1329 				mpath = 1;
1330 			prio = rtm->rtm_priority;
1331 			flags = (prio == kr_state.fib_prio) ?
1332 			    F_OSPFD_INSERTED : F_KERNEL;
1333 
1334 			switch (sa->sa_family) {
1335 			case AF_INET6:
1336 				prefix =
1337 				    ((struct sockaddr_in6 *)sa)->sin6_addr;
1338 				sa_in6 = (struct sockaddr_in6 *)
1339 				    rti_info[RTAX_NETMASK];
1340 				if (sa_in6 != NULL) {
1341 					if (sa_in6->sin6_len != 0)
1342 						prefixlen = mask2prefixlen(
1343 						    sa_in6);
1344 				} else if (rtm->rtm_flags & RTF_HOST)
1345 					prefixlen = 128;
1346 				else
1347 					fatalx("classful IPv6 address?!!");
1348 				if (rtm->rtm_flags & RTF_STATIC)
1349 					flags |= F_STATIC;
1350 				if (rtm->rtm_flags & RTF_BLACKHOLE)
1351 					flags |= F_BLACKHOLE;
1352 				if (rtm->rtm_flags & RTF_REJECT)
1353 					flags |= F_REJECT;
1354 				if (rtm->rtm_flags & RTF_DYNAMIC)
1355 					flags |= F_DYNAMIC;
1356 				break;
1357 			default:
1358 				continue;
1359 			}
1360 
1361 			ifindex = rtm->rtm_index;
1362 			if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
1363 				switch (sa->sa_family) {
1364 				case AF_INET6:
1365 					if (rtm->rtm_flags & RTF_CONNECTED)
1366 						flags |= F_CONNECTED;
1367 
1368 					sa_in6 = (struct sockaddr_in6 *)sa;
1369 					/*
1370 					 * XXX The kernel provides the scope
1371 					 * XXX via the kame hack instead of
1372 					 * XXX the scope_id field.
1373 					 */
1374 					recoverscope(sa_in6);
1375 					nexthop = sa_in6->sin6_addr;
1376 					scope = sa_in6->sin6_scope_id;
1377 					break;
1378 				case AF_LINK:
1379 					flags |= F_CONNECTED;
1380 					break;
1381 				}
1382 			}
1383 		}
1384 
1385 		switch (rtm->rtm_type) {
1386 		case RTM_ADD:
1387 		case RTM_GET:
1388 		case RTM_CHANGE:
1389 			if (IN6_IS_ADDR_UNSPECIFIED(&nexthop) &&
1390 			    !(flags & F_CONNECTED)) {
1391 				log_warnx("rtmsg_process no nexthop for %s/%u",
1392 				    log_in6addr(&prefix), prefixlen);
1393 				continue;
1394 			}
1395 
1396 			if ((okr = kroute_find(&prefix, prefixlen, prio))
1397 			    != NULL) {
1398 				/* just add new multipath routes */
1399 				if (mpath && rtm->rtm_type == RTM_ADD)
1400 					goto add;
1401 				/* get the correct route */
1402 				kr = okr;
1403 				if (mpath && (kr = kroute_matchgw(okr,
1404 				    &nexthop, scope)) == NULL) {
1405 					log_warnx("rtmsg_process: mpath route"
1406 					    " not found");
1407 					/* add routes we missed out earlier */
1408 					goto add;
1409 				}
1410 
1411 				if (kr->r.flags & F_REDISTRIBUTED)
1412 					flags |= F_REDISTRIBUTED;
1413 				kr->r.nexthop = nexthop;
1414 				kr->r.scope = scope;
1415 				kr->r.flags = flags;
1416 				kr->r.ifindex = ifindex;
1417 
1418 				rtlabel_unref(kr->r.rtlabel);
1419 				kr->r.rtlabel = 0;
1420 				kr->r.ext_tag = 0;
1421 				if ((label = (struct sockaddr_rtlabel *)
1422 				    rti_info[RTAX_LABEL]) != NULL) {
1423 					kr->r.rtlabel =
1424 					    rtlabel_name2id(label->sr_label);
1425 					kr->r.ext_tag =
1426 					    rtlabel_id2tag(kr->r.rtlabel);
1427 				}
1428 
1429 				if (kif_validate(kr->r.ifindex))
1430 					kr->r.flags &= ~F_DOWN;
1431 				else
1432 					kr->r.flags |= F_DOWN;
1433 
1434 				/* just readd, the RDE will care */
1435 				kr_redistribute(okr);
1436 			} else {
1437 add:
1438 				if ((kr = calloc(1,
1439 				    sizeof(struct kroute_node))) == NULL) {
1440 					log_warn("rtmsg_process calloc");
1441 					return (-1);
1442 				}
1443 				kr->r.prefix = prefix;
1444 				kr->r.prefixlen = prefixlen;
1445 				kr->r.nexthop = nexthop;
1446 				kr->r.scope = scope;
1447 				kr->r.flags = flags;
1448 				kr->r.ifindex = ifindex;
1449 				kr->r.priority = prio;
1450 
1451 				if (rtm->rtm_priority == kr_state.fib_prio) {
1452 					log_warnx("alien OSPF route %s/%d",
1453 					    log_in6addr(&prefix), prefixlen);
1454 					rv = send_rtmsg(kr_state.fd,
1455 					    RTM_DELETE, &kr->r);
1456 					free(kr);
1457 					if (rv == -1)
1458 						return (-1);
1459 				} else {
1460 					if ((label = (struct sockaddr_rtlabel *)
1461 					    rti_info[RTAX_LABEL]) != NULL) {
1462 						kr->r.rtlabel =
1463 						    rtlabel_name2id(
1464 						    label->sr_label);
1465 						kr->r.ext_tag =
1466 						    rtlabel_id2tag(
1467 						    kr->r.rtlabel);
1468 					}
1469 
1470 					kroute_insert(kr);
1471 				}
1472 			}
1473 			break;
1474 		case RTM_DELETE:
1475 			if ((kr = kroute_find(&prefix, prefixlen, prio)) ==
1476 			    NULL)
1477 				continue;
1478 			if (!(kr->r.flags & F_KERNEL))
1479 				continue;
1480 			/* get the correct route */
1481 			okr = kr;
1482 			if (mpath && (kr = kroute_matchgw(kr, &nexthop,
1483 			    scope)) == NULL) {
1484 				log_warnx("rtmsg_process mpath route"
1485 				    " not found");
1486 				return (-1);
1487 			}
1488 			if (kroute_remove(kr) == -1)
1489 				return (-1);
1490 			break;
1491 		case RTM_IFINFO:
1492 			memcpy(&ifm, next, sizeof(ifm));
1493 			if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
1494 			    (struct sockaddr_dl *)rti_info[RTAX_IFP]);
1495 			break;
1496 		case RTM_NEWADDR:
1497 			ifam = (struct ifa_msghdr *)rtm;
1498 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1499 			    RTA_BRD)) == 0)
1500 				break;
1501 
1502 			if_newaddr(ifam->ifam_index,
1503 			    (struct sockaddr_in6 *)rti_info[RTAX_IFA],
1504 			    (struct sockaddr_in6 *)rti_info[RTAX_NETMASK],
1505 			    (struct sockaddr_in6 *)rti_info[RTAX_BRD]);
1506 			break;
1507 		case RTM_DELADDR:
1508 			ifam = (struct ifa_msghdr *)rtm;
1509 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1510 			    RTA_BRD)) == 0)
1511 				break;
1512 
1513 			if_deladdr(ifam->ifam_index,
1514 			    (struct sockaddr_in6 *)rti_info[RTAX_IFA],
1515 			    (struct sockaddr_in6 *)rti_info[RTAX_NETMASK],
1516 			    (struct sockaddr_in6 *)rti_info[RTAX_BRD]);
1517 			break;
1518 		case RTM_IFANNOUNCE:
1519 			if_announce(next);
1520 			break;
1521 		default:
1522 			/* ignore for now */
1523 			break;
1524 		}
1525 	}
1526 	return (offset);
1527 }
1528