File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / sysdep / bsd / krt-sock.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 19:50:23 2021 UTC (4 years ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, HEAD
bird 1.6.8

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>