Annotation of embedaddon/bird2/sysdep/bsd/krt-sock.c, revision 1.1

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

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