GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/kroute.c Lines: 0 767 0.0 %
Date: 2017-11-07 Branches: 0 1247 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: kroute.c,v 1.35 2017/07/24 11:00:01 friehm 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;
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, PF_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
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
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
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 *
284
ktable_get(u_int rtableid)
285
{
286
	if (rtableid >= krt_size)
287
		return (NULL);
288
	return (krt[rtableid]);
289
}
290
291
int
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
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
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
353
kr_ifnumber(void)
354
{
355
	return (kr_state.ks_nkif);
356
}
357
358
u_long
359
kr_iflastchange(void)
360
{
361
	return (kr_state.ks_iflastchange);
362
}
363
364
int
365
kr_updateif(u_int if_index)
366
{
367
	return (fetchifs(if_index));
368
}
369
370
u_long
371
kr_routenumber(void)
372
{
373
	return (kr_state.ks_nroutes);
374
}
375
376
/* rb-tree compare */
377
int
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
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
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
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 *
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 *
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
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
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
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 *
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 *
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
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
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
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
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 *
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 *
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
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
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 *
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 *
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 *
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 *
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 *
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 *
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
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
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 *
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
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	*
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
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 *
955
kr_getaddr(struct sockaddr *sa)
956
{
957
	return (ka_find(sa));
958
}
959
960
struct kif_addr *
961
kr_getnextaddr(struct sockaddr *sa)
962
{
963
	struct kif_addr	*ka;
964
965
	if ((ka = ka_find(sa)) == NULL)
966
		return (NULL);
967
	if (sa)
968
		ka = RB_NEXT(ka_tree, &kat, ka);
969
970
	return (ka);
971
}
972
973
/* misc */
974
u_int8_t
975
prefixlen_classful(in_addr_t ina)
976
{
977
	/* it hurt to write this. */
978
979
	if (ina >= 0xf0000000U)		/* class E */
980
		return (32);
981
	else if (ina >= 0xe0000000U)	/* class D */
982
		return (4);
983
	else if (ina >= 0xc0000000U)	/* class C */
984
		return (24);
985
	else if (ina >= 0x80000000U)	/* class B */
986
		return (16);
987
	else				/* class A */
988
		return (8);
989
}
990
991
u_int8_t
992
mask2prefixlen(in_addr_t ina)
993
{
994
	if (ina == 0)
995
		return (0);
996
	else
997
		return (33 - ffs(ntohl(ina)));
998
}
999
1000
in_addr_t
1001
prefixlen2mask(u_int8_t prefixlen)
1002
{
1003
	if (prefixlen == 0)
1004
		return (0);
1005
1006
	return (htonl(0xffffffff << (32 - prefixlen)));
1007
}
1008
1009
u_int8_t
1010
mask2prefixlen6(struct sockaddr_in6 *sa_in6)
1011
{
1012
	u_int8_t	 l = 0, *ap, *ep;
1013
1014
	/*
1015
	 * sin6_len is the size of the sockaddr so substract the offset of
1016
	 * the possibly truncated sin6_addr struct.
1017
	 */
1018
	ap = (u_int8_t *)&sa_in6->sin6_addr;
1019
	ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
1020
	for (; ap < ep; ap++) {
1021
		/* this "beauty" is adopted from sbin/route/show.c ... */
1022
		switch (*ap) {
1023
		case 0xff:
1024
			l += 8;
1025
			break;
1026
		case 0xfe:
1027
			l += 7;
1028
			return (l);
1029
		case 0xfc:
1030
			l += 6;
1031
			return (l);
1032
		case 0xf8:
1033
			l += 5;
1034
			return (l);
1035
		case 0xf0:
1036
			l += 4;
1037
			return (l);
1038
		case 0xe0:
1039
			l += 3;
1040
			return (l);
1041
		case 0xc0:
1042
			l += 2;
1043
			return (l);
1044
		case 0x80:
1045
			l += 1;
1046
			return (l);
1047
		case 0x00:
1048
			return (l);
1049
		default:
1050
			fatalx("non contiguous inet6 netmask");
1051
		}
1052
	}
1053
1054
	return (l);
1055
}
1056
1057
struct in6_addr *
1058
prefixlen2mask6(u_int8_t prefixlen)
1059
{
1060
	static struct in6_addr	mask;
1061
	int			i;
1062
1063
	bzero(&mask, sizeof(mask));
1064
	for (i = 0; i < prefixlen / 8; i++)
1065
		mask.s6_addr[i] = 0xff;
1066
	i = prefixlen % 8;
1067
	if (i)
1068
		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1069
1070
	return (&mask);
1071
}
1072
1073
#define ROUNDUP(a) \
1074
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1075
1076
void
1077
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1078
{
1079
	int	i;
1080
1081
	for (i = 0; i < RTAX_MAX; i++) {
1082
		if (addrs & (1 << i)) {
1083
			rti_info[i] = sa;
1084
			sa = (struct sockaddr *)((char *)(sa) +
1085
			    ROUNDUP(sa->sa_len));
1086
		} else
1087
			rti_info[i] = NULL;
1088
1089
	}
1090
}
1091
1092
void
1093
if_change(u_short if_index, int flags, struct if_data *ifd,
1094
    struct sockaddr_dl *sdl)
1095
{
1096
	if (kif_update(if_index, flags, ifd, sdl) == NULL)
1097
		log_warn("%s: interface %u update failed", __func__, if_index);
1098
}
1099
1100
void
1101
if_newaddr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
1102
    struct sockaddr *brd)
1103
{
1104
	struct kif_node *kif;
1105
	struct kif_addr *ka;
1106
1107
	if (ifa == NULL)
1108
		return;
1109
	if ((kif = kif_find(if_index)) == NULL) {
1110
		log_warnx("%s: corresponding if %u not found", __func__,
1111
		    if_index);
1112
		return;
1113
	}
1114
	if ((ka = ka_find(ifa)) == NULL) {
1115
		if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
1116
			fatal("if_newaddr");
1117
		bcopy(ifa, &ka->addr.sa, ifa->sa_len);
1118
		TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
1119
		ka_insert(if_index, ka);
1120
	}
1121
1122
	if (mask)
1123
		bcopy(mask, &ka->mask.sa, mask->sa_len);
1124
	else
1125
		bzero(&ka->mask, sizeof(ka->mask));
1126
	if (brd)
1127
		bcopy(brd, &ka->dstbrd.sa, brd->sa_len);
1128
	else
1129
		bzero(&ka->dstbrd, sizeof(ka->dstbrd));
1130
}
1131
1132
void
1133
if_deladdr(u_short if_index, struct sockaddr *ifa, struct sockaddr *mask,
1134
    struct sockaddr *brd)
1135
{
1136
	struct kif_node *kif;
1137
	struct kif_addr *ka;
1138
1139
	if (ifa == NULL)
1140
		return;
1141
	if ((kif = kif_find(if_index)) == NULL) {
1142
		log_warnx("%s: corresponding if %u not found", __func__,
1143
		    if_index);
1144
		return;
1145
	}
1146
	if ((ka = ka_find(ifa)) == NULL)
1147
		return;
1148
1149
	TAILQ_REMOVE(&kif->addrs, ka, entry);
1150
	ka_remove(ka);
1151
}
1152
1153
void
1154
if_announce(void *msg)
1155
{
1156
	struct if_announcemsghdr	*ifan;
1157
	struct kif_node			*kif;
1158
1159
	ifan = msg;
1160
1161
	switch (ifan->ifan_what) {
1162
	case IFAN_ARRIVAL:
1163
		kif = kif_insert(ifan->ifan_index);
1164
		strlcpy(kif->k.if_name, ifan->ifan_name,
1165
		    sizeof(kif->k.if_name));
1166
		break;
1167
	case IFAN_DEPARTURE:
1168
		kif = kif_find(ifan->ifan_index);
1169
		kif_remove(kif);
1170
		break;
1171
	}
1172
}
1173
1174
int
1175
fetchtable(struct ktable *kt)
1176
{
1177
	int			 mib[7];
1178
	size_t			 len;
1179
	char			*buf;
1180
	int			 rv;
1181
1182
	mib[0] = CTL_NET;
1183
	mib[1] = PF_ROUTE;
1184
	mib[2] = 0;
1185
	mib[3] = AF_INET;
1186
	mib[4] = NET_RT_DUMP;
1187
	mib[5] = 0;
1188
	mib[6] = kt->rtableid;
1189
1190
	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1191
		if (kt->rtableid != 0 && errno == EINVAL)
1192
			/* table nonexistent */
1193
			return (0);
1194
		log_warn("%s: failed to fetch routing table %u size", __func__,
1195
		    kt->rtableid);
1196
		return (-1);
1197
	}
1198
	if (len == 0)
1199
		return (0);
1200
	if ((buf = malloc(len)) == NULL) {
1201
		log_warn("%s: malloc", __func__);
1202
		return (-1);
1203
	}
1204
	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1205
		log_warn("%s: failed to fetch routing table %u", __func__,
1206
		    kt->rtableid);
1207
		free(buf);
1208
		return (-1);
1209
	}
1210
1211
	rv = rtmsg_process(buf, len);
1212
	free(buf);
1213
1214
	return (rv);
1215
}
1216
1217
int
1218
fetchifs(u_short if_index)
1219
{
1220
	size_t			 len;
1221
	int			 mib[6];
1222
	char			*buf;
1223
	int			 rv;
1224
1225
	mib[0] = CTL_NET;
1226
	mib[1] = PF_ROUTE;
1227
	mib[2] = 0;
1228
	mib[3] = 0;	/* wildcard address family */
1229
	mib[4] = NET_RT_IFLIST;
1230
	mib[5] = if_index;
1231
1232
	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
1233
		log_warn("%s: failed to fetch address table size for %u",
1234
		    __func__, if_index);
1235
		return (-1);
1236
	}
1237
	if ((buf = malloc(len)) == NULL) {
1238
		log_warn("%s: malloc", __func__);
1239
		return (-1);
1240
	}
1241
	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
1242
		log_warn("%s: failed to fetch address table for %u",
1243
		    __func__, if_index);
1244
		free(buf);
1245
		return (-1);
1246
	}
1247
1248
	rv = rtmsg_process(buf, len);
1249
	free(buf);
1250
1251
	return (rv);
1252
}
1253
1254
int
1255
fetcharp(struct ktable *kt)
1256
{
1257
	size_t			 len;
1258
	int			 mib[7];
1259
	char			*buf;
1260
	int			 rv;
1261
1262
	mib[0] = CTL_NET;
1263
	mib[1] = PF_ROUTE;
1264
	mib[2] = 0;
1265
	mib[3] = AF_INET;
1266
	mib[4] = NET_RT_FLAGS;
1267
	mib[5] = RTF_LLINFO;
1268
	mib[6] = kt->rtableid;
1269
1270
	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1271
		log_warn("%s: failed to fetch arp table %u size", __func__,
1272
		    kt->rtableid);
1273
		return (-1);
1274
	}
1275
	/* Empty table? */
1276
	if (len == 0)
1277
		return (0);
1278
	if ((buf = malloc(len)) == NULL) {
1279
		log_warn("%s: malloc", __func__);
1280
		return (-1);
1281
	}
1282
	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1283
		log_warn("%s: failed to fetch arp table %u", __func__,
1284
		    kt->rtableid);
1285
		free(buf);
1286
		return (-1);
1287
	}
1288
1289
	rv = rtmsg_process(buf, len);
1290
	free(buf);
1291
1292
	return (rv);
1293
}
1294
1295
/* ARGSUSED */
1296
void
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
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
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 *
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 *
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
}