Annotation of embedaddon/bird/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 "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: };
        !           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>