Annotation of embedaddon/bird2/sysdep/bsd/krt-sock.c, revision 1.1
1.1 ! misho 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>