Annotation of embedaddon/ipsec-tools/src/racoon/grabmyaddr.c, revision 1.1.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>