1: /*
2: * BIRD -- BSD Routing Table Syncing
3: *
4: * (c) 2004 Ondrej Filip <feela@network.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: #include <stdio.h>
10: #include <stdlib.h>
11: #include <ctype.h>
12: #include <fcntl.h>
13: #include <unistd.h>
14: #include <sys/param.h>
15: #include <sys/types.h>
16: #include <sys/socket.h>
17: #include <sys/sysctl.h>
18: #include <sys/ioctl.h>
19: #include <netinet/in.h>
20: #include <net/route.h>
21: #include <net/if.h>
22: #include <net/if_dl.h>
23:
24: #undef LOCAL_DEBUG
25:
26: #include "nest/bird.h"
27: #include "nest/iface.h"
28: #include "nest/route.h"
29: #include "nest/protocol.h"
30: #include "nest/iface.h"
31: #include "sysdep/unix/unix.h"
32: #include "sysdep/unix/krt.h"
33: #include "lib/string.h"
34: #include "lib/socket.h"
35:
36: const int rt_default_ecmp = 0;
37:
38: /*
39: * There are significant differences in multiple tables support between BSD variants.
40: *
41: * OpenBSD has table_id field for routes in route socket protocol, therefore all
42: * tables could be managed by one kernel socket. FreeBSD lacks such field,
43: * therefore multiple sockets (locked to specific table using SO_SETFIB socket
44: * option) must be used.
45: *
46: * Both FreeBSD and OpenBSD uses separate scans for each table. In OpenBSD,
47: * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it
48: * is handled implicitly by changing default table using setfib() syscall.
49: *
50: * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto
51: * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan
52: * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets
53: * KRT_USE_SYSCTL_7 - use 7-th arg of sysctl() as table id for route scans
54: * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs
55: */
56:
57: #ifdef __FreeBSD__
58: #define KRT_MAX_TABLES 256
59: #define KRT_USE_SETFIB_SCAN
60: #define KRT_USE_SETFIB_SOCK
61: #define KRT_USE_SYSCTL_NET_FIBS
62: #endif
63:
64: #ifdef __OpenBSD__
65: #define KRT_MAX_TABLES (RT_TABLEID_MAX+1)
66: #define KRT_SHARED_SOCKET
67: #define KRT_USE_SYSCTL_7
68: #endif
69:
70: #ifndef KRT_MAX_TABLES
71: #define KRT_MAX_TABLES 1
72: #endif
73:
74:
75: /* Dynamic max number of tables */
76:
77: uint krt_max_tables;
78:
79: #ifdef KRT_USE_SYSCTL_NET_FIBS
80:
81: static uint
82: krt_get_max_tables(void)
83: {
84: int fibs;
85: size_t fibs_len = sizeof(fibs);
86:
87: if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0)
88: {
89: log(L_WARN "KRT: unable to get max number of fib tables: %m");
90: return 1;
91: }
92:
93: /* Should not happen */
94: if (fibs < 1)
95: return 1;
96:
97: return (uint) MIN(fibs, KRT_MAX_TABLES);
98: }
99:
100: #else
101:
102: static int
103: krt_get_max_tables(void)
104: {
105: return KRT_MAX_TABLES;
106: }
107:
108: #endif /* KRT_USE_SYSCTL_NET_FIBS */
109:
110:
111: /* setfib() syscall for FreeBSD scans */
112:
113: #ifdef KRT_USE_SETFIB_SCAN
114:
115: /*
116: static int krt_default_fib;
117:
118: static int
119: krt_get_active_fib(void)
120: {
121: int fib;
122: size_t fib_len = sizeof(fib);
123:
124: if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0)
125: {
126: log(L_WARN "KRT: unable to get active fib number: %m");
127: return 0;
128: }
129:
130: return fib;
131: }
132: */
133:
134: extern int setfib(int fib);
135:
136: #endif /* KRT_USE_SETFIB_SCAN */
137:
138:
139: /* table_id -> krt_proto map */
140:
141: #ifdef KRT_SHARED_SOCKET
142: static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2];
143: #endif
144:
145:
146: /* Route socket message processing */
147:
148: int
149: krt_capable(rte *e)
150: {
151: rta *a = e->attrs;
152:
153: return
154: ((a->dest == RTD_UNICAST && !a->nh.next) /* No multipath support */
155: #ifdef RTF_REJECT
156: || a->dest == RTD_UNREACHABLE
157: #endif
158: #ifdef RTF_BLACKHOLE
159: || a->dest == RTD_BLACKHOLE
160: #endif
161: );
162: }
163:
164: #ifndef RTAX_MAX
165: #define RTAX_MAX 8
166: #endif
167:
168: struct ks_msg
169: {
170: struct rt_msghdr rtm;
171: struct sockaddr_storage buf[RTAX_MAX];
172: } PACKED;
173:
174: #define ROUNDUP(a) \
175: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
176:
177: #define NEXTADDR(w, u) \
178: if (msg.rtm.rtm_addrs & (w)) {\
179: l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
180: memmove(body, &(u), l); body += l;}
181:
182: #define GETADDR(p, F) \
183: bzero(p, sizeof(*p));\
184: if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
185: uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
186: memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
187: body += l;}
188:
189: static inline void
190: sockaddr_fill_dl(struct sockaddr_dl *sa, struct iface *ifa)
191: {
192: uint len = OFFSETOF(struct sockaddr_dl, sdl_data);
193: memset(sa, 0, len);
194: sa->sdl_len = len;
195: sa->sdl_family = AF_LINK;
196: sa->sdl_index = ifa->index;
197: }
198:
199: static int
200: krt_send_route(struct krt_proto *p, int cmd, rte *e)
201: {
202: net *net = e->net;
203: rta *a = e->attrs;
204: static int msg_seq;
205: struct iface *j, *i = a->nh.iface;
206: int l;
207: struct ks_msg msg;
208: char *body = (char *)msg.buf;
209: sockaddr gate, mask, dst;
210:
211: DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
212:
213: bzero(&msg,sizeof (struct rt_msghdr));
214: msg.rtm.rtm_version = RTM_VERSION;
215: msg.rtm.rtm_type = cmd;
216: msg.rtm.rtm_seq = msg_seq++;
217: msg.rtm.rtm_addrs = RTA_DST;
218: msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
219:
220: /* XXXX */
221: if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
222: msg.rtm.rtm_flags |= RTF_HOST;
223: else
224: msg.rtm.rtm_addrs |= RTA_NETMASK;
225:
226: #ifdef KRT_SHARED_SOCKET
227: msg.rtm.rtm_tableid = KRT_CF->sys.table_id;
228: #endif
229:
230: #ifdef RTF_REJECT
231: if(a->dest == RTD_UNREACHABLE)
232: msg.rtm.rtm_flags |= RTF_REJECT;
233: #endif
234: #ifdef RTF_BLACKHOLE
235: if(a->dest == RTD_BLACKHOLE)
236: msg.rtm.rtm_flags |= RTF_BLACKHOLE;
237: #endif
238:
239: /*
240: * This is really very nasty, but I'm not able to add reject/blackhole route
241: * without gateway address.
242: */
243: if (!i)
244: {
245: WALK_LIST(j, iface_list)
246: {
247: if (j->flags & IF_LOOPBACK)
248: {
249: i = j;
250: break;
251: }
252: }
253:
254: if (!i)
255: {
256: log(L_ERR "KRT: Cannot find loopback iface");
257: return -1;
258: }
259: }
260:
261: int af = AF_UNSPEC;
262:
263: switch (net->n.addr->type) {
264: case NET_IP4:
265: af = AF_INET;
266: break;
267: case NET_IP6:
268: af = AF_INET6;
269: break;
270: default:
271: log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
272: return -1;
273: }
274:
275: sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
276: sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
277:
278: switch (a->dest)
279: {
280: case RTD_UNICAST:
281: if (ipa_nonzero(a->nh.gw))
282: {
283: ip_addr gw = a->nh.gw;
284:
285: /* Embed interface ID to link-local address */
286: if (ipa_is_link_local(gw))
287: _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
288:
289: sockaddr_fill(&gate, af, gw, NULL, 0);
290: msg.rtm.rtm_flags |= RTF_GATEWAY;
291: msg.rtm.rtm_addrs |= RTA_GATEWAY;
292: break;
293: }
294:
295: #ifdef RTF_REJECT
296: case RTD_UNREACHABLE:
297: #endif
298: #ifdef RTF_BLACKHOLE
299: case RTD_BLACKHOLE:
300: #endif
301: {
302: /* Fallback for all other valid cases */
303:
304: #if __OpenBSD__
305: /* Keeping temporarily old code for OpenBSD */
306: struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
307:
308: if (!addr)
309: {
310: log(L_ERR "KRT: interface %s has no IP addess", i->name);
311: return -1;
312: }
313:
314: /* Embed interface ID to link-local address */
315: ip_addr gw = addr->ip;
316: if (ipa_is_link_local(gw))
317: _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
318:
319: sockaddr_fill(&gate, af, gw, i, 0);
320: #else
321: sockaddr_fill_dl(&gate, i);
322: #endif
323:
324: msg.rtm.rtm_addrs |= RTA_GATEWAY;
325: break;
326: }
327:
328: default:
329: bug("krt-sock: unknown flags, but not filtered");
330: }
331:
332: msg.rtm.rtm_index = i->index;
333:
334: NEXTADDR(RTA_DST, dst);
335: NEXTADDR(RTA_GATEWAY, gate);
336: NEXTADDR(RTA_NETMASK, mask);
337:
338: l = body - (char *)&msg;
339: msg.rtm.rtm_msglen = l;
340:
341: if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
342: log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
343: return -1;
344: }
345:
346: return 0;
347: }
348:
349: void
350: krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
351: {
352: int err = 0;
353:
354: if (old)
355: krt_send_route(p, RTM_DELETE, old);
356:
357: if (new)
358: err = krt_send_route(p, RTM_ADD, new);
359:
360: if (err < 0)
361: n->n.flags |= KRF_SYNC_ERROR;
362: else
363: n->n.flags &= ~KRF_SYNC_ERROR;
364: }
365:
366: #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
367:
368: static void
369: krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
370: {
371: /* p is NULL iff KRT_SHARED_SOCKET and !scan */
372:
373: int ipv6;
374: rte *e;
375: net *net;
376: sockaddr dst, gate, mask;
377: ip_addr idst, igate, imask;
378: net_addr ndst;
379: void *body = (char *)msg->buf;
380: int new = (msg->rtm.rtm_type != RTM_DELETE);
381: char *errmsg = "KRT: Invalid route received";
382: int flags = msg->rtm.rtm_flags;
383: int addrs = msg->rtm.rtm_addrs;
384: int src;
385: byte src2;
386:
387: if (!(flags & RTF_UP) && scan)
388: SKIP("not up in scan\n");
389:
390: if (!(flags & RTF_DONE) && !scan)
391: SKIP("not done in async\n");
392:
393: if (flags & RTF_LLINFO)
394: SKIP("link-local\n");
395:
396: GETADDR(&dst, RTA_DST);
397: GETADDR(&gate, RTA_GATEWAY);
398: GETADDR(&mask, RTA_NETMASK);
399:
400: switch (dst.sa.sa_family) {
401: case AF_INET:
402: ipv6 = 0;
403: break;
404: case AF_INET6:
405: ipv6 = 1;
406: break;
407: default:
408: SKIP("invalid DST");
409: }
410:
411: /* We do not test family for RTA_NETMASK, because BSD sends us
412: some strange values, but interpreting them as IPv4/IPv6 works */
413: mask.sa.sa_family = dst.sa.sa_family;
414:
415: idst = ipa_from_sa(&dst);
416: imask = ipa_from_sa(&mask);
417: igate = (gate.sa.sa_family == dst.sa.sa_family) ? ipa_from_sa(&gate) : IPA_NONE;
418:
419: #ifdef KRT_SHARED_SOCKET
420: if (!scan)
421: {
422: int table_id = msg->rtm.rtm_tableid;
423: p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL;
424:
425: if (!p)
426: SKIP("unknown table id %d\n", table_id);
427: }
428: #endif
429: if ((!ipv6) && (p->p.main_channel->table->addr_type != NET_IP4))
430: SKIP("reading only IPv4 routes");
431: if ( ipv6 && (p->p.main_channel->table->addr_type != NET_IP6))
432: SKIP("reading only IPv6 routes");
433:
434: int c = ipa_classify_net(idst);
435: if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
436: SKIP("strange class/scope\n");
437:
438: int pxlen;
439: if (ipv6)
440: pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask));
441: else
442: pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask));
443:
444: if (pxlen < 0)
445: { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
446:
447: if (ipv6)
448: net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen);
449: else
450: net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
451:
452: if ((flags & RTF_GATEWAY) && ipa_zero(igate))
453: { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
454:
455: u32 self_mask = RTF_PROTO1;
456: u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
457:
458: src2 = (flags & RTF_STATIC) ? 1 : 0;
459: src2 |= (flags & RTF_PROTO1) ? 2 : 0;
460:
461: #ifdef RTF_PROTO2
462: alien_mask |= RTF_PROTO2;
463: src2 |= (flags & RTF_PROTO2) ? 4 : 0;
464: #endif
465:
466: #ifdef RTF_PROTO3
467: alien_mask |= RTF_PROTO3;
468: src2 |= (flags & RTF_PROTO3) ? 8 : 0;
469: #endif
470:
471: #ifdef RTF_REJECT
472: alien_mask |= RTF_REJECT;
473: #endif
474:
475: #ifdef RTF_BLACKHOLE
476: alien_mask |= RTF_BLACKHOLE;
477: #endif
478:
479: if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
480: src = KRT_SRC_REDIRECT;
481: else if (flags & self_mask)
482: {
483: if (!scan)
484: SKIP("echo\n");
485: src = KRT_SRC_BIRD;
486: }
487: else if (flags & alien_mask)
488: src = KRT_SRC_ALIEN;
489: else
490: src = KRT_SRC_KERNEL;
491:
492: net = net_get(p->p.main_channel->table, &ndst);
493:
494: rta a = {
495: .src = p->p.main_source,
496: .source = RTS_INHERIT,
497: .scope = SCOPE_UNIVERSE,
498: };
499:
500: /* reject/blackhole routes have also set RTF_GATEWAY,
501: we wil check them first. */
502:
503: #ifdef RTF_REJECT
504: if(flags & RTF_REJECT) {
505: a.dest = RTD_UNREACHABLE;
506: goto done;
507: }
508: #endif
509:
510: #ifdef RTF_BLACKHOLE
511: if(flags & RTF_BLACKHOLE) {
512: a.dest = RTD_BLACKHOLE;
513: goto done;
514: }
515: #endif
516:
517: a.nh.iface = if_find_by_index(msg->rtm.rtm_index);
518: if (!a.nh.iface)
519: {
520: log(L_ERR "KRT: Received route %N with unknown ifindex %u",
521: net->n.addr, msg->rtm.rtm_index);
522: return;
523: }
524:
525: a.dest = RTD_UNICAST;
526: if (flags & RTF_GATEWAY)
527: {
528: neighbor *ng;
529: a.nh.gw = igate;
530:
531: /* Clean up embedded interface ID returned in link-local address */
532: if (ipa_is_link_local(a.nh.gw))
533: _I0(a.nh.gw) = 0xfe800000;
534:
535: ng = neigh_find(&p->p, a.nh.gw, a.nh.iface, 0);
536: if (!ng || (ng->scope == SCOPE_HOST))
537: {
538: /* Ignore routes with next-hop 127.0.0.1, host routes with such
539: next-hop appear on OpenBSD for address aliases. */
540: if (ipa_classify(a.nh.gw) == (IADDR_HOST | SCOPE_HOST))
541: return;
542:
543: log(L_ERR "KRT: Received route %N with strange next-hop %I",
544: net->n.addr, a.nh.gw);
545: return;
546: }
547: }
548:
549: done:
550: e = rte_get_temp(&a);
551: e->net = net;
552: e->u.krt.src = src;
553: e->u.krt.proto = src2;
554: e->u.krt.seen = 0;
555: e->u.krt.best = 0;
556: e->u.krt.metric = 0;
557:
558: if (scan)
559: krt_got_route(p, e);
560: else
561: krt_got_route_async(p, e, new);
562: }
563:
564: static void
565: krt_read_ifannounce(struct ks_msg *msg)
566: {
567: struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
568:
569: if (ifam->ifan_what == IFAN_ARRIVAL)
570: {
571: /* Not enough info to create the iface, so we just trigger iface scan */
572: kif_request_scan();
573: }
574: else if (ifam->ifan_what == IFAN_DEPARTURE)
575: {
576: struct iface *iface = if_find_by_index(ifam->ifan_index);
577:
578: /* Interface is destroyed */
579: if (!iface)
580: {
581: DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
582: return;
583: }
584:
585: if_delete(iface);
586: }
587:
588: DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
589: }
590:
591: static void
592: krt_read_ifinfo(struct ks_msg *msg, int scan)
593: {
594: struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
595: void *body = (void *)(ifm + 1);
596: struct sockaddr_dl *dl = NULL;
597: uint i;
598: struct iface *iface = NULL, f = {};
599: int fl = ifm->ifm_flags;
600: int nlen = 0;
601:
602: for (i = 1; i<=RTA_IFP; i <<= 1)
603: {
604: if (i & ifm->ifm_addrs)
605: {
606: if (i == RTA_IFP)
607: {
608: dl = (struct sockaddr_dl *)body;
609: break;
610: }
611: body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);
612: }
613: }
614:
615: if (dl && (dl->sdl_family != AF_LINK))
616: {
617: log(L_WARN "Ignoring strange IFINFO");
618: return;
619: }
620:
621: if (dl)
622: nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
623:
624: /* Note that asynchronous IFINFO messages do not contain iface
625: name, so we have to found an existing iface by iface index */
626:
627: iface = if_find_by_index(ifm->ifm_index);
628: if (!iface)
629: {
630: /* New interface */
631: if (!dl)
632: return; /* No interface name, ignoring */
633:
634: memcpy(f.name, dl->sdl_data, nlen);
635: DBG("New interface '%s' found\n", f.name);
636: }
637: else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
638: {
639: /* Interface renamed */
640: if_delete(iface);
641: memcpy(f.name, dl->sdl_data, nlen);
642: }
643: else
644: {
645: /* Old interface */
646: memcpy(f.name, iface->name, sizeof(f.name));
647: }
648:
649: f.index = ifm->ifm_index;
650: f.mtu = ifm->ifm_data.ifi_mtu;
651:
652: if (fl & IFF_UP)
653: f.flags |= IF_ADMIN_UP;
654: if (ifm->ifm_data.ifi_link_state != LINK_STATE_DOWN)
655: f.flags |= IF_LINK_UP; /* up or unknown */
656: if (fl & IFF_LOOPBACK) /* Loopback */
657: f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
658: else if (fl & IFF_POINTOPOINT) /* PtP */
659: f.flags |= IF_MULTICAST;
660: else if (fl & IFF_BROADCAST) /* Broadcast */
661: f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
662: else
663: f.flags |= IF_MULTIACCESS; /* NBMA */
664:
665: iface = if_update(&f);
666:
667: if (!scan)
668: if_end_partial_update(iface);
669: }
670:
671: static void
672: krt_read_addr(struct ks_msg *msg, int scan)
673: {
674: struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
675: void *body = (void *)(ifam + 1);
676: sockaddr addr, mask, brd;
677: struct iface *iface = NULL;
678: struct ifa ifa;
679: struct sockaddr null;
680: ip_addr iaddr, imask, ibrd;
681: int addrs = ifam->ifam_addrs;
682: int scope, masklen = -1;
683: int new = (ifam->ifam_type == RTM_NEWADDR);
684:
685: /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
686: if (ifam->ifam_index == 0)
687: return;
688:
689: if(!(iface = if_find_by_index(ifam->ifam_index)))
690: {
691: log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
692: return;
693: }
694:
695: GETADDR (&null, RTA_DST);
696: GETADDR (&null, RTA_GATEWAY);
697: GETADDR (&mask, RTA_NETMASK);
698: GETADDR (&null, RTA_GENMASK);
699: GETADDR (&null, RTA_IFP);
700: GETADDR (&addr, RTA_IFA);
701: GETADDR (&null, RTA_AUTHOR);
702: GETADDR (&brd, RTA_BRD);
703:
704: /* Is addr family IP4 or IP6? */
705: int ipv6;
706: switch (addr.sa.sa_family) {
707: case AF_INET: ipv6 = 0; break;
708: case AF_INET6: ipv6 = 1; break;
709: default: return;
710: }
711:
712: /* We do not test family for RTA_NETMASK, because BSD sends us
713: some strange values, but interpreting them as IPv4/IPv6 works */
714: mask.sa.sa_family = addr.sa.sa_family;
715:
716: iaddr = ipa_from_sa(&addr);
717: imask = ipa_from_sa(&mask);
718: ibrd = ipa_from_sa(&brd);
719:
720: if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0)
721: {
722: log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name);
723: return;
724: }
725:
726: /* Clean up embedded interface ID returned in link-local address */
727:
728: if (ipa_is_link_local(iaddr))
729: _I0(iaddr) = 0xfe800000;
730:
731: if (ipa_is_link_local(ibrd))
732: _I0(ibrd) = 0xfe800000;
733:
734:
735: bzero(&ifa, sizeof(ifa));
736: ifa.iface = iface;
737: ifa.ip = iaddr;
738:
739: scope = ipa_classify(ifa.ip);
740: if (scope < 0)
741: {
742: log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
743: return;
744: }
745: ifa.scope = scope & IADDR_SCOPE_MASK;
746:
747: if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
748: {
749: net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
750: net_normalize(&ifa.prefix);
751:
752: if (masklen == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1))
753: ifa.opposite = ipa_opposite_m1(ifa.ip);
754:
755: if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2))
756: ifa.opposite = ipa_opposite_m2(ifa.ip);
757:
758: if (iface->flags & IF_BROADCAST)
759: ifa.brd = ibrd;
760:
761: if (!(iface->flags & IF_MULTIACCESS))
762: ifa.opposite = ibrd;
763: }
764: else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
765: {
766: net_fill_ipa(&ifa.prefix, ibrd, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
767: ifa.opposite = ibrd;
768: ifa.flags |= IA_PEER;
769: }
770: else
771: {
772: net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH));
773: ifa.flags |= IA_HOST;
774: }
775:
776: if (new)
777: ifa_update(&ifa);
778: else
779: ifa_delete(&ifa);
780:
781: if (!scan)
782: if_end_partial_update(iface);
783: }
784:
785: static void
786: krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
787: {
788: /* p is NULL iff KRT_SHARED_SOCKET and !scan */
789:
790: switch (msg->rtm.rtm_type)
791: {
792: case RTM_GET:
793: if(!scan) return;
794: case RTM_ADD:
795: case RTM_DELETE:
796: case RTM_CHANGE:
797: krt_read_route(msg, (struct krt_proto *)p, scan);
798: break;
799: case RTM_IFANNOUNCE:
800: krt_read_ifannounce(msg);
801: break;
802: case RTM_IFINFO:
803: krt_read_ifinfo(msg, scan);
804: break;
805: case RTM_NEWADDR:
806: case RTM_DELADDR:
807: krt_read_addr(msg, scan);
808: break;
809: default:
810: break;
811: }
812: }
813:
814:
815: /* Sysctl based scans */
816:
817: static byte *krt_buffer;
818: static size_t krt_buflen, krt_bufmin;
819: static struct proto *krt_buffer_owner;
820:
821: static byte *
822: krt_buffer_update(struct proto *p, size_t *needed)
823: {
824: size_t req = *needed;
825:
826: if ((req > krt_buflen) ||
827: ((p == krt_buffer_owner) && (req < krt_bufmin)))
828: {
829: /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */
830: size_t step = (req < 0x100000) ? 0x2000 : 0x20000;
831: krt_buflen = (req < 0x6000) ? 0x8000 : (req + step);
832: krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step);
833:
834: if (krt_buffer)
835: mb_free(krt_buffer);
836: krt_buffer = mb_alloc(krt_pool, krt_buflen);
837: krt_buffer_owner = p;
838: }
839:
840: *needed = krt_buflen;
841: return krt_buffer;
842: }
843:
844: static void
845: krt_buffer_release(struct proto *p)
846: {
847: if (p == krt_buffer_owner)
848: {
849: mb_free(krt_buffer);
850: krt_buffer = NULL;
851: krt_buflen = 0;
852: krt_buffer_owner = 0;
853: }
854: }
855:
856: static void
857: krt_sysctl_scan(struct proto *p, int cmd, int table_id)
858: {
859: byte *buf, *next;
860: int mib[7], mcnt;
861: size_t needed;
862: struct ks_msg *m;
863: int retries = 3;
864: int rv;
865:
866: mib[0] = CTL_NET;
867: mib[1] = PF_ROUTE;
868: mib[2] = 0;
869: mib[3] = 0; // Set AF to 0 for all available families
870: mib[4] = cmd;
871: mib[5] = 0;
872: mcnt = 6;
873:
874: #ifdef KRT_USE_SYSCTL_7
875: if (table_id >= 0)
876: {
877: mib[6] = table_id;
878: mcnt = 7;
879: }
880: #endif
881:
882: #ifdef KRT_USE_SETFIB_SCAN
883: if (table_id > 0)
884: if (setfib(table_id) < 0)
885: {
886: log(L_ERR "KRT: setfib(%d) failed: %m", table_id);
887: return;
888: }
889: #endif
890:
891: try:
892: rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0);
893: if (rv < 0)
894: {
895: /* OpenBSD returns EINVAL for not yet used tables */
896: if ((errno == EINVAL) && (table_id > 0))
897: goto exit;
898:
899: log(L_ERR "KRT: Route scan estimate failed: %m");
900: goto exit;
901: }
902:
903: /* The table is empty */
904: if (needed == 0)
905: goto exit;
906:
907: buf = krt_buffer_update(p, &needed);
908:
909: rv = sysctl(mib, mcnt, buf, &needed, NULL, 0);
910: if (rv < 0)
911: {
912: /* The buffer size changed since last sysctl ('needed' is not changed) */
913: if ((errno == ENOMEM) && retries--)
914: goto try;
915:
916: log(L_ERR "KRT: Route scan failed: %m");
917: goto exit;
918: }
919:
920: #ifdef KRT_USE_SETFIB_SCAN
921: if (table_id > 0)
922: if (setfib(0) < 0)
923: die("KRT: setfib(%d) failed: %m", 0);
924: #endif
925:
926: /* Process received messages */
927: for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen)
928: {
929: m = (struct ks_msg *)next;
930: krt_read_msg(p, m, 1);
931: }
932:
933: return;
934:
935: exit:
936: krt_buffer_release(p);
937:
938: #ifdef KRT_USE_SETFIB_SCAN
939: if (table_id > 0)
940: if (setfib(0) < 0)
941: die("KRT: setfib(%d) failed: %m", 0);
942: #endif
943: }
944:
945: void
946: krt_do_scan(struct krt_proto *p)
947: {
948: krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id);
949: }
950:
951: void
952: kif_do_scan(struct kif_proto *p)
953: {
954: if_start_update();
955: krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1);
956: if_end_update();
957: }
958:
959:
960: /* Kernel sockets */
961:
962: static int
963: krt_sock_hook(sock *sk, uint size UNUSED)
964: {
965: struct ks_msg msg;
966: int l = read(sk->fd, (char *)&msg, sizeof(msg));
967:
968: if (l <= 0)
969: log(L_ERR "krt-sock: read failed");
970: else
971: krt_read_msg((struct proto *) sk->data, &msg, 0);
972:
973: return 0;
974: }
975:
976: static void
977: krt_sock_err_hook(sock *sk, int e UNUSED)
978: {
979: krt_sock_hook(sk, 0);
980: }
981:
982: static sock *
983: krt_sock_open(pool *pool, void *data, int table_id UNUSED)
984: {
985: sock *sk;
986: int fd;
987:
988: fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
989: if (fd < 0)
990: die("Cannot open kernel socket for routes");
991:
992: #ifdef KRT_USE_SETFIB_SOCK
993: if (table_id > 0)
994: {
995: if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0)
996: die("Cannot set FIB %d for kernel socket: %m", table_id);
997: }
998: #endif
999:
1000: sk = sk_new(pool);
1001: sk->type = SK_MAGIC;
1002: sk->rx_hook = krt_sock_hook;
1003: sk->err_hook = krt_sock_err_hook;
1004: sk->fd = fd;
1005: sk->data = data;
1006:
1007: if (sk_open(sk) < 0)
1008: bug("krt-sock: sk_open failed");
1009:
1010: return sk;
1011: }
1012:
1013: static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2];
1014:
1015: #ifdef KRT_SHARED_SOCKET
1016:
1017: static sock *krt_sock;
1018: static int krt_sock_count;
1019:
1020:
1021: static void
1022: krt_sock_open_shared(void)
1023: {
1024: if (!krt_sock_count)
1025: krt_sock = krt_sock_open(krt_pool, NULL, -1);
1026:
1027: krt_sock_count++;
1028: }
1029:
1030: static void
1031: krt_sock_close_shared(void)
1032: {
1033: krt_sock_count--;
1034:
1035: if (!krt_sock_count)
1036: {
1037: rfree(krt_sock);
1038: krt_sock = NULL;
1039: }
1040: }
1041:
1042: int
1043: krt_sys_start(struct krt_proto *p)
1044: {
1045: int id = KRT_CF->sys.table_id;
1046:
1047: if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1048: {
1049: log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1050: return 0;
1051: }
1052:
1053: krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1054:
1055: krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p;
1056:
1057: krt_sock_open_shared();
1058: p->sys.sk = krt_sock;
1059:
1060: return 1;
1061: }
1062:
1063: void
1064: krt_sys_shutdown(struct krt_proto *p)
1065: {
1066: krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1067:
1068: krt_sock_close_shared();
1069: p->sys.sk = NULL;
1070:
1071: krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL;
1072:
1073: krt_buffer_release(&p->p);
1074: }
1075:
1076: #else
1077:
1078: int
1079: krt_sys_start(struct krt_proto *p)
1080: {
1081: int id = KRT_CF->sys.table_id;
1082:
1083: if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32)))
1084: {
1085: log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id);
1086: return 0;
1087: }
1088:
1089: krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32));
1090:
1091: p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id);
1092: return 1;
1093: }
1094:
1095: void
1096: krt_sys_shutdown(struct krt_proto *p)
1097: {
1098: krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32));
1099:
1100: rfree(p->sys.sk);
1101: p->sys.sk = NULL;
1102:
1103: krt_buffer_release(&p->p);
1104: }
1105:
1106: #endif /* KRT_SHARED_SOCKET */
1107:
1108:
1109: /* KRT configuration callbacks */
1110:
1111: int
1112: krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
1113: {
1114: return n->sys.table_id == o->sys.table_id;
1115: }
1116:
1117: void
1118: krt_sys_preconfig(struct config *c UNUSED)
1119: {
1120: krt_max_tables = krt_get_max_tables();
1121: bzero(&krt_table_cf, sizeof(krt_table_cf));
1122: }
1123:
1124: void krt_sys_init_config(struct krt_config *c)
1125: {
1126: c->sys.table_id = 0; /* Default table */
1127: }
1128:
1129: void krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
1130: {
1131: d->sys.table_id = s->sys.table_id;
1132: }
1133:
1134:
1135: /* KIF misc code */
1136:
1137: void
1138: kif_sys_start(struct kif_proto *p UNUSED)
1139: {
1140: }
1141:
1142: void
1143: kif_sys_shutdown(struct kif_proto *p)
1144: {
1145: krt_buffer_release(&p->p);
1146: }
1147:
1148: int
1149: kif_update_sysdep_addr(struct iface *i)
1150: {
1151: static int fd = -1;
1152:
1153: if (fd < 0)
1154: fd = socket(AF_INET, SOCK_DGRAM, 0);
1155:
1156: struct ifreq ifr;
1157: memset(&ifr, 0, sizeof(ifr));
1158: strncpy(ifr.ifr_name, i->name, IFNAMSIZ);
1159:
1160: int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1161: if (rv < 0)
1162: return 0;
1163:
1164: ip4_addr old = i->sysdep;
1165: i->sysdep = ipa_to_ip4(ipa_from_sa4(&ifr.ifr_addr));
1166:
1167: return !ip4_equal(i->sysdep, old);
1168: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>