1 /*	$OpenBSD: kroute.c,v 1.3 2023/03/08 04:43:06 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@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 <sys/tree.h>
25 #include <sys/uio.h>
26 #include <sys/ioctl.h>
27 
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 #include <netinet/in.h>
33 #include <netinet/if_ether.h>
34 #include <arpa/inet.h>
35 
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <event.h>
44 
45 #include "snmpd.h"
46 
47 struct ktable		**krt;
48 u_int			  krt_size;
49 
50 struct {
51 	struct event		 ks_ev;
52 	u_long			 ks_iflastchange;
53 	u_long			 ks_nroutes;	/* 4 billions enough? */
54 	int			 ks_fd;
55 	int			 ks_ifd;
56 	u_short			 ks_nkif;
57 } kr_state;
58 
59 struct kroute_node {
60 	RB_ENTRY(kroute_node)	 entry;
61 	struct kroute		 r;
62 	struct kroute_node	*next;
63 };
64 
65 struct kroute6_node {
66 	RB_ENTRY(kroute6_node)	 entry;
67 	struct kroute6		 r;
68 	struct kroute6_node	*next;
69 };
70 
71 struct kif_node {
72 	RB_ENTRY(kif_node)	 entry;
73 	TAILQ_HEAD(, kif_addr)	 addrs;
74 	TAILQ_HEAD(, kif_arp)	 arps;
75 	struct kif		 k;
76 };
77 
78 int	kroute_compare(struct kroute_node *, struct kroute_node *);
79 int	kroute6_compare(struct kroute6_node *, struct kroute6_node *);
80 int	kif_compare(struct kif_node *, struct kif_node *);
81 
82 void			 ktable_init(void);
83 int			 ktable_new(u_int, u_int);
84 void			 ktable_free(u_int);
85 int			 ktable_exists(u_int, u_int *);
86 struct ktable		*ktable_get(u_int);
87 int			 ktable_update(u_int);
88 
89 struct kroute_node	*kroute_find(struct ktable *, in_addr_t, u_int8_t,
90 			    u_int8_t);
91 struct kroute_node	*kroute_matchgw(struct kroute_node *,
92 			    struct sockaddr_in *);
93 int			 kroute_insert(struct ktable *, struct kroute_node *);
94 int			 kroute_remove(struct ktable *, struct kroute_node *);
95 void			 kroute_clear(struct ktable *);
96 
97 struct kroute6_node	*kroute6_find(struct ktable *, const struct in6_addr *,
98 			    u_int8_t, u_int8_t);
99 struct kroute6_node	*kroute6_matchgw(struct kroute6_node *,
100 			    struct sockaddr_in6 *);
101 int			 kroute6_insert(struct ktable *, struct kroute6_node *);
102 int			 kroute6_remove(struct ktable *, struct kroute6_node *);
103 void			 kroute6_clear(struct ktable *);
104 
105 struct kif_arp		*karp_find(struct sockaddr *, u_short);
106 int			 karp_insert(struct kif_node *, struct kif_arp *);
107 int			 karp_remove(struct kif_node *, struct kif_arp *);
108 
109 struct kif_node		*kif_find(u_short);
110 struct kif_node		*kif_insert(u_short);
111 int			 kif_remove(struct kif_node *);
112 void			 kif_clear(void);
113 struct kif		*kif_update(u_short, int, struct if_data *,
114 			    struct sockaddr_dl *);
115 
116 int			 ka_compare(struct kif_addr *, struct kif_addr *);
117 void			 ka_insert(u_short, struct kif_addr *);
118 struct kif_addr		*ka_find(struct sockaddr *);
119 int			 ka_remove(struct kif_addr *);
120 
121 u_int8_t	prefixlen_classful(in_addr_t);
122 u_int8_t	mask2prefixlen(in_addr_t);
123 in_addr_t	prefixlen2mask(u_int8_t);
124 u_int8_t	mask2prefixlen6(struct sockaddr_in6 *);
125 struct in6_addr *prefixlen2mask6(u_int8_t);
126 void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
127 void		if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
128 void		if_newaddr(u_short, struct sockaddr *, struct sockaddr *,
129 		    struct sockaddr *);
130 void		if_deladdr(u_short, struct sockaddr *, struct sockaddr *,
131 		    struct sockaddr *);
132 void		if_announce(void *);
133 
134 int		fetchtable(struct ktable *);
135 int		fetchifs(u_short);
136 int		fetcharp(struct ktable *);
137 void		dispatch_rtmsg(int, short, void *);
138 int		rtmsg_process(char *, int);
139 int		dispatch_rtmsg_addr(struct ktable *, struct rt_msghdr *,
140 		    struct sockaddr *[RTAX_MAX]);
141 
142 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
143 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
144 
145 RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare)
146 RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare)
147 
148 RB_HEAD(kif_tree, kif_node)		kit;
149 RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
150 RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
151 
152 RB_HEAD(ka_tree, kif_addr)		kat;
RB_PROTOTYPE(ka_tree,kif_addr,node,ka_compare)153 RB_PROTOTYPE(ka_tree, kif_addr, node, ka_compare)
154 RB_GENERATE(ka_tree, kif_addr, node, ka_compare)
155 
156 void
157 kr_init(void)
158 {
159 	int		opt = 0, rcvbuf, default_rcvbuf;
160 	unsigned int	tid = RTABLE_ANY;
161 	socklen_t	optlen;
162 
163 	if ((kr_state.ks_ifd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
164 		fatal("kr_init: ioctl socket");
165 
166 	if ((kr_state.ks_fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
167 		fatal("kr_init: route socket");
168 
169 	/* not interested in my own messages */
170 	if (setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_USELOOPBACK,
171 	    &opt, sizeof(opt)) == -1)
172 		log_warn("%s: SO_USELOOPBACK", __func__);	/* not fatal */
173 
174 	if (snmpd_env->sc_rtfilter && setsockopt(kr_state.ks_fd, AF_ROUTE,
175 	    ROUTE_MSGFILTER, &snmpd_env->sc_rtfilter,
176 	    sizeof(snmpd_env->sc_rtfilter)) == -1)
177 		log_warn("%s: ROUTE_MSGFILTER", __func__);
178 
179 	/* grow receive buffer, don't wanna miss messages */
180 	optlen = sizeof(default_rcvbuf);
181 	if (getsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
182 	    &default_rcvbuf, &optlen) == -1)
183 		log_warn("%s: SO_RCVBUF", __func__);
184 	else
185 		for (rcvbuf = MAX_RTSOCK_BUF;
186 		    rcvbuf > default_rcvbuf &&
187 		    setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
188 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
189 		    rcvbuf /= 2)
190 			;	/* nothing */
191 
192 	if (setsockopt(kr_state.ks_fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
193 	    sizeof(tid)) == -1)
194 		log_warn("%s: ROUTE_TABLEFILTER", __func__);
195 
196 	RB_INIT(&kit);
197 	RB_INIT(&kat);
198 
199 	if (fetchifs(0) == -1)
200 		fatalx("kr_init: fetchifs");
201 
202 	ktable_init();
203 
204 	event_set(&kr_state.ks_ev, kr_state.ks_fd, EV_READ | EV_PERSIST,
205 	    dispatch_rtmsg, NULL);
206 	event_add(&kr_state.ks_ev, NULL);
207 }
208 
209 void
ktable_init(void)210 ktable_init(void)
211 {
212 	u_int		 i;
213 
214 	for (i = 0; i <= RT_TABLEID_MAX; i++)
215 		if (ktable_exists(i, NULL))
216 			ktable_update(i);
217 }
218 
219 int
ktable_new(u_int rtableid,u_int rdomid)220 ktable_new(u_int rtableid, u_int rdomid)
221 {
222 	struct ktable	**xkrt;
223 	struct ktable	 *kt;
224 	size_t		  newsize, oldsize;
225 
226 	/* resize index table if needed */
227 	if (rtableid >= krt_size) {
228 		if ((xkrt = reallocarray(krt, rtableid + 1,
229 		    sizeof(struct ktable *))) == NULL) {
230 			log_warn("%s: realloc", __func__);
231 			return (-1);
232 		}
233 		krt = xkrt;
234 		oldsize = krt_size * sizeof(struct ktable *);
235 		krt_size = rtableid + 1;
236 		newsize = krt_size * sizeof(struct ktable *);
237 		bzero((char *)krt + oldsize, newsize - oldsize);
238 	}
239 
240 	if (krt[rtableid])
241 		fatalx("ktable_new: table already exists");
242 
243 	/* allocate new element */
244 	kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
245 	if (kt == NULL) {
246 		log_warn("%s: calloc", __func__);
247 		return (-1);
248 	}
249 
250 	/* initialize structure ... */
251 	RB_INIT(&kt->krt);
252 	RB_INIT(&kt->krt6);
253 	kt->rtableid = rtableid;
254 	kt->rdomain = rdomid;
255 
256 	/* ... and load it */
257 	if (fetchtable(kt) == -1)
258 		return (-1);
259 	/* load arp information */
260 	if (fetcharp(kt) == -1)
261 		return (-1);
262 
263 	log_debug("%s: new ktable for rtableid %d", __func__, rtableid);
264 	return (0);
265 }
266 
267 void
ktable_free(u_int rtableid)268 ktable_free(u_int rtableid)
269 {
270 	struct ktable	*kt;
271 
272 	if ((kt = ktable_get(rtableid)) == NULL)
273 		return;
274 
275 	log_debug("%s: freeing ktable rtableid %u", __func__, kt->rtableid);
276 	kroute_clear(kt);
277 	kroute6_clear(kt);
278 
279 	krt[kt->rtableid] = NULL;
280 	free(kt);
281 }
282 
283 struct ktable *
ktable_get(u_int rtableid)284 ktable_get(u_int rtableid)
285 {
286 	if (rtableid >= krt_size)
287 		return (NULL);
288 	return (krt[rtableid]);
289 }
290 
291 int
ktable_update(u_int rtableid)292 ktable_update(u_int rtableid)
293 {
294 	struct ktable	*kt;
295 	u_int		 rdomid;
296 
297 	if (!ktable_exists(rtableid, &rdomid))
298 		fatalx("ktable_update: table doesn't exist");
299 
300 	if (rdomid != rtableid) {
301 		if (ktable_get(rdomid) == NULL &&
302 		    ktable_new(rdomid, rdomid) != 0)
303 			return (-1);
304 	}
305 
306 	kt = ktable_get(rtableid);
307 	if (kt == NULL) {
308 		if (ktable_new(rtableid, rdomid))
309 			return (-1);
310 	}
311 	return (0);
312 }
313 
314 int
ktable_exists(u_int rtableid,u_int * rdomid)315 ktable_exists(u_int rtableid, u_int *rdomid)
316 {
317 	size_t			 len;
318 	struct rt_tableinfo	 info;
319 	int			 mib[6];
320 
321 	mib[0] = CTL_NET;
322 	mib[1] = PF_ROUTE;
323 	mib[2] = 0;
324 	mib[3] = 0;
325 	mib[4] = NET_RT_TABLE;
326 	mib[5] = rtableid;
327 
328 	len = sizeof(info);
329 	if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
330 		if (errno == ENOENT)
331 			/* table nonexistent */
332 			return (0);
333 		log_warn("%s: sysctl", __func__);
334 		/* must return 0 so that the table is considered non-existent */
335 		return (0);
336 	}
337 	if (rdomid)
338 		*rdomid = info.rti_domainid;
339 	return (1);
340 }
341 
342 void
kr_shutdown(void)343 kr_shutdown(void)
344 {
345 	u_int	i;
346 
347 	for (i = krt_size; i > 0; i--)
348 		ktable_free(i - 1);
349 	kif_clear();
350 }
351 
352 u_int
kr_ifnumber(void)353 kr_ifnumber(void)
354 {
355 	return (kr_state.ks_nkif);
356 }
357 
358 u_long
kr_iflastchange(void)359 kr_iflastchange(void)
360 {
361 	return (kr_state.ks_iflastchange);
362 }
363 
364 int
kr_updateif(u_int if_index)365 kr_updateif(u_int if_index)
366 {
367 	return (fetchifs(if_index));
368 }
369 
370 u_long
kr_routenumber(void)371 kr_routenumber(void)
372 {
373 	return (kr_state.ks_nroutes);
374 }
375 
376 /* rb-tree compare */
377 int
kroute_compare(struct kroute_node * a,struct kroute_node * b)378 kroute_compare(struct kroute_node *a, struct kroute_node *b)
379 {
380 	if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
381 		return (-1);
382 	if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
383 		return (1);
384 	if (a->r.prefixlen < b->r.prefixlen)
385 		return (-1);
386 	if (a->r.prefixlen > b->r.prefixlen)
387 		return (1);
388 
389 	/* if the priority is RTP_ANY finish on the first address hit */
390 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
391 		return (0);
392 	if (a->r.priority < b->r.priority)
393 		return (-1);
394 	if (a->r.priority > b->r.priority)
395 		return (1);
396 	return (0);
397 }
398 
399 int
kroute6_compare(struct kroute6_node * a,struct kroute6_node * b)400 kroute6_compare(struct kroute6_node *a, struct kroute6_node *b)
401 {
402 	int i;
403 
404 	for (i = 0; i < 16; i++) {
405 		if (a->r.prefix.s6_addr[i] < b->r.prefix.s6_addr[i])
406 			return (-1);
407 		if (a->r.prefix.s6_addr[i] > b->r.prefix.s6_addr[i])
408 			return (1);
409 	}
410 
411 	if (a->r.prefixlen < b->r.prefixlen)
412 		return (-1);
413 	if (a->r.prefixlen > b->r.prefixlen)
414 		return (1);
415 
416 	/* if the priority is RTP_ANY finish on the first address hit */
417 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
418 		return (0);
419 	if (a->r.priority < b->r.priority)
420 		return (-1);
421 	if (a->r.priority > b->r.priority)
422 		return (1);
423 	return (0);
424 }
425 
426 int
kif_compare(struct kif_node * a,struct kif_node * b)427 kif_compare(struct kif_node *a, struct kif_node *b)
428 {
429 	return (a->k.if_index - b->k.if_index);
430 }
431 
432 int
ka_compare(struct kif_addr * a,struct kif_addr * b)433 ka_compare(struct kif_addr *a, struct kif_addr *b)
434 {
435 	if (a->addr.sa.sa_family < b->addr.sa.sa_family)
436 		return (-1);
437 	if (a->addr.sa.sa_family > b->addr.sa.sa_family)
438 		return (1);
439 	return (memcmp(&a->addr.sa, &b->addr.sa, a->addr.sa.sa_len));
440 }
441 
442 /* tree management */
443 struct kroute_node *
kroute_find(struct ktable * kt,in_addr_t prefix,u_int8_t prefixlen,u_int8_t prio)444 kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen,
445     u_int8_t prio)
446 {
447 	struct kroute_node	s;
448 	struct kroute_node	*kn, *tmp;
449 
450 	s.r.prefix.s_addr = prefix;
451 	s.r.prefixlen = prefixlen;
452 	s.r.priority = prio;
453 
454 	kn = RB_FIND(kroute_tree, &kt->krt, &s);
455 	if (kn && prio == RTP_ANY) {
456 		tmp = RB_PREV(kroute_tree, &kt->krt, kn);
457 		while (tmp) {
458 			if (kroute_compare(&s, tmp) == 0)
459 				kn = tmp;
460 			else
461 				break;
462 			tmp = RB_PREV(kroute_tree, &kt->krt, kn);
463 		}
464 	}
465 	return (kn);
466 }
467 
468 struct kroute_node *
kroute_matchgw(struct kroute_node * kr,struct sockaddr_in * sa_in)469 kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
470 {
471 	in_addr_t	nexthop;
472 
473 	if (sa_in == NULL) {
474 		log_warnx("%s: no nexthop defined", __func__);
475 		return (NULL);
476 	}
477 	nexthop = sa_in->sin_addr.s_addr;
478 
479 	while (kr) {
480 		if (kr->r.nexthop.s_addr == nexthop)
481 			return (kr);
482 		kr = kr->next;
483 	}
484 
485 	return (NULL);
486 }
487 
488 int
kroute_insert(struct ktable * kt,struct kroute_node * kr)489 kroute_insert(struct ktable *kt, struct kroute_node *kr)
490 {
491 	struct kroute_node	*krm;
492 
493 	if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) {
494 		/* multipath route, add at end of list */
495 		while (krm->next != NULL)
496 			krm = krm->next;
497 		krm->next = kr;
498 		kr->next = NULL; /* to be sure */
499 	}
500 
501 	kr_state.ks_nroutes++;
502 	return (0);
503 }
504 
505 int
kroute_remove(struct ktable * kt,struct kroute_node * kr)506 kroute_remove(struct ktable *kt, struct kroute_node *kr)
507 {
508 	struct kroute_node	*krm;
509 
510 	if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) {
511 		log_warnx("%s: failed to find %s/%u", __func__,
512 		    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
513 		return (-1);
514 	}
515 
516 	if (krm == kr) {
517 		/* head element */
518 		if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) {
519 			log_warnx("%s: failed for %s/%u", __func__,
520 			    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
521 			return (-1);
522 		}
523 		if (kr->next != NULL) {
524 			if (RB_INSERT(kroute_tree, &kt->krt, kr->next)
525 			    != NULL) {
526 				log_warnx("%s: failed to add %s/%u", __func__,
527 				    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
528 				return (-1);
529 			}
530 		}
531 	} else {
532 		/* somewhere in the list */
533 		while (krm->next != kr && krm->next != NULL)
534 			krm = krm->next;
535 		if (krm->next == NULL) {
536 			log_warnx("%s: multipath list corrupted for %s/%u",
537 			    __func__, inet_ntoa(kr->r.prefix), kr->r.prefixlen);
538 			return (-1);
539 		}
540 		krm->next = kr->next;
541 	}
542 
543 	kr_state.ks_nroutes--;
544 	free(kr);
545 	return (0);
546 }
547 
548 void
kroute_clear(struct ktable * kt)549 kroute_clear(struct ktable *kt)
550 {
551 	struct kroute_node	*kr;
552 
553 	while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL)
554 		kroute_remove(kt, kr);
555 }
556 
557 struct kroute6_node *
kroute6_find(struct ktable * kt,const struct in6_addr * prefix,u_int8_t prefixlen,u_int8_t prio)558 kroute6_find(struct ktable *kt, const struct in6_addr *prefix,
559     u_int8_t prefixlen, u_int8_t prio)
560 {
561 	struct kroute6_node	s;
562 	struct kroute6_node	*kn6, *tmp;
563 
564 	memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr));
565 	s.r.prefixlen = prefixlen;
566 	s.r.priority = prio;
567 
568 	kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s);
569 	if (kn6 && prio == RTP_ANY) {
570 		tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
571 		while (tmp) {
572 			if (kroute6_compare(&s, tmp) == 0)
573 				kn6 = tmp;
574 			else
575 				break;
576 			tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
577 		}
578 	}
579 	return (kn6);
580 }
581 
582 struct kroute6_node *
kroute6_matchgw(struct kroute6_node * kr,struct sockaddr_in6 * sa_in6)583 kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
584 {
585 	struct in6_addr	nexthop;
586 
587 	if (sa_in6 == NULL) {
588 		log_warnx("%s: no nexthop defined", __func__);
589 		return (NULL);
590 	}
591 	memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
592 
593 	while (kr) {
594 		if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
595 			return (kr);
596 		kr = kr->next;
597 	}
598 
599 	return (NULL);
600 }
601 
602 int
kroute6_insert(struct ktable * kt,struct kroute6_node * kr)603 kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
604 {
605 	struct kroute6_node	*krm;
606 
607 	if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) {
608 		/* multipath route, add at end of list */
609 		while (krm->next != NULL)
610 			krm = krm->next;
611 		krm->next = kr;
612 		kr->next = NULL; /* to be sure */
613 	}
614 
615 	kr_state.ks_nroutes++;
616 	return (0);
617 }
618 
619 int
kroute6_remove(struct ktable * kt,struct kroute6_node * kr)620 kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
621 {
622 	struct kroute6_node	*krm;
623 
624 	if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) {
625 		log_warnx("%s: failed for %s/%u", __func__,
626 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
627 		return (-1);
628 	}
629 
630 	if (krm == kr) {
631 		/* head element */
632 		if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) {
633 			log_warnx("%s: failed for %s/%u", __func__,
634 			    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
635 			return (-1);
636 		}
637 		if (kr->next != NULL) {
638 			if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) !=
639 			    NULL) {
640 				log_warnx("%s: failed to add %s/%u", __func__,
641 				    log_in6addr(&kr->r.prefix),
642 				    kr->r.prefixlen);
643 				return (-1);
644 			}
645 		}
646 	} else {
647 		/* somewhere in the list */
648 		while (krm->next != kr && krm->next != NULL)
649 			krm = krm->next;
650 		if (krm->next == NULL) {
651 			log_warnx("%s: multipath list corrupted for %s/%u",
652 			    __func__, log_in6addr(&kr->r.prefix),
653 			    kr->r.prefixlen);
654 			return (-1);
655 		}
656 		krm->next = kr->next;
657 	}
658 
659 	kr_state.ks_nroutes--;
660 	free(kr);
661 	return (0);
662 }
663 
664 void
kroute6_clear(struct ktable * kt)665 kroute6_clear(struct ktable *kt)
666 {
667 	struct kroute6_node	*kr;
668 
669 	while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL)
670 		kroute6_remove(kt, kr);
671 }
672 
673 static inline int
karp_compare(struct kif_arp * a,struct kif_arp * b)674 karp_compare(struct kif_arp *a, struct kif_arp *b)
675 {
676 	/* Interface indices are assumed equal */
677 	if (ntohl(a->addr.sin.sin_addr.s_addr) >
678 	    ntohl(b->addr.sin.sin_addr.s_addr))
679 		return (1);
680 	if (ntohl(a->addr.sin.sin_addr.s_addr) <
681 	    ntohl(b->addr.sin.sin_addr.s_addr))
682 		return (-1);
683 	return (0);
684 }
685 
686 static inline struct kif_arp *
karp_search(struct kif_node * kn,struct kif_arp * ka)687 karp_search(struct kif_node *kn, struct kif_arp *ka)
688 {
689 	struct kif_arp		*pivot;
690 
691 	TAILQ_FOREACH(pivot, &kn->arps, entry) {
692 		switch (karp_compare(ka, pivot)) {
693 		case 0: /* found */
694 			return (pivot);
695 		case -1: /* ka < pivot, end the search */
696 			return (NULL);
697 		}
698 	}
699 	/* looped through the whole list and didn't find */
700 	return (NULL);
701 }
702 
703 struct kif_arp *
karp_find(struct sockaddr * sa,u_short ifindex)704 karp_find(struct sockaddr *sa, u_short ifindex)
705 {
706 	struct kif_node		*kn;
707 	struct kif_arp		*ka = NULL, s;
708 
709 	memcpy(&s.addr.sa, sa, sa->sa_len);
710 
711 	if (ifindex == 0) {
712 		/*
713 		 * We iterate manually to handle zero ifindex special
714 		 * case differently from kif_find, in particular we
715 		 * want to look for the address on all available
716 		 * interfaces.
717 		 */
718 		RB_FOREACH(kn, kif_tree, &kit) {
719 			if ((ka = karp_search(kn, &s)) != NULL)
720 				break;
721 		}
722 	} else {
723 		if ((kn = kif_find(ifindex)) == NULL)
724 			return (NULL);
725 		ka = karp_search(kn, &s);
726 	}
727 	return (ka);
728 }
729 
730 int
karp_insert(struct kif_node * kn,struct kif_arp * ka)731 karp_insert(struct kif_node *kn, struct kif_arp *ka)
732 {
733 	struct kif_arp		*pivot;
734 
735 	if (ka->if_index == 0)
736 		return (-1);
737 	if (!kn && (kn = kif_find(ka->if_index)) == NULL)
738 		return (-1);
739 	/* Put entry on the list in the ascending lexical order */
740 	TAILQ_FOREACH(pivot, &kn->arps, entry) {
741 		switch (karp_compare(ka, pivot)) {
742 		case 0: /* collision */
743 			return (-1);
744 		case -1: /* ka < pivot */
745 			TAILQ_INSERT_BEFORE(pivot, ka, entry);
746 			return (0);
747 		}
748 	}
749 	/* ka is larger than any other element on the list */
750 	TAILQ_INSERT_TAIL(&kn->arps, ka, entry);
751 	return (0);
752 }
753 
754 int
karp_remove(struct kif_node * kn,struct kif_arp * ka)755 karp_remove(struct kif_node *kn, struct kif_arp *ka)
756 {
757 	if (ka->if_index == 0)
758 		return (-1);
759 	if (!kn && (kn = kif_find(ka->if_index)) == NULL)
760 		return (-1);
761 	TAILQ_REMOVE(&kn->arps, ka, entry);
762 	free(ka);
763 	return (0);
764 }
765 
766 struct kif_arp *
karp_first(u_short ifindex)767 karp_first(u_short ifindex)
768 {
769 	struct kif_node		*kn;
770 
771 	if ((kn = kif_find(ifindex)) == NULL)
772 		return (NULL);
773 	return (TAILQ_FIRST(&kn->arps));
774 }
775 
776 struct kif_arp *
karp_getaddr(struct sockaddr * sa,u_short ifindex,int next)777 karp_getaddr(struct sockaddr *sa, u_short ifindex, int next)
778 {
779 	struct kif_arp		*ka;
780 
781 	if ((ka = karp_find(sa, ifindex)) == NULL)
782 		return (NULL);
783 	return (next ? TAILQ_NEXT(ka, entry) : ka);
784 }
785 
786 struct kif_node *
kif_find(u_short if_index)787 kif_find(u_short if_index)
788 {
789 	struct kif_node	s;
790 
791 	if (if_index == 0)
792 		return (RB_MIN(kif_tree, &kit));
793 
794 	bzero(&s, sizeof(s));
795 	s.k.if_index = if_index;
796 
797 	return (RB_FIND(kif_tree, &kit, &s));
798 }
799 
800 struct kif *
kr_getif(u_short if_index)801 kr_getif(u_short if_index)
802 {
803 	struct kif_node	*kn;
804 
805 	kn = kif_find(if_index);
806 	if (kn == NULL)
807 		return (NULL);
808 
809 	return (&kn->k);
810 }
811 
812 struct kif *
kr_getnextif(u_short if_index)813 kr_getnextif(u_short if_index)
814 {
815 	struct kif_node	*kn;
816 
817 	if ((kn = kif_find(if_index)) == NULL)
818 		return (NULL);
819 	if (if_index)
820 		kn = RB_NEXT(kif_tree, &kit, kn);
821 	if (kn == NULL)
822 		return (NULL);
823 
824 	return (&kn->k);
825 }
826 
827 struct kif_node *
kif_insert(u_short if_index)828 kif_insert(u_short if_index)
829 {
830 	struct kif_node	*kif;
831 
832 	if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
833 		return (NULL);
834 
835 	kif->k.if_index = if_index;
836 	TAILQ_INIT(&kif->addrs);
837 	TAILQ_INIT(&kif->arps);
838 
839 	if (RB_INSERT(kif_tree, &kit, kif) != NULL)
840 		fatalx("kif_insert: RB_INSERT");
841 
842 	kr_state.ks_nkif++;
843 	kr_state.ks_iflastchange = smi_getticks();
844 
845 	return (kif);
846 }
847 
848 int
kif_remove(struct kif_node * kif)849 kif_remove(struct kif_node *kif)
850 {
851 	struct kif_addr	*ka;
852 	struct kif_arp	*kr;
853 
854 	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
855 		log_warnx("%s: RB_REMOVE failed", __func__);
856 		return (-1);
857 	}
858 
859 	while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
860 		TAILQ_REMOVE(&kif->addrs, ka, entry);
861 		ka_remove(ka);
862 	}
863 	while ((kr = TAILQ_FIRST(&kif->arps)) != NULL) {
864 		karp_remove(kif, kr);
865 	}
866 	free(kif);
867 
868 	kr_state.ks_nkif--;
869 	kr_state.ks_iflastchange = smi_getticks();
870 
871 	return (0);
872 }
873 
874 void
kif_clear(void)875 kif_clear(void)
876 {
877 	struct kif_node	*kif;
878 
879 	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
880 		kif_remove(kif);
881 	kr_state.ks_nkif = 0;
882 	kr_state.ks_iflastchange = smi_getticks();
883 }
884 
885 struct kif *
kif_update(u_short if_index,int flags,struct if_data * ifd,struct sockaddr_dl * sdl)886 kif_update(u_short if_index, int flags, struct if_data *ifd,
887     struct sockaddr_dl *sdl)
888 {
889 	struct kif_node		*kif;
890 	struct ether_addr	*ea;
891 	struct ifreq		 ifr;
892 
893 	if ((kif = kif_find(if_index)) == NULL)
894 		if ((kif = kif_insert(if_index)) == NULL)
895 			return (NULL);
896 
897 	kif->k.if_flags = flags;
898 	bcopy(ifd, &kif->k.if_data, sizeof(struct if_data));
899 	kif->k.if_ticks = smi_getticks();
900 
901 	if (sdl && sdl->sdl_family == AF_LINK) {
902 		if (sdl->sdl_nlen >= sizeof(kif->k.if_name))
903 			memcpy(kif->k.if_name, sdl->sdl_data,
904 			    sizeof(kif->k.if_name) - 1);
905 		else if (sdl->sdl_nlen > 0)
906 			memcpy(kif->k.if_name, sdl->sdl_data,
907 			    sdl->sdl_nlen);
908 		/* string already terminated via calloc() */
909 
910 		if ((ea = (struct ether_addr *)LLADDR(sdl)) != NULL)
911 			bcopy(&ea->ether_addr_octet, kif->k.if_lladdr,
912 			    ETHER_ADDR_LEN);
913 	}
914 
915 	bzero(&ifr, sizeof(ifr));
916 	strlcpy(ifr.ifr_name, kif->k.if_name, sizeof(ifr.ifr_name));
917 	ifr.ifr_data = (caddr_t)&kif->k.if_descr;
918 	if (ioctl(kr_state.ks_ifd, SIOCGIFDESCR, &ifr) == -1)
919 		bzero(&kif->k.if_descr, sizeof(kif->k.if_descr));
920 
921 	return (&kif->k);
922 }
923 
924 void
ka_insert(u_short if_index,struct kif_addr * ka)925 ka_insert(u_short if_index, struct kif_addr *ka)
926 {
927 	if (ka->addr.sa.sa_len == 0)
928 		return;
929 
930 	ka->if_index = if_index;
931 	RB_INSERT(ka_tree, &kat, ka);
932 }
933 
934 struct kif_addr	*
ka_find(struct sockaddr * sa)935 ka_find(struct sockaddr *sa)
936 {
937 	struct kif_addr		ka;
938 
939 	if (sa == NULL)
940 		return (RB_MIN(ka_tree, &kat));
941 	bzero(&ka.addr, sizeof(ka.addr));
942 	bcopy(sa, &ka.addr.sa, sa->sa_len);
943 	return (RB_FIND(ka_tree, &kat, &ka));
944 }
945 
946 int
ka_remove(struct kif_addr * ka)947 ka_remove(struct kif_addr *ka)
948 {
949 	RB_REMOVE(ka_tree, &kat, ka);
950 	free(ka);
951 	return (0);
952 }
953 
954 struct kif_addr *
kr_getaddr(struct sockaddr * sa)955 kr_getaddr(struct sockaddr *sa)
956 {
957 	return (ka_find(sa));
958 }
959 
960 struct kif_addr *
kr_getnextaddr(struct sockaddr * sa)961 kr_getnextaddr(struct sockaddr *sa)
962 {
963 	struct kif_addr	ka;
964 
965 	bzero(&ka.addr, sizeof(ka.addr));
966 	bcopy(sa, &ka.addr.sa, sa->sa_len);
967 	return RB_NFIND(ka_tree, &kat, &ka);
968 }
969 
970 /* misc */
971 u_int8_t
prefixlen_classful(in_addr_t ina)972 prefixlen_classful(in_addr_t ina)
973 {
974 	/* it hurt to write this. */
975 
976 	if (ina >= 0xf0000000U)		/* class E */
977 		return (32);
978 	else if (ina >= 0xe0000000U)	/* class D */
979 		return (4);
980 	else if (ina >= 0xc0000000U)	/* class C */
981 		return (24);
982 	else if (ina >= 0x80000000U)	/* class B */
983 		return (16);
984 	else				/* class A */
985 		return (8);
986 }
987 
988 u_int8_t
mask2prefixlen(in_addr_t ina)989 mask2prefixlen(in_addr_t ina)
990 {
991 	if (ina == 0)
992 		return (0);
993 	else
994 		return (33 - ffs(ntohl(ina)));
995 }
996 
997 in_addr_t
prefixlen2mask(u_int8_t prefixlen)998 prefixlen2mask(u_int8_t prefixlen)
999 {
1000 	if (prefixlen == 0)
1001 		return (0);
1002 
1003 	return (htonl(0xffffffff << (32 - prefixlen)));
1004 }
1005 
1006 u_int8_t
mask2prefixlen6(struct sockaddr_in6 * sa_in6)1007 mask2prefixlen6(struct sockaddr_in6 *sa_in6)
1008 {
1009 	unsigned int	 l = 0;
1010 	u_int8_t	*ap, *ep;
1011 
1012 	/*
1013 	 * sin6_len is the size of the sockaddr so subtract the offset of
1014 	 * the possibly truncated sin6_addr struct.
1015 	 */
1016 	ap = (u_int8_t *)&sa_in6->sin6_addr;
1017 	ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
1018 	for (; ap < ep; ap++) {
1019 		/* this "beauty" is adopted from sbin/route/show.c ... */
1020 		switch (*ap) {
1021 		case 0xff:
1022 			l += 8;
1023 			break;
1024 		case 0xfe:
1025 			l += 7;
1026 			goto done;
1027 		case 0xfc:
1028 			l += 6;
1029 			goto done;
1030 		case 0xf8:
1031 			l += 5;
1032 			goto done;
1033 		case 0xf0:
1034 			l += 4;
1035 			goto done;
1036 		case 0xe0:
1037 			l += 3;
1038 			goto done;
1039 		case 0xc0:
1040 			l += 2;
1041 			goto done;
1042 		case 0x80:
1043 			l += 1;
1044 			goto done;
1045 		case 0x00:
1046 			goto done;
1047 		default:
1048 			fatalx("non contiguous inet6 netmask");
1049 		}
1050 	}
1051 
1052 done:
1053 	if (l > sizeof(struct in6_addr) * 8)
1054 		fatalx("inet6 prefixlen out of bound");
1055 	return (l);
1056 }
1057 
1058 struct in6_addr *
prefixlen2mask6(u_int8_t prefixlen)1059 prefixlen2mask6(u_int8_t prefixlen)
1060 {
1061 	static struct in6_addr	mask;
1062 	int			i;
1063 
1064 	bzero(&mask, sizeof(mask));
1065 	for (i = 0; i < prefixlen / 8; i++)
1066 		mask.s6_addr[i] = 0xff;
1067 	i = prefixlen % 8;
1068 	if (i)
1069 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1070 
1071 	return (&mask);
1072 }
1073 
1074 #define ROUNDUP(a) \
1075 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1076 
1077 void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)1078 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1079 {
1080 	int	i;
1081 
1082 	for (i = 0; i < RTAX_MAX; i++) {
1083 		if (addrs & (1 << i)) {
1084 			rti_info[i] = sa;
1085 			sa = (struct sockaddr *)((char *)(sa) +
1086 			    ROUNDUP(sa->sa_len));
1087 		} else
1088 			rti_info[i] = NULL;
1089 
1090 	}
1091 }
1092 
1093 void
if_change(u_short if_index,int flags,struct if_data * ifd,struct sockaddr_dl * sdl)1094 if_change(u_short if_index, int flags, struct if_data *ifd,
1095     struct sockaddr_dl *sdl)
1096 {
1097 	if (kif_update(if_index, flags, ifd, sdl) == NULL)
1098 		log_warn("%s: interface %u update failed", __func__, if_index);
1099 }
1100 
1101 void
if_newaddr(u_short if_index,struct sockaddr * ifa,struct sockaddr * mask,struct sockaddr * brd)1102 if_newaddr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
1103     struct sockaddr *brd)
1104 {
1105 	struct kif_node *kif;
1106 	struct kif_addr *ka;
1107 
1108 	if (ifa == NULL)
1109 		return;
1110 	if ((kif = kif_find(if_index)) == NULL) {
1111 		log_warnx("%s: corresponding if %u not found", __func__,
1112 		    if_index);
1113 		return;
1114 	}
1115 	if ((ka = ka_find(ifa)) == NULL) {
1116 		if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
1117 			fatal("if_newaddr");
1118 		bcopy(ifa, &ka->addr.sa, ifa->sa_len);
1119 		TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
1120 		ka_insert(if_index, ka);
1121 	}
1122 
1123 	if (mask)
1124 		bcopy(mask, &ka->mask.sa, mask->sa_len);
1125 	else
1126 		bzero(&ka->mask, sizeof(ka->mask));
1127 	if (brd)
1128 		bcopy(brd, &ka->dstbrd.sa, brd->sa_len);
1129 	else
1130 		bzero(&ka->dstbrd, sizeof(ka->dstbrd));
1131 }
1132 
1133 void
if_deladdr(u_short if_index,struct sockaddr * ifa,struct sockaddr * mask,struct sockaddr * brd)1134 if_deladdr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
1135     struct sockaddr *brd)
1136 {
1137 	struct kif_node *kif;
1138 	struct kif_addr *ka;
1139 
1140 	if (ifa == NULL)
1141 		return;
1142 	if ((kif = kif_find(if_index)) == NULL) {
1143 		log_warnx("%s: corresponding if %u not found", __func__,
1144 		    if_index);
1145 		return;
1146 	}
1147 	if ((ka = ka_find(ifa)) == NULL)
1148 		return;
1149 
1150 	TAILQ_REMOVE(&kif->addrs, ka, entry);
1151 	ka_remove(ka);
1152 }
1153 
1154 void
if_announce(void * msg)1155 if_announce(void *msg)
1156 {
1157 	struct if_announcemsghdr	*ifan;
1158 	struct kif_node			*kif;
1159 
1160 	ifan = msg;
1161 
1162 	switch (ifan->ifan_what) {
1163 	case IFAN_ARRIVAL:
1164 		kif = kif_insert(ifan->ifan_index);
1165 		strlcpy(kif->k.if_name, ifan->ifan_name,
1166 		    sizeof(kif->k.if_name));
1167 		break;
1168 	case IFAN_DEPARTURE:
1169 		kif = kif_find(ifan->ifan_index);
1170 		kif_remove(kif);
1171 		break;
1172 	}
1173 }
1174 
1175 int
fetchtable(struct ktable * kt)1176 fetchtable(struct ktable *kt)
1177 {
1178 	int			 mib[7];
1179 	size_t			 len;
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_INET;
1187 	mib[4] = NET_RT_DUMP;
1188 	mib[5] = 0;
1189 	mib[6] = kt->rtableid;
1190 
1191 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1192 		if (kt->rtableid != 0 && errno == EINVAL)
1193 			/* table nonexistent */
1194 			return (0);
1195 		log_warn("%s: failed to fetch routing table %u size", __func__,
1196 		    kt->rtableid);
1197 		return (-1);
1198 	}
1199 	if (len == 0)
1200 		return (0);
1201 	if ((buf = malloc(len)) == NULL) {
1202 		log_warn("%s: malloc", __func__);
1203 		return (-1);
1204 	}
1205 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1206 		log_warn("%s: failed to fetch routing table %u", __func__,
1207 		    kt->rtableid);
1208 		free(buf);
1209 		return (-1);
1210 	}
1211 
1212 	rv = rtmsg_process(buf, len);
1213 	free(buf);
1214 
1215 	return (rv);
1216 }
1217 
1218 int
fetchifs(u_short if_index)1219 fetchifs(u_short if_index)
1220 {
1221 	size_t			 len;
1222 	int			 mib[6];
1223 	char			*buf;
1224 	int			 rv;
1225 
1226 	mib[0] = CTL_NET;
1227 	mib[1] = PF_ROUTE;
1228 	mib[2] = 0;
1229 	mib[3] = 0;	/* wildcard address family */
1230 	mib[4] = NET_RT_IFLIST;
1231 	mib[5] = if_index;
1232 
1233 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
1234 		log_warn("%s: failed to fetch address table size for %u",
1235 		    __func__, if_index);
1236 		return (-1);
1237 	}
1238 	if ((buf = malloc(len)) == NULL) {
1239 		log_warn("%s: malloc", __func__);
1240 		return (-1);
1241 	}
1242 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
1243 		log_warn("%s: failed to fetch address table for %u",
1244 		    __func__, if_index);
1245 		free(buf);
1246 		return (-1);
1247 	}
1248 
1249 	rv = rtmsg_process(buf, len);
1250 	free(buf);
1251 
1252 	return (rv);
1253 }
1254 
1255 int
fetcharp(struct ktable * kt)1256 fetcharp(struct ktable *kt)
1257 {
1258 	size_t			 len;
1259 	int			 mib[7];
1260 	char			*buf;
1261 	int			 rv;
1262 
1263 	mib[0] = CTL_NET;
1264 	mib[1] = PF_ROUTE;
1265 	mib[2] = 0;
1266 	mib[3] = AF_INET;
1267 	mib[4] = NET_RT_FLAGS;
1268 	mib[5] = RTF_LLINFO;
1269 	mib[6] = kt->rtableid;
1270 
1271 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1272 		log_warn("%s: failed to fetch arp table %u size", __func__,
1273 		    kt->rtableid);
1274 		return (-1);
1275 	}
1276 	/* Empty table? */
1277 	if (len == 0)
1278 		return (0);
1279 	if ((buf = malloc(len)) == NULL) {
1280 		log_warn("%s: malloc", __func__);
1281 		return (-1);
1282 	}
1283 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1284 		log_warn("%s: failed to fetch arp table %u", __func__,
1285 		    kt->rtableid);
1286 		free(buf);
1287 		return (-1);
1288 	}
1289 
1290 	rv = rtmsg_process(buf, len);
1291 	free(buf);
1292 
1293 	return (rv);
1294 }
1295 
1296 void
dispatch_rtmsg(int fd,short event,void * arg)1297 dispatch_rtmsg(int fd, short event, void *arg)
1298 {
1299 	char			 buf[RT_BUF_SIZE];
1300 	ssize_t			 n;
1301 
1302 	if ((n = read(fd, &buf, sizeof(buf))) == -1) {
1303 		log_warn("%s: read error", __func__);
1304 		return;
1305 	}
1306 
1307 	if (n == 0) {
1308 		log_warnx("%s: routing socket closed", __func__);
1309 		return;
1310 	}
1311 
1312 	rtmsg_process(buf, n);
1313 }
1314 
1315 int
rtmsg_process(char * buf,int len)1316 rtmsg_process(char *buf, int len)
1317 {
1318 	struct ktable		*kt;
1319 	struct rt_msghdr	*rtm;
1320 	struct if_msghdr	 ifm;
1321 	struct ifa_msghdr	*ifam;
1322 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1323 	int			 offset;
1324 	char			*next;
1325 
1326 	for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
1327 		next = buf + offset;
1328 		rtm = (struct rt_msghdr *)next;
1329 		if (rtm->rtm_version != RTM_VERSION)
1330 			continue;
1331 
1332 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1333 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1334 
1335 		switch (rtm->rtm_type) {
1336 		case RTM_ADD:
1337 		case RTM_GET:
1338 		case RTM_CHANGE:
1339 		case RTM_DELETE:
1340 		case RTM_RESOLVE:
1341 			if (rtm->rtm_errno)		 /* failed attempts */
1342 				continue;
1343 
1344 			if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
1345 				continue;
1346 
1347 			if (dispatch_rtmsg_addr(kt, rtm, rti_info) == -1)
1348 				return (-1);
1349 			break;
1350 		case RTM_IFINFO:
1351 			memcpy(&ifm, next, sizeof(ifm));
1352 			if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
1353 			    (struct sockaddr_dl *)rti_info[RTAX_IFP]);
1354 			break;
1355 		case RTM_DELADDR:
1356 			ifam = (struct ifa_msghdr *)rtm;
1357 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1358 			    RTA_BRD)) == 0)
1359 				break;
1360 
1361 			if_deladdr(ifam->ifam_index, rti_info[RTAX_IFA],
1362 			    rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
1363 			break;
1364 		case RTM_NEWADDR:
1365 			ifam = (struct ifa_msghdr *)rtm;
1366 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1367 			    RTA_BRD)) == 0)
1368 				break;
1369 
1370 			if_newaddr(ifam->ifam_index, rti_info[RTAX_IFA],
1371 			    rti_info[RTAX_NETMASK], rti_info[RTAX_BRD]);
1372 			break;
1373 		case RTM_IFANNOUNCE:
1374 			if_announce(next);
1375 			break;
1376 		case RTM_DESYNC:
1377 			kr_shutdown();
1378 			if (fetchifs(0) == -1)
1379 				fatalx("rtmsg_process: fetchifs");
1380 			ktable_init();
1381 			break;
1382 		default:
1383 			/* ignore for now */
1384 			break;
1385 		}
1386 	}
1387 
1388 	return (offset);
1389 }
1390 
1391 int
dispatch_rtmsg_addr(struct ktable * kt,struct rt_msghdr * rtm,struct sockaddr * rti_info[RTAX_MAX])1392 dispatch_rtmsg_addr(struct ktable *kt, struct rt_msghdr *rtm,
1393     struct sockaddr *rti_info[RTAX_MAX])
1394 {
1395 	struct sockaddr		*sa, *psa;
1396 	struct sockaddr_in	*sa_in, *psa_in = NULL;
1397 	struct sockaddr_in6	*sa_in6, *psa_in6 = NULL;
1398 	struct sockaddr_dl	*sa_dl;
1399 	struct kroute_node	*kr;
1400 	struct kroute6_node	*kr6;
1401 	struct kif_arp		*ka;
1402 	int			 flags, mpath = 0;
1403 	u_int16_t		 ifindex;
1404 	u_int8_t		 prefixlen;
1405 	u_int8_t		 prio;
1406 
1407 	flags = 0;
1408 	ifindex = 0;
1409 	prefixlen = 0;
1410 
1411 	if ((psa = rti_info[RTAX_DST]) == NULL)
1412 		return (-1);
1413 
1414 	if (rtm->rtm_flags & RTF_STATIC)
1415 		flags |= F_STATIC;
1416 	if (rtm->rtm_flags & RTF_BLACKHOLE)
1417 		flags |= F_BLACKHOLE;
1418 	if (rtm->rtm_flags & RTF_REJECT)
1419 		flags |= F_REJECT;
1420 	if (rtm->rtm_flags & RTF_DYNAMIC)
1421 		flags |= F_DYNAMIC;
1422 #ifdef RTF_MPATH
1423 	if (rtm->rtm_flags & RTF_MPATH)
1424 		mpath = 1;
1425 #endif
1426 
1427 	prio = rtm->rtm_priority;
1428 	switch (psa->sa_family) {
1429 	case AF_INET:
1430 		psa_in = (struct sockaddr_in *)psa;
1431 		sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
1432 		if (sa_in != NULL) {
1433 			if (sa_in->sin_len != 0)
1434 				prefixlen = mask2prefixlen(
1435 				    sa_in->sin_addr.s_addr);
1436 		} else if (rtm->rtm_flags & RTF_HOST)
1437 			prefixlen = 32;
1438 		else
1439 			prefixlen =
1440 			    prefixlen_classful(psa_in->sin_addr.s_addr);
1441 		break;
1442 	case AF_INET6:
1443 		psa_in6 = (struct sockaddr_in6 *)psa;
1444 		sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
1445 		if (sa_in6 != NULL) {
1446 			if (sa_in6->sin6_len != 0)
1447 				prefixlen = mask2prefixlen6(sa_in6);
1448 		} else if (rtm->rtm_flags & RTF_HOST)
1449 			prefixlen = 128;
1450 		else
1451 			fatalx("in6 net addr without netmask");
1452 		break;
1453 	default:
1454 		return (0);
1455 	}
1456 
1457 	if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
1458 		switch (sa->sa_family) {
1459 		case AF_INET:
1460 		case AF_INET6:
1461 			if (rtm->rtm_flags & RTF_CONNECTED) {
1462 				flags |= F_CONNECTED;
1463 				ifindex = rtm->rtm_index;
1464 			}
1465 			mpath = 0;	/* link local stuff can't be mpath */
1466 			break;
1467 		case AF_LINK:
1468 			/*
1469 			 * Traditional BSD connected routes have
1470 			 * a gateway of type AF_LINK.
1471 			 */
1472 			flags |= F_CONNECTED;
1473 			ifindex = rtm->rtm_index;
1474 			mpath = 0;	/* link local stuff can't be mpath */
1475 			break;
1476 		}
1477 
1478 	if (rtm->rtm_type == RTM_DELETE) {
1479 		if (sa != NULL && sa->sa_family == AF_LINK &&
1480 		    (rtm->rtm_flags & RTF_HOST) &&
1481 		    psa->sa_family == AF_INET) {
1482 			if ((ka = karp_find(psa, ifindex)) == NULL)
1483 				return (0);
1484 			if (karp_remove(NULL, ka) == -1)
1485 				return (-1);
1486 			return (0);
1487 		} else if (sa == NULL && (rtm->rtm_flags & RTF_HOST) &&
1488 		    psa->sa_family == AF_INET) {
1489 			if ((ka = karp_find(psa, ifindex)) != NULL)
1490 				karp_remove(NULL, ka);
1491 			/* Continue to the route section below  */
1492 		}
1493 		switch (psa->sa_family) {
1494 		case AF_INET:
1495 			sa_in = (struct sockaddr_in *)sa;
1496 			if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr,
1497 			    prefixlen, prio)) == NULL)
1498 				return (0);
1499 
1500 			if (mpath)
1501 				/* get the correct route */
1502 				if ((kr = kroute_matchgw(kr, sa_in)) == NULL) {
1503 					log_warnx("%s[delete]: "
1504 					    "mpath route not found", __func__);
1505 					return (0);
1506 				}
1507 
1508 			if (kroute_remove(kt, kr) == -1)
1509 				return (-1);
1510 			break;
1511 		case AF_INET6:
1512 			sa_in6 = (struct sockaddr_in6 *)sa;
1513 			if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr,
1514 			    prefixlen, prio)) == NULL)
1515 				return (0);
1516 
1517 			if (mpath)
1518 				/* get the correct route */
1519 				if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
1520 				    NULL) {
1521 					log_warnx("%s[delete]: "
1522 					    "IPv6 mpath route not found",
1523 					    __func__);
1524 					return (0);
1525 				}
1526 
1527 			if (kroute6_remove(kt, kr6) == -1)
1528 				return (-1);
1529 			break;
1530 		}
1531 		return (0);
1532 	}
1533 
1534 	if (sa == NULL && !(flags & F_CONNECTED))
1535 		return (0);
1536 
1537 	/* Add or update an ARP entry */
1538 	if ((rtm->rtm_flags & RTF_LLINFO) && (rtm->rtm_flags & RTF_HOST) &&
1539 	    sa != NULL && sa->sa_family == AF_LINK &&
1540 	    psa->sa_family == AF_INET) {
1541 		sa_dl = (struct sockaddr_dl *)sa;
1542 		/* ignore incomplete entries */
1543 		if (!sa_dl->sdl_alen)
1544 			return (0);
1545 		/* ignore entries that do not specify an interface */
1546 		if (ifindex == 0)
1547 			return (0);
1548 		if ((ka = karp_find(psa, ifindex)) != NULL) {
1549 			memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
1550 			if (rtm->rtm_flags & RTF_PERMANENT_ARP)
1551 				flags |= F_STATIC;
1552 			ka->flags = flags;
1553 		} else {
1554 			if ((ka = calloc(1, sizeof(struct kif_arp))) == NULL) {
1555 				log_warn("%s: calloc", __func__);
1556 				return (-1);
1557 			}
1558 			memcpy(&ka->addr.sa, psa, psa->sa_len);
1559 			memcpy(&ka->target.sdl, sa_dl, sa_dl->sdl_len);
1560 			if (rtm->rtm_flags & RTF_PERMANENT_ARP)
1561 				flags |= F_STATIC;
1562 			ka->flags = flags;
1563 			ka->if_index = ifindex;
1564 			if (karp_insert(NULL, ka)) {
1565 				free(ka);
1566 				log_warnx("%s: failed to insert", __func__);
1567 				return (-1);
1568 			}
1569 		}
1570 		return (0);
1571 	}
1572 
1573 	switch (psa->sa_family) {
1574 	case AF_INET:
1575 		sa_in = (struct sockaddr_in *)sa;
1576 		if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr, prefixlen,
1577 		    prio)) != NULL) {
1578 			/* get the correct route */
1579 			if (mpath && rtm->rtm_type == RTM_CHANGE &&
1580 			    (kr = kroute_matchgw(kr, sa_in)) == NULL) {
1581 				log_warnx("%s[change]: "
1582 				    "mpath route not found", __func__);
1583 				return (-1);
1584 			} else if (mpath && rtm->rtm_type == RTM_ADD)
1585 				goto add4;
1586 
1587 			if (sa_in != NULL)
1588 				kr->r.nexthop.s_addr =
1589 				    sa_in->sin_addr.s_addr;
1590 			else
1591 				kr->r.nexthop.s_addr = 0;
1592 			kr->r.flags = flags;
1593 			kr->r.if_index = ifindex;
1594 			kr->r.ticks = smi_getticks();
1595 		} else {
1596 add4:
1597 			if ((kr = calloc(1,
1598 			    sizeof(struct kroute_node))) == NULL) {
1599 				log_warn("%s: calloc", __func__);
1600 				return (-1);
1601 			}
1602 			kr->r.prefix.s_addr = psa_in->sin_addr.s_addr;
1603 			kr->r.prefixlen = prefixlen;
1604 			if (sa_in != NULL)
1605 				kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr;
1606 			else
1607 				kr->r.nexthop.s_addr = 0;
1608 			kr->r.flags = flags;
1609 			kr->r.if_index = ifindex;
1610 			kr->r.ticks = smi_getticks();
1611 			kr->r.priority = prio;
1612 
1613 			kroute_insert(kt, kr);
1614 		}
1615 		break;
1616 	case AF_INET6:
1617 		sa_in6 = (struct sockaddr_in6 *)sa;
1618 		if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr, prefixlen,
1619 		    prio)) != NULL) {
1620 			/* get the correct route */
1621 			if (mpath && rtm->rtm_type == RTM_CHANGE &&
1622 			    (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
1623 			    NULL) {
1624 				log_warnx("%s[change]: "
1625 				    "IPv6 mpath route not found", __func__);
1626 				return (-1);
1627 			} else if (mpath && rtm->rtm_type == RTM_ADD)
1628 				goto add6;
1629 
1630 			if (sa_in6 != NULL)
1631 				memcpy(&kr6->r.nexthop,
1632 				    &sa_in6->sin6_addr,
1633 				    sizeof(struct in6_addr));
1634 			else
1635 				memcpy(&kr6->r.nexthop,
1636 				    &in6addr_any,
1637 				    sizeof(struct in6_addr));
1638 
1639 			kr6->r.flags = flags;
1640 			kr6->r.if_index = ifindex;
1641 			kr6->r.ticks = smi_getticks();
1642 		} else {
1643 add6:
1644 			if ((kr6 = calloc(1,
1645 			    sizeof(struct kroute6_node))) == NULL) {
1646 				log_warn("%s: calloc", __func__);
1647 				return (-1);
1648 			}
1649 			memcpy(&kr6->r.prefix, &psa_in6->sin6_addr,
1650 			    sizeof(struct in6_addr));
1651 			kr6->r.prefixlen = prefixlen;
1652 			if (sa_in6 != NULL)
1653 				memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr,
1654 				    sizeof(struct in6_addr));
1655 			else
1656 				memcpy(&kr6->r.nexthop, &in6addr_any,
1657 				    sizeof(struct in6_addr));
1658 			kr6->r.flags = flags;
1659 			kr6->r.if_index = ifindex;
1660 			kr6->r.ticks = smi_getticks();
1661 			kr6->r.priority = prio;
1662 
1663 			kroute6_insert(kt, kr6);
1664 		}
1665 		break;
1666 	}
1667 
1668 	return (0);
1669 }
1670 
1671 struct kroute *
kroute_first(void)1672 kroute_first(void)
1673 {
1674 	struct kroute_node	*kn;
1675 	struct ktable		*kt;
1676 
1677 	if ((kt = ktable_get(0)) == NULL)
1678 		return (NULL);
1679 	kn = RB_MIN(kroute_tree, &kt->krt);
1680 	return (&kn->r);
1681 }
1682 
1683 struct kroute *
kroute_getaddr(in_addr_t prefix,u_int8_t prefixlen,u_int8_t prio,int next)1684 kroute_getaddr(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio, int next)
1685 {
1686 	struct kroute_node	*kn;
1687 	struct ktable		*kt;
1688 
1689 	if ((kt = ktable_get(0)) == NULL)
1690 		return (NULL);
1691 	kn = kroute_find(kt, prefix, prefixlen, prio);
1692 	if (kn != NULL && next)
1693 		kn = RB_NEXT(kroute_tree, &kt->krt, kn);
1694 	if (kn != NULL)
1695 		return (&kn->r);
1696 	else
1697 		return (NULL);
1698 }
1699