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