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