File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / sysdep / bsd / krt-sock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (5 years, 5 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    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>