1 /* $OpenBSD: kroute.c,v 1.36 2023/03/08 04:43:14 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/sysctl.h>
23 #include <sys/tree.h>
24 #include <sys/uio.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_types.h>
30 #include <net/route.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include "rip.h"
40 #include "ripd.h"
41 #include "log.h"
42
43 struct {
44 u_int32_t rtseq;
45 pid_t pid;
46 int fib_sync;
47 u_int8_t fib_prio;
48 int fd;
49 struct event ev;
50 u_int rdomain;
51 } kr_state;
52
53 struct kroute_node {
54 RB_ENTRY(kroute_node) entry;
55 struct kroute r;
56 };
57
58 struct kif_node {
59 RB_ENTRY(kif_node) entry;
60 struct kif k;
61 };
62
63 void kr_redistribute(int, struct kroute *);
64 int kroute_compare(struct kroute_node *, struct kroute_node *);
65 int kif_compare(struct kif_node *, struct kif_node *);
66 int kr_change_fib(struct kroute_node *, struct kroute *, int);
67
68 struct kroute_node *kroute_find(in_addr_t, in_addr_t, u_int8_t);
69 int kroute_insert(struct kroute_node *);
70 int kroute_remove(struct kroute_node *);
71 void kroute_clear(void);
72
73 struct kif_node *kif_find(int);
74 int kif_insert(struct kif_node *);
75 int kif_remove(struct kif_node *);
76 void kif_clear(void);
77 int kif_validate(int);
78
79 struct kroute_node *kroute_match(in_addr_t);
80
81 int protect_lo(void);
82 u_int8_t prefixlen_classful(in_addr_t);
83 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
84 void if_change(u_short, int, struct if_data *);
85 void if_announce(void *);
86
87 int send_rtmsg(int, int, struct kroute *);
88 int dispatch_rtmsg(void);
89 int fetchtable(void);
90 int fetchifs(int);
91
92 RB_HEAD(kroute_tree, kroute_node) krt;
93 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
94 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
95
96 RB_HEAD(kif_tree, kif_node) kit;
RB_PROTOTYPE(kif_tree,kif_node,entry,kif_compare)97 RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
98 RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
99
100 int
101 kif_init(void)
102 {
103 RB_INIT(&kit);
104
105 if (fetchifs(0) == -1)
106 return (-1);
107
108 return (0);
109 }
110
111 int
kr_init(int fs,u_int rdomain,u_int8_t fib_prio)112 kr_init(int fs, u_int rdomain, u_int8_t fib_prio)
113 {
114 int opt = 0, rcvbuf, default_rcvbuf;
115 socklen_t optlen;
116
117 if ((kr_state.fd = socket(AF_ROUTE,
118 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
119 log_warn("kr_init: socket");
120 return (-1);
121 }
122
123 /* not interested in my own messages */
124 if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
125 &opt, sizeof(opt)) == -1)
126 log_warn("kr_init: setsockopt"); /* not fatal */
127
128 /* grow receive buffer, don't wanna miss messages */
129 optlen = sizeof(default_rcvbuf);
130 if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
131 &default_rcvbuf, &optlen) == -1)
132 log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
133 else
134 for (rcvbuf = MAX_RTSOCK_BUF;
135 rcvbuf > default_rcvbuf &&
136 setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
137 &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
138 rcvbuf /= 2)
139 ; /* nothing */
140
141 kr_state.pid = getpid();
142 kr_state.rtseq = 1;
143 kr_state.fib_prio = fib_prio;
144
145 RB_INIT(&krt);
146
147 if (fetchtable() == -1)
148 return (-1);
149
150 if (protect_lo() == -1)
151 return (-1);
152
153 kr_state.fib_sync = fs; /* now set correct sync mode */
154 kr_state.rdomain = rdomain;
155
156 event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST,
157 kr_dispatch_msg, NULL);
158 event_add(&kr_state.ev, NULL);
159
160 return (0);
161 }
162
163 int
kr_change_fib(struct kroute_node * kr,struct kroute * kroute,int action)164 kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int action)
165 {
166 /* nexthop within 127/8 -> ignore silently */
167 if ((kroute->nexthop.s_addr & htonl(IN_CLASSA_NET)) ==
168 htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
169 return (0);
170
171 if (send_rtmsg(kr_state.fd, action, kroute) == -1)
172 return (-1);
173
174 if (action == RTM_ADD) {
175 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL)
176 fatal("kr_change_fib");
177
178 kr->r.prefix.s_addr = kroute->prefix.s_addr;
179 kr->r.netmask.s_addr = kroute->netmask.s_addr;
180 kr->r.nexthop.s_addr = kroute->nexthop.s_addr;
181 kr->r.flags = kroute->flags |= F_RIPD_INSERTED;
182 kr->r.priority = kr_state.fib_prio;
183
184 if (kroute_insert(kr) == -1) {
185 log_debug("kr_update_fib: cannot insert %s",
186 inet_ntoa(kroute->nexthop));
187 }
188 } else
189 kr->r.nexthop.s_addr = kroute->nexthop.s_addr;
190
191 return (0);
192 }
193
194 int
kr_change(struct kroute * kroute)195 kr_change(struct kroute *kroute)
196 {
197 struct kroute_node *kr;
198 int action = RTM_ADD;
199
200 kr = kroute_find(kroute->prefix.s_addr, kroute->netmask.s_addr,
201 kr_state.fib_prio);
202 if (kr != NULL)
203 action = RTM_CHANGE;
204
205 return (kr_change_fib(kr, kroute, action));
206 }
207
208 int
kr_delete(struct kroute * kroute)209 kr_delete(struct kroute *kroute)
210 {
211 struct kroute_node *kr;
212
213 kr = kroute_find(kroute->prefix.s_addr, kroute->netmask.s_addr,
214 kr_state.fib_prio);
215 if (kr == NULL)
216 return (0);
217
218 if (kr->r.priority != kr_state.fib_prio)
219 log_warn("kr_delete_fib: %s/%d has wrong priority %d",
220 inet_ntoa(kr->r.prefix), mask2prefixlen(kr->r.netmask.s_addr),
221 kr->r.priority);
222
223 if (send_rtmsg(kr_state.fd, RTM_DELETE, kroute) == -1)
224 return (-1);
225
226 if (kroute_remove(kr) == -1)
227 return (-1);
228
229 return (0);
230 }
231
232 void
kr_shutdown(void)233 kr_shutdown(void)
234 {
235 kr_fib_decouple();
236
237 kroute_clear();
238 kif_clear();
239 }
240
241 void
kr_fib_couple(void)242 kr_fib_couple(void)
243 {
244 struct kroute_node *kr;
245
246 if (kr_state.fib_sync == 1) /* already coupled */
247 return;
248
249 kr_state.fib_sync = 1;
250
251 RB_FOREACH(kr, kroute_tree, &krt)
252 if (kr->r.priority == kr_state.fib_prio)
253 send_rtmsg(kr_state.fd, RTM_ADD, &kr->r);
254
255 log_info("kernel routing table coupled");
256 }
257
258 void
kr_fib_decouple(void)259 kr_fib_decouple(void)
260 {
261 struct kroute_node *kr;
262
263 if (kr_state.fib_sync == 0) /* already decoupled */
264 return;
265
266 RB_FOREACH(kr, kroute_tree, &krt)
267 if (kr->r.priority == kr_state.fib_prio)
268 send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
269
270 kr_state.fib_sync = 0;
271
272 log_info("kernel routing table decoupled");
273 }
274
275 void
kr_dispatch_msg(int fd,short event,void * bula)276 kr_dispatch_msg(int fd, short event, void *bula)
277 {
278 dispatch_rtmsg();
279 }
280
281 void
kr_show_route(struct imsg * imsg)282 kr_show_route(struct imsg *imsg)
283 {
284 struct kroute_node *kr;
285 int flags;
286 struct in_addr addr;
287
288 switch (imsg->hdr.type) {
289 case IMSG_CTL_KROUTE:
290 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) {
291 log_warnx("kr_show_route: wrong imsg len");
292 return;
293 }
294 memcpy(&flags, imsg->data, sizeof(flags));
295 RB_FOREACH(kr, kroute_tree, &krt)
296 if (!flags || kr->r.flags & flags) {
297 main_imsg_compose_ripe(IMSG_CTL_KROUTE,
298 imsg->hdr.pid, &kr->r, sizeof(kr->r));
299 }
300 break;
301 case IMSG_CTL_KROUTE_ADDR:
302 if (imsg->hdr.len != IMSG_HEADER_SIZE +
303 sizeof(struct in_addr)) {
304 log_warnx("kr_show_route: wrong imsg len");
305 return;
306 }
307 memcpy(&addr, imsg->data, sizeof(addr));
308 kr = NULL;
309 kr = kroute_match(addr.s_addr);
310 if (kr != NULL)
311 main_imsg_compose_ripe(IMSG_CTL_KROUTE, imsg->hdr.pid,
312 &kr->r, sizeof(kr->r));
313 break;
314 default:
315 log_debug("kr_show_route: error handling imsg");
316 break;
317 }
318
319 main_imsg_compose_ripe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
320 }
321
322 void
kr_ifinfo(char * ifname,pid_t pid)323 kr_ifinfo(char *ifname, pid_t pid)
324 {
325 struct kif_node *kif;
326
327 RB_FOREACH(kif, kif_tree, &kit)
328 if (ifname == NULL || !strcmp(ifname, kif->k.ifname)) {
329 main_imsg_compose_ripe(IMSG_CTL_IFINFO,
330 pid, &kif->k, sizeof(kif->k));
331 }
332
333 main_imsg_compose_ripe(IMSG_CTL_END, pid, NULL, 0);
334 }
335
336 void
kr_redistribute(int type,struct kroute * kr)337 kr_redistribute(int type, struct kroute *kr)
338 {
339 u_int32_t a;
340
341
342 if (type == IMSG_NETWORK_DEL) {
343 dont_redistribute:
344 /* was the route redistributed? */
345 if (kr->flags & F_REDISTRIBUTED) {
346 /* remove redistributed flag */
347 kr->flags &= ~F_REDISTRIBUTED;
348 main_imsg_compose_rde(type, 0, kr,
349 sizeof(struct kroute));
350 }
351 return;
352 }
353
354 /* interface is not up and running so don't announce */
355 if (kr->flags & F_DOWN)
356 return;
357
358 /*
359 * We consider the loopback net and multicast addresses
360 * as not redistributable.
361 */
362 a = ntohl(kr->prefix.s_addr);
363 if (IN_MULTICAST(a) || (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
364 return;
365 /*
366 * Consider networks with nexthop loopback as not redistributable
367 * unless it is a reject or blackhole route.
368 */
369 if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK) &&
370 !(kr->flags & (F_BLACKHOLE|F_REJECT)))
371 return;
372
373 /* Should we redistribute this route? */
374 if (!rip_redistribute(kr))
375 goto dont_redistribute;
376
377 /* Does not matter if we resend the kr, the RDE will cope. */
378 kr->flags |= F_REDISTRIBUTED;
379 main_imsg_compose_rde(type, 0, kr, sizeof(struct kroute));
380 }
381
382 /* rb-tree compare */
383 int
kroute_compare(struct kroute_node * a,struct kroute_node * b)384 kroute_compare(struct kroute_node *a, struct kroute_node *b)
385 {
386 if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
387 return (-1);
388 if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
389 return (1);
390 if (ntohl(a->r.netmask.s_addr) < ntohl(b->r.netmask.s_addr))
391 return (-1);
392 if (ntohl(a->r.netmask.s_addr) > ntohl(b->r.netmask.s_addr))
393 return (1);
394
395 /* if the priority is RTP_ANY finish on the first address hit */
396 if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
397 return (0);
398 if (a->r.priority < b->r.priority)
399 return (-1);
400 if (a->r.priority > b->r.priority)
401 return (1);
402
403 return (0);
404 }
405
406 int
kif_compare(struct kif_node * a,struct kif_node * b)407 kif_compare(struct kif_node *a, struct kif_node *b)
408 {
409 return (b->k.ifindex - a->k.ifindex);
410 }
411
412 /* tree management */
413 struct kroute_node *
kroute_find(in_addr_t prefix,in_addr_t netmask,u_int8_t prio)414 kroute_find(in_addr_t prefix, in_addr_t netmask, u_int8_t prio)
415 {
416 struct kroute_node s, *kn, *tmp;
417
418 s.r.prefix.s_addr = prefix;
419 s.r.netmask.s_addr = netmask;
420 s.r.priority = prio;
421
422 kn = RB_FIND(kroute_tree, &krt, &s);
423 if (kn && prio == RTP_ANY) {
424 tmp = RB_PREV(kroute_tree, &krt, kn);
425 while (tmp) {
426 if (kroute_compare(&s, tmp) == 0)
427 kn = tmp;
428 else
429 break;
430 tmp = RB_PREV(kroute_tree, &krt, kn);
431 }
432 }
433
434 return (kn);
435 }
436
437 int
kroute_insert(struct kroute_node * kr)438 kroute_insert(struct kroute_node *kr)
439 {
440 if (RB_INSERT(kroute_tree, &krt, kr) != NULL) {
441 log_warnx("kroute_insert failed for %s/%u",
442 inet_ntoa(kr->r.prefix),
443 mask2prefixlen(kr->r.netmask.s_addr));
444 free(kr);
445 return (-1);
446 }
447
448 if (!(kr->r.flags & F_KERNEL)) {
449 /* don't validate or redistribute rip route */
450 kr->r.flags &= ~F_DOWN;
451 return (0);
452 }
453
454 if (kif_validate(kr->r.ifindex))
455 kr->r.flags &= ~F_DOWN;
456 else
457 kr->r.flags |= F_DOWN;
458
459 kr_redistribute(IMSG_NETWORK_ADD, &kr->r);
460
461 return (0);
462 }
463
464 int
kroute_remove(struct kroute_node * kr)465 kroute_remove(struct kroute_node *kr)
466 {
467 if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) {
468 log_warnx("kroute_remove failed for %s/%u",
469 inet_ntoa(kr->r.prefix),
470 mask2prefixlen(kr->r.netmask.s_addr));
471 return (-1);
472 }
473
474 kr_redistribute(IMSG_NETWORK_DEL, &kr->r);
475 rtlabel_unref(kr->r.rtlabel);
476
477 free(kr);
478 return (0);
479 }
480
481 void
kroute_clear(void)482 kroute_clear(void)
483 {
484 struct kroute_node *kr;
485
486 while ((kr = RB_MIN(kroute_tree, &krt)) != NULL)
487 kroute_remove(kr);
488 }
489
490 struct kif_node *
kif_find(int ifindex)491 kif_find(int ifindex)
492 {
493 struct kif_node s;
494
495 bzero(&s, sizeof(s));
496 s.k.ifindex = ifindex;
497
498 return (RB_FIND(kif_tree, &kit, &s));
499 }
500
501 struct kif *
kif_findname(char * ifname)502 kif_findname(char *ifname)
503 {
504 struct kif_node *kif;
505
506 RB_FOREACH(kif, kif_tree, &kit)
507 if (!strcmp(ifname, kif->k.ifname))
508 return (&kif->k);
509
510 return (NULL);
511 }
512
513 int
kif_insert(struct kif_node * kif)514 kif_insert(struct kif_node *kif)
515 {
516 if (RB_INSERT(kif_tree, &kit, kif) != NULL) {
517 log_warnx("RB_INSERT(kif_tree, &kit, kif)");
518 free(kif);
519 return (-1);
520 }
521
522 return (0);
523 }
524
525 int
kif_remove(struct kif_node * kif)526 kif_remove(struct kif_node *kif)
527 {
528 if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
529 log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
530 return (-1);
531 }
532
533 free(kif);
534 return (0);
535 }
536
537 void
kif_clear(void)538 kif_clear(void)
539 {
540 struct kif_node *kif;
541
542 while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
543 kif_remove(kif);
544 }
545
546 int
kif_validate(int ifindex)547 kif_validate(int ifindex)
548 {
549 struct kif_node *kif;
550
551 if ((kif = kif_find(ifindex)) == NULL) {
552 log_warnx("interface with index %u not found", ifindex);
553 return (1);
554 }
555
556 return (kif->k.nh_reachable);
557 }
558
559 struct kroute_node *
kroute_match(in_addr_t key)560 kroute_match(in_addr_t key)
561 {
562 u_int8_t i;
563 struct kroute_node *kr;
564
565 /* we will never match the default route */
566 for (i = 32; i > 0; i--)
567 if ((kr = kroute_find(key & prefixlen2mask(i),
568 prefixlen2mask(i), RTP_ANY)) != NULL)
569 return (kr);
570
571 /* if we don't have a match yet, try to find a default route */
572 if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL)
573 return (kr);
574
575 return (NULL);
576 }
577
578 /* misc */
579 int
protect_lo(void)580 protect_lo(void)
581 {
582 struct kroute_node *kr;
583
584 /* special protection for 127/8 */
585 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
586 log_warn("protect_lo");
587 return (-1);
588 }
589 kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK);
590 kr->r.netmask.s_addr = htonl(IN_CLASSA_NET);
591 kr->r.flags = F_KERNEL|F_CONNECTED;
592
593 if (RB_INSERT(kroute_tree, &krt, kr) != NULL)
594 free(kr); /* kernel route already there, no problem */
595
596 return (0);
597 }
598
599 u_int8_t
prefixlen_classful(in_addr_t ina)600 prefixlen_classful(in_addr_t ina)
601 {
602 /* it hurt to write this. */
603
604 if (ina >= 0xf0000000U) /* class E */
605 return (32);
606 else if (ina >= 0xe0000000U) /* class D */
607 return (4);
608 else if (ina >= 0xc0000000U) /* class C */
609 return (24);
610 else if (ina >= 0x80000000U) /* class B */
611 return (16);
612 else /* class A */
613 return (8);
614 }
615
616 u_int8_t
mask2prefixlen(in_addr_t ina)617 mask2prefixlen(in_addr_t ina)
618 {
619 if (ina == 0)
620 return (0);
621 else
622 return (33 - ffs(ntohl(ina)));
623 }
624
625 in_addr_t
prefixlen2mask(u_int8_t prefixlen)626 prefixlen2mask(u_int8_t prefixlen)
627 {
628 if (prefixlen == 0)
629 return (0);
630
631 return (htonl(0xffffffff << (32 - prefixlen)));
632 }
633
634 #define ROUNDUP(a) \
635 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
636
637 void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)638 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
639 {
640 int i;
641
642 for (i = 0; i < RTAX_MAX; i++) {
643 if (addrs & (1 << i)) {
644 rti_info[i] = sa;
645 sa = (struct sockaddr *)((char *)(sa) +
646 ROUNDUP(sa->sa_len));
647 } else
648 rti_info[i] = NULL;
649 }
650 }
651
652 void
if_change(u_short ifindex,int flags,struct if_data * ifd)653 if_change(u_short ifindex, int flags, struct if_data *ifd)
654 {
655 struct kif_node *kif;
656 struct kroute_node *kr;
657 int type;
658 u_int8_t reachable;
659
660 if ((kif = kif_find(ifindex)) == NULL) {
661 log_warnx("interface with index %u not found", ifindex);
662 return;
663 }
664
665 kif->k.flags = flags;
666 kif->k.link_state = ifd->ifi_link_state;
667 kif->k.if_type = ifd->ifi_type;
668 kif->k.baudrate = ifd->ifi_baudrate;
669
670 if ((reachable = (flags & IFF_UP) &&
671 LINK_STATE_IS_UP(ifd->ifi_link_state)) == kif->k.nh_reachable)
672 return; /* nothing changed wrt nexthop validity */
673
674 kif->k.nh_reachable = reachable;
675 type = reachable ? IMSG_NETWORK_ADD : IMSG_NETWORK_DEL;
676
677 /* notify ripe about interface link state */
678 main_imsg_compose_ripe(IMSG_IFINFO, 0, &kif->k, sizeof(kif->k));
679
680 /* update redistribute list */
681 RB_FOREACH(kr, kroute_tree, &krt)
682 if (kr->r.ifindex == ifindex) {
683 if (reachable)
684 kr->r.flags &= ~F_DOWN;
685 else
686 kr->r.flags |= F_DOWN;
687
688 kr_redistribute(type, &kr->r);
689 }
690 }
691
692 void
if_announce(void * msg)693 if_announce(void *msg)
694 {
695 struct if_announcemsghdr *ifan;
696 struct kif_node *kif;
697
698 ifan = msg;
699
700 switch (ifan->ifan_what) {
701 case IFAN_ARRIVAL:
702 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
703 log_warn("if_announce");
704 return;
705 }
706
707 kif->k.ifindex = ifan->ifan_index;
708 strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
709 kif_insert(kif);
710 break;
711 case IFAN_DEPARTURE:
712 kif = kif_find(ifan->ifan_index);
713 kif_remove(kif);
714 break;
715 }
716 }
717
718 /* rtsock */
719 int
send_rtmsg(int fd,int action,struct kroute * kroute)720 send_rtmsg(int fd, int action, struct kroute *kroute)
721 {
722 struct iovec iov[4];
723 struct rt_msghdr hdr;
724 struct sockaddr_in prefix;
725 struct sockaddr_in nexthop;
726 struct sockaddr_in mask;
727 int iovcnt = 0;
728
729 if (kr_state.fib_sync == 0)
730 return (0);
731
732 /* initialize header */
733 bzero(&hdr, sizeof(hdr));
734 hdr.rtm_version = RTM_VERSION;
735 hdr.rtm_type = action;
736 hdr.rtm_priority = kr_state.fib_prio;
737 hdr.rtm_tableid = kr_state.rdomain;
738 if (action == RTM_CHANGE)
739 hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
740 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
741 hdr.rtm_msglen = sizeof(hdr);
742 /* adjust iovec */
743 iov[iovcnt].iov_base = &hdr;
744 iov[iovcnt++].iov_len = sizeof(hdr);
745
746 bzero(&prefix, sizeof(prefix));
747 prefix.sin_len = sizeof(prefix);
748 prefix.sin_family = AF_INET;
749 prefix.sin_addr.s_addr = kroute->prefix.s_addr;
750 /* adjust header */
751 hdr.rtm_addrs |= RTA_DST;
752 hdr.rtm_msglen += sizeof(prefix);
753 /* adjust iovec */
754 iov[iovcnt].iov_base = &prefix;
755 iov[iovcnt++].iov_len = sizeof(prefix);
756
757 if (kroute->nexthop.s_addr != 0) {
758 bzero(&nexthop, sizeof(nexthop));
759 nexthop.sin_len = sizeof(nexthop);
760 nexthop.sin_family = AF_INET;
761 nexthop.sin_addr.s_addr = kroute->nexthop.s_addr;
762 /* adjust header */
763 hdr.rtm_flags |= RTF_GATEWAY;
764 hdr.rtm_addrs |= RTA_GATEWAY;
765 hdr.rtm_msglen += sizeof(nexthop);
766 /* adjust iovec */
767 iov[iovcnt].iov_base = &nexthop;
768 iov[iovcnt++].iov_len = sizeof(nexthop);
769 }
770
771 bzero(&mask, sizeof(mask));
772 mask.sin_len = sizeof(mask);
773 mask.sin_family = AF_INET;
774 mask.sin_addr.s_addr = kroute->netmask.s_addr;
775 /* adjust header */
776 hdr.rtm_addrs |= RTA_NETMASK;
777 hdr.rtm_msglen += sizeof(mask);
778 /* adjust iovec */
779 iov[iovcnt].iov_base = &mask;
780 iov[iovcnt++].iov_len = sizeof(mask);
781
782
783 retry:
784 if (writev(fd, iov, iovcnt) == -1) {
785 if (errno == ESRCH) {
786 if (hdr.rtm_type == RTM_CHANGE) {
787 hdr.rtm_type = RTM_ADD;
788 goto retry;
789 } else if (hdr.rtm_type == RTM_DELETE) {
790 log_info("route %s/%u vanished before delete",
791 inet_ntoa(kroute->prefix),
792 mask2prefixlen(kroute->netmask.s_addr));
793 return (0);
794 }
795 }
796 log_warn("send_rtmsg: action %u, prefix %s/%u",
797 hdr.rtm_type, inet_ntoa(kroute->prefix),
798 mask2prefixlen(kroute->netmask.s_addr));
799 return (0);
800 }
801
802 return (0);
803 }
804
805 int
fetchtable(void)806 fetchtable(void)
807 {
808 size_t len;
809 int mib[7];
810 char *buf, *next, *lim;
811 struct rt_msghdr *rtm;
812 struct sockaddr *sa, *rti_info[RTAX_MAX];
813 struct sockaddr_in *sa_in;
814 struct sockaddr_rtlabel *label;
815 struct kroute_node *kr;
816 struct iface *iface = NULL;
817
818 mib[0] = CTL_NET;
819 mib[1] = PF_ROUTE;
820 mib[2] = 0;
821 mib[3] = AF_INET;
822 mib[4] = NET_RT_DUMP;
823 mib[5] = 0;
824 mib[6] = kr_state.rdomain; /* rtableid */
825
826 if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
827 log_warn("sysctl");
828 return (-1);
829 }
830 if ((buf = malloc(len)) == NULL) {
831 log_warn("fetchtable");
832 return (-1);
833 }
834 if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
835 log_warn("sysctl");
836 free(buf);
837 return (-1);
838 }
839
840 lim = buf + len;
841 for (next = buf; next < lim; next += rtm->rtm_msglen) {
842 rtm = (struct rt_msghdr *)next;
843 if (rtm->rtm_version != RTM_VERSION)
844 continue;
845 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
846 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
847
848 if ((sa = rti_info[RTAX_DST]) == NULL)
849 continue;
850
851 /* Skip ARP/ND cache and broadcast routes. */
852 if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
853 continue;
854
855 #ifdef RTF_MPATH
856 if (rtm->rtm_flags & RTF_MPATH) /* multipath */
857 continue;
858 #endif
859
860 if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
861 log_warn("fetchtable");
862 free(buf);
863 return (-1);
864 }
865
866 kr->r.flags = F_KERNEL;
867 kr->r.priority = rtm->rtm_priority;
868
869 switch (sa->sa_family) {
870 case AF_INET:
871 kr->r.prefix.s_addr =
872 ((struct sockaddr_in *)sa)->sin_addr.s_addr;
873 sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
874 if (rtm->rtm_flags & RTF_STATIC)
875 kr->r.flags |= F_STATIC;
876 if (rtm->rtm_flags & RTF_BLACKHOLE)
877 kr->r.flags |= F_BLACKHOLE;
878 if (rtm->rtm_flags & RTF_REJECT)
879 kr->r.flags |= F_REJECT;
880 if (rtm->rtm_flags & RTF_DYNAMIC)
881 kr->r.flags |= F_DYNAMIC;
882 if (sa_in != NULL) {
883 if (sa_in->sin_len == 0)
884 break;
885 kr->r.netmask.s_addr =
886 sa_in->sin_addr.s_addr;
887 } else if (rtm->rtm_flags & RTF_HOST)
888 kr->r.netmask.s_addr = prefixlen2mask(32);
889 else
890 kr->r.netmask.s_addr =
891 prefixlen2mask(prefixlen_classful
892 (kr->r.prefix.s_addr));
893 break;
894 default:
895 free(kr);
896 continue;
897 }
898
899 kr->r.ifindex = rtm->rtm_index;
900
901 iface = if_find_index(rtm->rtm_index);
902 if (iface != NULL)
903 kr->r.metric = iface->cost;
904 else
905 kr->r.metric = DEFAULT_COST;
906
907 if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
908 switch (sa->sa_family) {
909 case AF_INET:
910 if (rtm->rtm_flags & RTF_CONNECTED) {
911 kr->r.flags |= F_CONNECTED;
912 break;
913 }
914
915 kr->r.nexthop.s_addr =
916 ((struct sockaddr_in *)sa)->sin_addr.s_addr;
917 break;
918 case AF_LINK:
919 /*
920 * Traditional BSD connected routes have
921 * a gateway of type AF_LINK.
922 */
923 kr->r.flags |= F_CONNECTED;
924 break;
925 }
926
927 if (rtm->rtm_priority == kr_state.fib_prio) {
928 send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
929 free(kr);
930 } else {
931 if ((label = (struct sockaddr_rtlabel *)
932 rti_info[RTAX_LABEL]) != NULL)
933 kr->r.rtlabel =
934 rtlabel_name2id(label->sr_label);
935 kroute_insert(kr);
936 }
937
938 }
939 free(buf);
940 return (0);
941 }
942
943 int
fetchifs(int ifindex)944 fetchifs(int ifindex)
945 {
946 size_t len;
947 int mib[6];
948 char *buf, *next, *lim;
949 struct if_msghdr ifm;
950 struct kif_node *kif;
951 struct sockaddr *sa, *rti_info[RTAX_MAX];
952 struct sockaddr_dl *sdl;
953
954 mib[0] = CTL_NET;
955 mib[1] = PF_ROUTE;
956 mib[2] = 0;
957 mib[3] = AF_INET;
958 mib[4] = NET_RT_IFLIST;
959 mib[5] = ifindex;
960
961 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
962 log_warn("sysctl");
963 return (-1);
964 }
965 if ((buf = malloc(len)) == NULL) {
966 log_warn("fetchif");
967 return (-1);
968 }
969 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
970 log_warn("sysctl");
971 free(buf);
972 return (-1);
973 }
974
975 lim = buf + len;
976 for (next = buf; next < lim; next += ifm.ifm_msglen) {
977 memcpy(&ifm, next, sizeof(ifm));
978 if (ifm.ifm_version != RTM_VERSION)
979 continue;
980 if (ifm.ifm_type != RTM_IFINFO)
981 continue;
982
983 sa = (struct sockaddr *)(next + sizeof(ifm));
984 get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
985
986 if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
987 log_warn("fetchifs");
988 free(buf);
989 return (-1);
990 }
991
992 kif->k.ifindex = ifm.ifm_index;
993 kif->k.flags = ifm.ifm_flags;
994 kif->k.link_state = ifm.ifm_data.ifi_link_state;
995 kif->k.if_type = ifm.ifm_data.ifi_type;
996 kif->k.baudrate = ifm.ifm_data.ifi_baudrate;
997 kif->k.mtu = ifm.ifm_data.ifi_mtu;
998 kif->k.nh_reachable = (kif->k.flags & IFF_UP) &&
999 LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state);
1000 if ((sa = rti_info[RTAX_IFP]) != NULL)
1001 if (sa->sa_family == AF_LINK) {
1002 sdl = (struct sockaddr_dl *)sa;
1003 if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
1004 memcpy(kif->k.ifname, sdl->sdl_data,
1005 sizeof(kif->k.ifname) - 1);
1006 else if (sdl->sdl_nlen > 0)
1007 memcpy(kif->k.ifname, sdl->sdl_data,
1008 sdl->sdl_nlen);
1009 /* string already terminated via calloc() */
1010 }
1011
1012 kif_insert(kif);
1013 }
1014 free(buf);
1015 return (0);
1016 }
1017
1018 int
dispatch_rtmsg(void)1019 dispatch_rtmsg(void)
1020 {
1021 char buf[RT_BUF_SIZE];
1022 ssize_t n;
1023 char *next, *lim;
1024 struct rt_msghdr *rtm;
1025 struct if_msghdr ifm;
1026 struct sockaddr *sa, *rti_info[RTAX_MAX];
1027 struct sockaddr_in *sa_in;
1028 struct sockaddr_rtlabel *label;
1029 struct kroute_node *kr;
1030 struct in_addr prefix, nexthop, netmask;
1031 struct iface *iface = NULL;
1032 int flags;
1033 u_short ifindex = 0;
1034 u_int8_t metric, prio;
1035
1036 if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1037 if (errno == EAGAIN || errno == EINTR)
1038 return (0);
1039 log_warn("dispatch_rtmsg: read error");
1040 return (-1);
1041 }
1042
1043 if (n == 0) {
1044 log_warnx("routing socket closed");
1045 return (-1);
1046 }
1047
1048 lim = buf + n;
1049 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1050 rtm = (struct rt_msghdr *)next;
1051 if (lim < next + sizeof(u_short) ||
1052 lim < next + rtm->rtm_msglen)
1053 fatalx("dispatch_rtmsg: partial rtm in buffer");
1054 if (rtm->rtm_version != RTM_VERSION)
1055 continue;
1056
1057 prefix.s_addr = 0;
1058 netmask.s_addr = 0;
1059 flags = F_KERNEL;
1060 nexthop.s_addr = 0;
1061 prio = 0;
1062
1063 if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE ||
1064 rtm->rtm_type == RTM_DELETE) {
1065 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1066 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1067
1068 if (rtm->rtm_tableid != kr_state.rdomain)
1069 continue;
1070
1071 if (rtm->rtm_pid == kr_state.pid) /* cause by us */
1072 continue;
1073
1074 if (rtm->rtm_errno) /* failed attempts... */
1075 continue;
1076
1077 /* Skip ARP/ND cache and broadcast routes. */
1078 if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
1079 continue;
1080
1081 prio = rtm->rtm_priority;
1082
1083 switch (sa->sa_family) {
1084 case AF_INET:
1085 prefix.s_addr =
1086 ((struct sockaddr_in *)sa)->sin_addr.s_addr;
1087 sa_in = (struct sockaddr_in *)
1088 rti_info[RTAX_NETMASK];
1089 if (sa_in != NULL) {
1090 if (sa_in->sin_len != 0)
1091 netmask.s_addr =
1092 sa_in->sin_addr.s_addr;
1093 } else if (rtm->rtm_flags & RTF_HOST)
1094 netmask.s_addr = prefixlen2mask(32);
1095 else
1096 netmask.s_addr =
1097 prefixlen2mask(prefixlen_classful(
1098 prefix.s_addr));
1099 if (rtm->rtm_flags & RTF_STATIC)
1100 flags |= F_STATIC;
1101 if (rtm->rtm_flags & RTF_BLACKHOLE)
1102 flags |= F_BLACKHOLE;
1103 if (rtm->rtm_flags & RTF_REJECT)
1104 flags |= F_REJECT;
1105 if (rtm->rtm_flags & RTF_DYNAMIC)
1106 flags |= F_DYNAMIC;
1107 break;
1108 default:
1109 continue;
1110 }
1111
1112 ifindex = rtm->rtm_index;
1113 if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
1114 switch (sa->sa_family) {
1115 case AF_INET:
1116 nexthop.s_addr = ((struct
1117 sockaddr_in *)sa)->sin_addr.s_addr;
1118 break;
1119 case AF_LINK:
1120 flags |= F_CONNECTED;
1121 break;
1122 }
1123 }
1124 }
1125
1126 switch (rtm->rtm_type) {
1127 case RTM_ADD:
1128 case RTM_CHANGE:
1129 if (nexthop.s_addr == 0 && !(flags & F_CONNECTED)) {
1130 log_warnx("dispatch_rtmsg no nexthop for %s/%u",
1131 inet_ntoa(prefix),
1132 mask2prefixlen(netmask.s_addr));
1133 continue;
1134 }
1135
1136 if ((kr = kroute_find(prefix.s_addr, netmask.s_addr,
1137 prio)) != NULL) {
1138 if (kr->r.flags & F_REDISTRIBUTED)
1139 flags |= F_REDISTRIBUTED;
1140 kr->r.nexthop.s_addr = nexthop.s_addr;
1141 kr->r.flags = flags;
1142 kr->r.ifindex = ifindex;
1143 kr->r.priority = prio;
1144
1145 rtlabel_unref(kr->r.rtlabel);
1146 kr->r.rtlabel = 0;
1147 if ((label = (struct sockaddr_rtlabel *)
1148 rti_info[RTAX_LABEL]) != NULL)
1149 kr->r.rtlabel =
1150 rtlabel_name2id(label->sr_label);
1151
1152 if (kif_validate(kr->r.ifindex))
1153 kr->r.flags &= ~F_DOWN;
1154 else
1155 kr->r.flags |= F_DOWN;
1156
1157 /* just readd, the RDE will care */
1158 kr_redistribute(IMSG_NETWORK_ADD, &kr->r);
1159 } else {
1160 if ((kr = calloc(1,
1161 sizeof(struct kroute_node))) == NULL) {
1162 log_warn("dispatch_rtmsg");
1163 return (-1);
1164 }
1165
1166 iface = if_find_index(rtm->rtm_index);
1167 if (iface != NULL)
1168 metric = iface->cost;
1169 else
1170 metric = DEFAULT_COST;
1171
1172 kr->r.prefix.s_addr = prefix.s_addr;
1173 kr->r.netmask.s_addr = netmask.s_addr;
1174 kr->r.nexthop.s_addr = nexthop.s_addr;
1175 kr->r.metric = metric;
1176 kr->r.flags = flags;
1177 kr->r.ifindex = ifindex;
1178
1179 if ((label = (struct sockaddr_rtlabel *)
1180 rti_info[RTAX_LABEL]) != NULL)
1181 kr->r.rtlabel =
1182 rtlabel_name2id(label->sr_label);
1183
1184 kroute_insert(kr);
1185 }
1186 break;
1187 case RTM_DELETE:
1188 if ((kr = kroute_find(prefix.s_addr, netmask.s_addr,
1189 prio)) == NULL)
1190 continue;
1191 if (!(kr->r.flags & F_KERNEL))
1192 continue;
1193 if (kroute_remove(kr) == -1)
1194 return (-1);
1195 break;
1196 case RTM_IFINFO:
1197 memcpy(&ifm, next, sizeof(ifm));
1198 if_change(ifm.ifm_index, ifm.ifm_flags,
1199 &ifm.ifm_data);
1200 break;
1201 case RTM_IFANNOUNCE:
1202 if_announce(next);
1203 break;
1204 default:
1205 /* ignore for now */
1206 break;
1207 }
1208 }
1209 return (0);
1210 }
1211