Annotation of embedaddon/ipsec-tools/src/racoon/grabmyaddr.c, revision 1.1

1.1     ! misho       1: /*     $NetBSD: grabmyaddr.c,v 1.28 2011/03/14 17:18:12 tteras Exp $   */
        !             2: /*
        !             3:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             4:  * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
        !             5:  * All rights reserved.
        !             6:  * 
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. Neither the name of the project nor the names of its contributors
        !            16:  *    may be used to endorse or promote products derived from this software
        !            17:  *    without specific prior written permission.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            29:  * SUCH DAMAGE.
        !            30:  */
        !            31: 
        !            32: #include "config.h"
        !            33: 
        !            34: #include <errno.h>
        !            35: #include <fcntl.h>
        !            36: #include <unistd.h>
        !            37: #include <string.h>
        !            38: #include <sys/types.h>
        !            39: #include <sys/queue.h>
        !            40: #include <sys/socket.h>
        !            41: 
        !            42: #ifdef __linux__
        !            43: #include <linux/netlink.h>
        !            44: #include <linux/rtnetlink.h>
        !            45: #define USE_NETLINK
        !            46: #else
        !            47: #include <net/route.h>
        !            48: #include <net/if.h>
        !            49: #include <net/if_dl.h>
        !            50: #include <sys/sysctl.h>
        !            51: #define USE_ROUTE
        !            52: #endif
        !            53: 
        !            54: #include "var.h"
        !            55: #include "misc.h"
        !            56: #include "vmbuf.h"
        !            57: #include "plog.h"
        !            58: #include "sockmisc.h"
        !            59: #include "session.h"
        !            60: #include "debug.h"
        !            61: 
        !            62: #include "localconf.h"
        !            63: #include "handler.h"
        !            64: #include "grabmyaddr.h"
        !            65: #include "sockmisc.h"
        !            66: #include "isakmp_var.h"
        !            67: #include "gcmalloc.h"
        !            68: #include "nattraversal.h"
        !            69: 
        !            70: static int kernel_receive __P((void *ctx, int fd));
        !            71: static int kernel_open_socket __P((void));
        !            72: static void kernel_sync __P((void));
        !            73: 
        !            74: struct myaddr {
        !            75:        LIST_ENTRY(myaddr) chain;
        !            76:        struct sockaddr_storage addr;
        !            77:        int fd;
        !            78:        int udp_encap;
        !            79: };
        !            80: 
        !            81: static LIST_HEAD(_myaddr_list_, myaddr) configured, opened;
        !            82: 
        !            83: static void
        !            84: myaddr_delete(my)
        !            85:        struct myaddr *my;
        !            86: {
        !            87:        if (my->fd != -1)
        !            88:                isakmp_close(my->fd);
        !            89:        LIST_REMOVE(my, chain);
        !            90:        racoon_free(my);
        !            91: }
        !            92: 
        !            93: static int
        !            94: myaddr_configured(addr)
        !            95:        struct sockaddr *addr;
        !            96: {
        !            97:        struct myaddr *cfg;
        !            98: 
        !            99:        if (LIST_EMPTY(&configured))
        !           100:                return TRUE;
        !           101: 
        !           102:        LIST_FOREACH(cfg, &configured, chain) {
        !           103:                if (cmpsaddr(addr, (struct sockaddr *) &cfg->addr) <= CMPSADDR_WILDPORT_MATCH)
        !           104:                        return TRUE;
        !           105:        }
        !           106: 
        !           107:        return FALSE;
        !           108: }
        !           109: 
        !           110: static int
        !           111: myaddr_open(addr, udp_encap)
        !           112:        struct sockaddr *addr;
        !           113:        int udp_encap;
        !           114: {
        !           115:        struct myaddr *my;
        !           116: 
        !           117:        /* Already open? */
        !           118:        LIST_FOREACH(my, &opened, chain) {
        !           119:                if (cmpsaddr(addr, (struct sockaddr *) &my->addr) <= CMPSADDR_WILDPORT_MATCH)
        !           120:                        return TRUE;
        !           121:        }
        !           122: 
        !           123:        my = racoon_calloc(1, sizeof(struct myaddr));
        !           124:        if (my == NULL)
        !           125:                return FALSE;
        !           126: 
        !           127:        memcpy(&my->addr, addr, sysdep_sa_len(addr));
        !           128:        my->fd = isakmp_open(addr, udp_encap);
        !           129:        if (my->fd < 0) {
        !           130:                racoon_free(my);
        !           131:                return FALSE;
        !           132:        }
        !           133:        my->udp_encap = udp_encap;
        !           134:        LIST_INSERT_HEAD(&opened, my, chain);
        !           135:        return TRUE;
        !           136: }
        !           137: 
        !           138: static int
        !           139: myaddr_open_all_configured(addr)
        !           140:        struct sockaddr *addr;
        !           141: {
        !           142:        /* create all configured, not already opened addresses */
        !           143:        struct myaddr *cfg, *my;
        !           144: 
        !           145:        if (addr != NULL) {
        !           146:                switch (addr->sa_family) {
        !           147:                case AF_INET:
        !           148: #ifdef INET6
        !           149:                case AF_INET6:
        !           150: #endif
        !           151:                        break;
        !           152:                default:
        !           153:                        return FALSE;
        !           154:                }
        !           155:        }
        !           156: 
        !           157:        LIST_FOREACH(cfg, &configured, chain) {
        !           158:                if (addr != NULL &&
        !           159:                    cmpsaddr(addr, (struct sockaddr *) &cfg->addr) > CMPSADDR_WILDPORT_MATCH)
        !           160:                        continue;
        !           161:                if (!myaddr_open((struct sockaddr *) &cfg->addr, cfg->udp_encap))
        !           162:                        return FALSE;
        !           163:        }
        !           164:        if (LIST_EMPTY(&configured)) {
        !           165: #ifdef ENABLE_HYBRID
        !           166:                /* Exclude any address we got through ISAKMP mode config */
        !           167:                if (exclude_cfg_addr(addr) == 0)
        !           168:                        return FALSE;
        !           169: #endif
        !           170:                set_port(addr, lcconf->port_isakmp);
        !           171:                myaddr_open(addr, FALSE);
        !           172: #ifdef ENABLE_NATT
        !           173:                set_port(addr, lcconf->port_isakmp_natt);
        !           174:                myaddr_open(addr, TRUE);
        !           175: #endif
        !           176:        }
        !           177:        return TRUE;
        !           178: }
        !           179: 
        !           180: static void
        !           181: myaddr_close_all_open(addr)
        !           182:        struct sockaddr *addr;
        !           183: {
        !           184:        /* delete all matching open sockets */
        !           185:        struct myaddr *my, *next;
        !           186: 
        !           187:        for (my = LIST_FIRST(&opened); my; my = next) {
        !           188:                next = LIST_NEXT(my, chain);
        !           189: 
        !           190:                if (cmpsaddr((struct sockaddr *) addr,
        !           191:                             (struct sockaddr *) &my->addr)
        !           192:                    <= CMPSADDR_WOP_MATCH)
        !           193:                        myaddr_delete(my);
        !           194:        }
        !           195: }
        !           196: 
        !           197: static void
        !           198: myaddr_flush_list(list)
        !           199:        struct _myaddr_list_ *list;
        !           200: {
        !           201:        struct myaddr *my, *next;
        !           202: 
        !           203:        for (my = LIST_FIRST(list); my; my = next) {
        !           204:                next = LIST_NEXT(my, chain);
        !           205:                myaddr_delete(my);
        !           206:        }
        !           207: }
        !           208: 
        !           209: void
        !           210: myaddr_flush()
        !           211: {
        !           212:        myaddr_flush_list(&configured);
        !           213: }
        !           214: 
        !           215: int
        !           216: myaddr_listen(addr, udp_encap)
        !           217:        struct sockaddr *addr;
        !           218:        int udp_encap;
        !           219: {
        !           220:        struct myaddr *my;
        !           221: 
        !           222:        if (sysdep_sa_len(addr) > sizeof(my->addr)) {
        !           223:                plog(LLV_ERROR, LOCATION, NULL,
        !           224:                     "sockaddr size larger than sockaddr_storage\n");
        !           225:                return -1;
        !           226:        }
        !           227: 
        !           228:        my = racoon_calloc(1, sizeof(struct myaddr));
        !           229:        if (my == NULL)
        !           230:                return -1;
        !           231: 
        !           232:        memcpy(&my->addr, addr, sysdep_sa_len(addr));
        !           233:        my->udp_encap = udp_encap;
        !           234:        my->fd = -1;
        !           235:        LIST_INSERT_HEAD(&configured, my, chain);
        !           236: 
        !           237:        return 0;
        !           238: }
        !           239: 
        !           240: void
        !           241: myaddr_sync()
        !           242: {
        !           243:        struct myaddr *my, *next;
        !           244: 
        !           245:        if (!lcconf->strict_address) {
        !           246:                kernel_sync();
        !           247: 
        !           248:                /* delete all existing listeners which are not configured */
        !           249:                for (my = LIST_FIRST(&opened); my; my = next) {
        !           250:                        next = LIST_NEXT(my, chain);
        !           251: 
        !           252:                        if (!myaddr_configured((struct sockaddr *) &my->addr))
        !           253:                                myaddr_delete(my);
        !           254:                }
        !           255:        }
        !           256: }
        !           257: 
        !           258: int
        !           259: myaddr_getfd(addr)
        !           260:         struct sockaddr *addr;
        !           261: {
        !           262:        struct myaddr *my;
        !           263: 
        !           264:        LIST_FOREACH(my, &opened, chain) {
        !           265:                if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
        !           266:                        return my->fd;
        !           267:        }
        !           268: 
        !           269:        return -1;
        !           270: }
        !           271: 
        !           272: int
        !           273: myaddr_getsport(addr)
        !           274:        struct sockaddr *addr;
        !           275: {
        !           276:        struct myaddr *my;
        !           277: 
        !           278:        LIST_FOREACH(my, &opened, chain) {
        !           279:                if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH)
        !           280:                        return extract_port((struct sockaddr *) &my->addr);
        !           281:        }
        !           282: 
        !           283:        return PORT_ISAKMP;
        !           284: }
        !           285: 
        !           286: void
        !           287: myaddr_init_lists()
        !           288: {
        !           289:        LIST_INIT(&configured);
        !           290:        LIST_INIT(&opened);
        !           291: }
        !           292: 
        !           293: int
        !           294: myaddr_init()
        !           295: {
        !           296:         if (!lcconf->strict_address) {
        !           297:                lcconf->rtsock = kernel_open_socket();
        !           298:                if (lcconf->rtsock < 0)
        !           299:                        return -1;
        !           300:                monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
        !           301:        } else {
        !           302:                lcconf->rtsock = -1;
        !           303:                if (!myaddr_open_all_configured(NULL))
        !           304:                        return -1;
        !           305:        }
        !           306:        return 0;
        !           307: }
        !           308: 
        !           309: void
        !           310: myaddr_close()
        !           311: {
        !           312:        myaddr_flush_list(&configured);
        !           313:        myaddr_flush_list(&opened);
        !           314:        if (lcconf->rtsock != -1) {
        !           315:                unmonitor_fd(lcconf->rtsock);
        !           316:                close(lcconf->rtsock);
        !           317:        }
        !           318: }
        !           319: 
        !           320: #if defined(USE_NETLINK)
        !           321: 
        !           322: static int netlink_fd = -1;
        !           323: 
        !           324: #define NLMSG_TAIL(nmsg) \
        !           325:        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
        !           326: 
        !           327: static void
        !           328: parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
        !           329: {
        !           330:        memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
        !           331:        while (RTA_OK(rta, len)) {
        !           332:                if (rta->rta_type <= max)
        !           333:                        tb[rta->rta_type] = rta;
        !           334:                rta = RTA_NEXT(rta,len);
        !           335:        }
        !           336: }
        !           337: 
        !           338: static int
        !           339: netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
        !           340:                     const void *data, int alen)
        !           341: {
        !           342:        int len = RTA_LENGTH(alen);
        !           343:        struct rtattr *rta;
        !           344: 
        !           345:        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
        !           346:                return FALSE;
        !           347: 
        !           348:        rta = NLMSG_TAIL(n);
        !           349:        rta->rta_type = type;
        !           350:        rta->rta_len = len;
        !           351:        memcpy(RTA_DATA(rta), data, alen);
        !           352:        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
        !           353:        return TRUE;
        !           354: }
        !           355: 
        !           356: static int
        !           357: netlink_enumerate(fd, family, type)
        !           358:        int fd;
        !           359:        int family;
        !           360:        int type;
        !           361: {
        !           362:        struct {
        !           363:                struct nlmsghdr nlh;
        !           364:                struct rtgenmsg g;
        !           365:        } req;
        !           366:        struct sockaddr_nl addr;
        !           367:        static __u32 seq = 0;
        !           368: 
        !           369:        memset(&addr, 0, sizeof(addr));
        !           370:        addr.nl_family = AF_NETLINK;
        !           371: 
        !           372:        memset(&req, 0, sizeof(req));
        !           373:        req.nlh.nlmsg_len = sizeof(req);
        !           374:        req.nlh.nlmsg_type = type;
        !           375:        req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
        !           376:        req.nlh.nlmsg_pid = 0;
        !           377:        req.nlh.nlmsg_seq = ++seq;
        !           378:        req.g.rtgen_family = family;
        !           379: 
        !           380:        return sendto(fd, (void *) &req, sizeof(req), 0,
        !           381:                      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
        !           382: }
        !           383: 
        !           384: static void
        !           385: netlink_add_del_address(int add, struct sockaddr *saddr)
        !           386: {
        !           387:        plog(LLV_DEBUG, LOCATION, NULL,
        !           388:             "Netlink: address %s %s\n",
        !           389:             saddrwop2str((struct sockaddr *) saddr),
        !           390:             add ? "added" : "deleted");
        !           391: 
        !           392:        if (add)
        !           393:                myaddr_open_all_configured(saddr);
        !           394:        else
        !           395:                myaddr_close_all_open(saddr);
        !           396: }
        !           397: 
        !           398: #ifdef INET6
        !           399: static int
        !           400: netlink_process_addr(struct nlmsghdr *h)
        !           401: {
        !           402:        struct sockaddr_storage addr;
        !           403:        struct ifaddrmsg *ifa;
        !           404:        struct rtattr *rta[IFA_MAX+1];
        !           405:        struct sockaddr_in6 *sin6;
        !           406: 
        !           407:        ifa = NLMSG_DATA(h);
        !           408:        parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
        !           409: 
        !           410:        if (ifa->ifa_family != AF_INET6)
        !           411:                return 0;
        !           412:        if (ifa->ifa_flags & IFA_F_TENTATIVE)
        !           413:                return 0;
        !           414:        if (rta[IFA_LOCAL] == NULL)
        !           415:                rta[IFA_LOCAL] = rta[IFA_ADDRESS];
        !           416:        if (rta[IFA_LOCAL] == NULL)
        !           417:                return 0;
        !           418: 
        !           419:        memset(&addr, 0, sizeof(addr));
        !           420:        addr.ss_family = ifa->ifa_family;
        !           421:        sin6 = (struct sockaddr_in6 *) &addr;
        !           422:        memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
        !           423:                sizeof(sin6->sin6_addr));
        !           424:        if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
        !           425:                return 0;
        !           426:        sin6->sin6_scope_id = ifa->ifa_index;
        !           427: 
        !           428:        netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
        !           429:                                (struct sockaddr *) &addr);
        !           430: 
        !           431:        return 0;
        !           432: }
        !           433: #endif
        !           434: 
        !           435: static int
        !           436: netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
        !           437: {
        !           438:        struct {
        !           439:                struct nlmsghdr n;
        !           440:                struct rtmsg    r;
        !           441:                char            buf[1024];
        !           442:        } req;
        !           443:        struct rtmsg *r = NLMSG_DATA(&req.n);
        !           444:        struct rtattr *rta[RTA_MAX+1];
        !           445:        struct sockaddr_nl nladdr;
        !           446:        ssize_t rlen;
        !           447: 
        !           448:        memset(&req, 0, sizeof(req));
        !           449:        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !           450:        req.n.nlmsg_flags = NLM_F_REQUEST;
        !           451:        req.n.nlmsg_type = RTM_GETROUTE;
        !           452:        req.r.rtm_family = family;
        !           453:        netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
        !           454:                             addr, addr_len);
        !           455:        req.r.rtm_dst_len = addr_len * 8;
        !           456: 
        !           457:        memset(&nladdr, 0, sizeof(nladdr));
        !           458:        nladdr.nl_family = AF_NETLINK;
        !           459: 
        !           460:        if (sendto(netlink_fd, &req, sizeof(req), 0,
        !           461:                   (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
        !           462:                return 0;
        !           463:        rlen = recv(netlink_fd, &req, sizeof(req), 0);
        !           464:        if (rlen < 0)
        !           465:                return 0;
        !           466: 
        !           467:        return  req.n.nlmsg_type == RTM_NEWROUTE &&
        !           468:                req.r.rtm_type == RTN_LOCAL;
        !           469: }
        !           470: 
        !           471: static int
        !           472: netlink_process_route(struct nlmsghdr *h)
        !           473: {
        !           474:        struct sockaddr_storage addr;
        !           475:        struct rtmsg *rtm;
        !           476:        struct rtattr *rta[RTA_MAX+1];
        !           477:        struct sockaddr_in *sin;
        !           478: #ifdef INET6
        !           479:        struct sockaddr_in6 *sin6;
        !           480: #endif
        !           481: 
        !           482:        rtm = NLMSG_DATA(h);
        !           483: 
        !           484:        /* local IP addresses get local route in the local table */
        !           485:        if (rtm->rtm_type != RTN_LOCAL ||
        !           486:            rtm->rtm_table != RT_TABLE_LOCAL)
        !           487:                return 0;
        !           488: 
        !           489:        parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
        !           490:        if (rta[RTA_DST] == NULL)
        !           491:                return 0;
        !           492: 
        !           493:        /* setup the socket address */
        !           494:        memset(&addr, 0, sizeof(addr));
        !           495:        addr.ss_family = rtm->rtm_family;
        !           496:        switch (rtm->rtm_family) {
        !           497:        case AF_INET:
        !           498:                sin = (struct sockaddr_in *) &addr;
        !           499:                memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
        !           500:                        sizeof(sin->sin_addr));
        !           501:                break;
        !           502: #ifdef INET6
        !           503:        case AF_INET6:
        !           504:                sin6 = (struct sockaddr_in6 *) &addr;
        !           505:                memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
        !           506:                        sizeof(sin6->sin6_addr));
        !           507:                /* Link-local addresses are handled with RTM_NEWADDR
        !           508:                 * notifications */
        !           509:                if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
        !           510:                        return 0;
        !           511:                break;
        !           512: #endif
        !           513:        default:
        !           514:                return 0;
        !           515:        }
        !           516: 
        !           517:        /* If local route was deleted, check if there is still local
        !           518:         * route for the same IP on another interface */
        !           519:        if (h->nlmsg_type == RTM_DELROUTE &&
        !           520:            netlink_route_is_local(rtm->rtm_family,
        !           521:                                   RTA_DATA(rta[RTA_DST]),
        !           522:                                   RTA_PAYLOAD(rta[RTA_DST]))) {
        !           523:                plog(LLV_DEBUG, LOCATION, NULL,
        !           524:                        "Netlink: not deleting %s yet, it exists still\n",
        !           525:                        saddrwop2str((struct sockaddr *) &addr));
        !           526:                return 0;
        !           527:        }
        !           528: 
        !           529:        netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
        !           530:                                (struct sockaddr *) &addr);
        !           531:        return 0;
        !           532: }
        !           533: 
        !           534: static int
        !           535: netlink_process(struct nlmsghdr *h)
        !           536: {
        !           537:        switch (h->nlmsg_type) {
        !           538: #ifdef INET6
        !           539:        case RTM_NEWADDR:
        !           540:        case RTM_DELADDR:
        !           541:                return netlink_process_addr(h);
        !           542: #endif
        !           543:        case RTM_NEWROUTE:
        !           544:        case RTM_DELROUTE:
        !           545:                return netlink_process_route(h);
        !           546:        }
        !           547:        return 0;
        !           548: }
        !           549: 
        !           550: static int
        !           551: kernel_receive(ctx, fd)
        !           552:        void *ctx;
        !           553:        int fd;
        !           554: {
        !           555:        struct sockaddr_nl nladdr;
        !           556:        struct iovec iov;
        !           557:        struct msghdr msg = {
        !           558:                .msg_name = &nladdr,
        !           559:                .msg_namelen = sizeof(nladdr),
        !           560:                .msg_iov = &iov,
        !           561:                .msg_iovlen = 1,
        !           562:        };
        !           563:        struct nlmsghdr *h;
        !           564:        int len, status;
        !           565:        char buf[16*1024];
        !           566: 
        !           567:        iov.iov_base = buf;
        !           568:        while (1) {
        !           569:                iov.iov_len = sizeof(buf);
        !           570:                status = recvmsg(fd, &msg, MSG_DONTWAIT);
        !           571:                if (status < 0) {
        !           572:                        if (errno == EINTR)
        !           573:                                continue;
        !           574:                        if (errno == EAGAIN)
        !           575:                                return FALSE;
        !           576:                        continue;
        !           577:                }
        !           578:                if (status == 0)
        !           579:                        return FALSE;
        !           580: 
        !           581:                h = (struct nlmsghdr *) buf;
        !           582:                while (NLMSG_OK(h, status)) {
        !           583:                        netlink_process(h);
        !           584:                        h = NLMSG_NEXT(h, status);
        !           585:                }
        !           586:        }
        !           587: 
        !           588:        return TRUE;
        !           589: }
        !           590: 
        !           591: static int
        !           592: netlink_open_socket()
        !           593: {
        !           594:        int fd;
        !           595: 
        !           596:        fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !           597:        if (fd < 0) {
        !           598:                plog(LLV_ERROR, LOCATION, NULL,
        !           599:                        "socket(PF_NETLINK) failed: %s",
        !           600:                        strerror(errno));
        !           601:                return -1;
        !           602:        }
        !           603:        close_on_exec(fd);
        !           604:        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
        !           605:                plog(LLV_WARNING, LOCATION, NULL,
        !           606:                     "failed to put socket in non-blocking mode\n");
        !           607: 
        !           608:        return fd;
        !           609: }
        !           610: 
        !           611: static int
        !           612: kernel_open_socket()
        !           613: {
        !           614:        struct sockaddr_nl nl;
        !           615:        int fd;
        !           616: 
        !           617:        if (netlink_fd < 0) {
        !           618:                netlink_fd = netlink_open_socket();
        !           619:                if (netlink_fd < 0)
        !           620:                        return -1;
        !           621:        }
        !           622: 
        !           623:        fd = netlink_open_socket();
        !           624:        if (fd < 0)
        !           625:                return fd;
        !           626: 
        !           627:        /* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
        !           628:         * the get the RTN_LOCAL routes which are automatically added
        !           629:         * by kernel. This is because:
        !           630:         *  - Linux kernel has a bug that calling bind() immediately
        !           631:         *    after IPv4 RTM_NEWADDR event can fail
        !           632:         *  - if IP is configured in multiple interfaces, we get
        !           633:         *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
        !           634:         *    after the last IP address is deconfigured.
        !           635:         * The latter reason is also why I chose to use route
        !           636:         * notifications for IPv6. However, we do need to use RTM_NEWADDR
        !           637:         * for the link-local IPv6 addresses to get the interface index
        !           638:         * that is needed in bind().
        !           639:         */
        !           640:        memset(&nl, 0, sizeof(nl));
        !           641:        nl.nl_family = AF_NETLINK;
        !           642:        nl.nl_groups = RTMGRP_IPV4_ROUTE 
        !           643: #ifdef INET6
        !           644:                        | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
        !           645: #endif
        !           646:                        ;
        !           647:        if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
        !           648:                plog(LLV_ERROR, LOCATION, NULL,
        !           649:                     "bind(PF_NETLINK) failed: %s\n",
        !           650:                     strerror(errno));
        !           651:                close(fd);
        !           652:                return -1;
        !           653:        }
        !           654:        return fd;
        !           655: }
        !           656: 
        !           657: static void
        !           658: kernel_sync()
        !           659: {
        !           660:        int fd = lcconf->rtsock;
        !           661: 
        !           662:        /* refresh addresses */
        !           663:        if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
        !           664:                plog(LLV_ERROR, LOCATION, NULL,
        !           665:                     "unable to enumerate addresses: %s\n",
        !           666:                     strerror(errno));
        !           667:        }
        !           668:        while (kernel_receive(NULL, fd) == TRUE);
        !           669: 
        !           670: #ifdef INET6
        !           671:        if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
        !           672:                plog(LLV_ERROR, LOCATION, NULL,
        !           673:                     "unable to enumerate addresses: %s\n",
        !           674:                     strerror(errno));
        !           675:        }
        !           676:        while (kernel_receive(NULL, fd) == TRUE);
        !           677: #endif
        !           678: }
        !           679: 
        !           680: #elif defined(USE_ROUTE)
        !           681: 
        !           682: #define ROUNDUP(a) \
        !           683:   ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
        !           684: 
        !           685: #define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
        !           686: 
        !           687: static size_t
        !           688: parse_address(start, end, dest)
        !           689:        caddr_t start;
        !           690:        caddr_t end;
        !           691:        struct sockaddr_storage *dest;
        !           692: {
        !           693:        int len;
        !           694: 
        !           695:        if (start >= end)
        !           696:                return 0;
        !           697: 
        !           698:        len = SAROUNDUP(start);
        !           699:        if (start + len > end)
        !           700:                return end - start;
        !           701: 
        !           702:        if (dest != NULL && len <= sizeof(struct sockaddr_storage))
        !           703:                memcpy(dest, start, len);
        !           704: 
        !           705:        return len;
        !           706: }
        !           707: 
        !           708: static void
        !           709: parse_addresses(start, end, flags, addr)
        !           710:        caddr_t start;
        !           711:        caddr_t end;
        !           712:        int flags;
        !           713:        struct sockaddr_storage *addr;
        !           714: {
        !           715:        memset(addr, 0, sizeof(*addr));
        !           716:        if (flags & RTA_DST)
        !           717:                start += parse_address(start, end, NULL);
        !           718:        if (flags & RTA_GATEWAY)
        !           719:                start += parse_address(start, end, NULL);
        !           720:        if (flags & RTA_NETMASK)
        !           721:                start += parse_address(start, end, NULL);
        !           722:        if (flags & RTA_GENMASK)
        !           723:                start += parse_address(start, end, NULL);
        !           724:        if (flags & RTA_IFP)
        !           725:                start += parse_address(start, end, NULL);
        !           726:        if (flags & RTA_IFA)
        !           727:                start += parse_address(start, end, addr);
        !           728:        if (flags & RTA_AUTHOR)
        !           729:                start += parse_address(start, end, NULL);
        !           730:        if (flags & RTA_BRD)
        !           731:                start += parse_address(start, end, NULL);
        !           732: }
        !           733: 
        !           734: static void
        !           735: kernel_handle_message(msg)
        !           736:        caddr_t msg;
        !           737: {
        !           738:        struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
        !           739:        struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
        !           740:        struct sockaddr_storage addr;
        !           741: 
        !           742:        switch (rtm->rtm_type) {
        !           743:        case RTM_NEWADDR:
        !           744:                parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
        !           745:                                ifa->ifam_addrs, &addr);
        !           746:                myaddr_open_all_configured((struct sockaddr *) &addr);
        !           747:                break;
        !           748:        case RTM_DELADDR:
        !           749:                parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
        !           750:                                ifa->ifam_addrs, &addr);
        !           751:                myaddr_close_all_open((struct sockaddr *) &addr);
        !           752:                break;
        !           753:        case RTM_ADD:
        !           754:        case RTM_DELETE:
        !           755:        case RTM_CHANGE:
        !           756:        case RTM_MISS:
        !           757:        case RTM_IFINFO:
        !           758: #ifdef RTM_OIFINFO
        !           759:        case RTM_OIFINFO:
        !           760: #endif
        !           761: #ifdef RTM_NEWMADDR
        !           762:        case RTM_NEWMADDR:
        !           763:        case RTM_DELMADDR:
        !           764: #endif
        !           765: #ifdef RTM_IFANNOUNCE
        !           766:        case RTM_IFANNOUNCE:
        !           767: #endif
        !           768:                break;
        !           769:        default:
        !           770:                plog(LLV_WARNING, LOCATION, NULL,
        !           771:                     "unrecognized route message with rtm_type: %d",
        !           772:                     rtm->rtm_type);
        !           773:                break;
        !           774:        }
        !           775: }
        !           776: 
        !           777: static int
        !           778: kernel_receive(ctx, fd)
        !           779:        void *ctx;
        !           780:        int fd;
        !           781: {
        !           782:        char buf[16*1024];
        !           783:        struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
        !           784:        int len;
        !           785: 
        !           786:        len = read(fd, &buf, sizeof(buf));
        !           787:        if (len <= 0) {
        !           788:                if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
        !           789:                        plog(LLV_WARNING, LOCATION, NULL,
        !           790:                             "routing socket error: %s", strerror(errno));
        !           791:                return FALSE;
        !           792:        }
        !           793: 
        !           794:        if (rtm->rtm_msglen != len) {
        !           795:                plog(LLV_WARNING, LOCATION, NULL,
        !           796:                     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
        !           797:                     rtm->rtm_msglen, len, rtm->rtm_type);
        !           798:                return FALSE;
        !           799:        }
        !           800: 
        !           801:        kernel_handle_message(buf);
        !           802:        return TRUE;
        !           803: }
        !           804: 
        !           805: static int
        !           806: kernel_open_socket()
        !           807: {
        !           808:        int fd;
        !           809: 
        !           810:        fd = socket(PF_ROUTE, SOCK_RAW, 0);
        !           811:        if (fd < 0) {
        !           812:                plog(LLV_ERROR, LOCATION, NULL,
        !           813:                        "socket(PF_ROUTE) failed: %s",
        !           814:                        strerror(errno));
        !           815:                return -1;
        !           816:        }
        !           817:        close_on_exec(fd);
        !           818:        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
        !           819:                plog(LLV_WARNING, LOCATION, NULL,
        !           820:                     "failed to put socket in non-blocking mode\n");
        !           821: 
        !           822:        return fd;
        !           823: }
        !           824: 
        !           825: static void
        !           826: kernel_sync()
        !           827: {
        !           828:        caddr_t ref, buf, end;
        !           829:        size_t bufsiz;
        !           830:        struct if_msghdr *ifm;
        !           831:        struct interface *ifp;
        !           832: 
        !           833: #define MIBSIZ 6
        !           834:        int mib[MIBSIZ] = {
        !           835:                CTL_NET,
        !           836:                PF_ROUTE,
        !           837:                0,
        !           838:                0, /*  AF_INET & AF_INET6 */
        !           839:                NET_RT_IFLIST,
        !           840:                0
        !           841:        };
        !           842: 
        !           843:        if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
        !           844:                plog(LLV_WARNING, LOCATION, NULL,
        !           845:                     "sysctl() error: %s", strerror(errno));
        !           846:                return;
        !           847:        }
        !           848: 
        !           849:        ref = buf = racoon_malloc(bufsiz);
        !           850: 
        !           851:        if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
        !           852:                /* Parse both interfaces and addresses. */
        !           853:                for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
        !           854:                        ifm = (struct if_msghdr *) buf;
        !           855:                        kernel_handle_message(buf);
        !           856:                }
        !           857:        } else {
        !           858:                plog(LLV_WARNING, LOCATION, NULL,
        !           859:                     "sysctl() error: %s", strerror(errno));
        !           860:        }
        !           861: 
        !           862:        racoon_free(ref);
        !           863: }
        !           864: 
        !           865: #else
        !           866: 
        !           867: #error No supported interface to monitor local addresses.
        !           868: 
        !           869: #endif

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