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

1.1.1.2 ! misho       1: /*     $NetBSD: grabmyaddr.c,v 1.28.2.2 2013/04/12 09:53:52 tteras Exp $       */
1.1       misho       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;
1.1.1.2 ! misho     277:        int port = 0, wport;
1.1       misho     278: 
                    279:        LIST_FOREACH(my, &opened, chain) {
1.1.1.2 ! misho     280:                switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) {
        !           281:                case CMPSADDR_MATCH:
1.1       misho     282:                        return extract_port((struct sockaddr *) &my->addr);
1.1.1.2 ! misho     283:                case CMPSADDR_WILDPORT_MATCH:
        !           284:                        wport = extract_port((struct sockaddr *) &my->addr);
        !           285:                        if (port == 0 || wport < port)
        !           286:                                port = wport;
        !           287:                        break;
        !           288:                }
1.1       misho     289:        }
1.1.1.2 ! misho     290:        
        !           291:        if (port == 0)
        !           292:                port = PORT_ISAKMP;
1.1       misho     293: 
1.1.1.2 ! misho     294:        return port;
1.1       misho     295: }
                    296: 
                    297: void
                    298: myaddr_init_lists()
                    299: {
                    300:        LIST_INIT(&configured);
                    301:        LIST_INIT(&opened);
                    302: }
                    303: 
                    304: int
                    305: myaddr_init()
                    306: {
                    307:         if (!lcconf->strict_address) {
                    308:                lcconf->rtsock = kernel_open_socket();
                    309:                if (lcconf->rtsock < 0)
                    310:                        return -1;
                    311:                monitor_fd(lcconf->rtsock, kernel_receive, NULL, 0);
                    312:        } else {
                    313:                lcconf->rtsock = -1;
                    314:                if (!myaddr_open_all_configured(NULL))
                    315:                        return -1;
                    316:        }
                    317:        return 0;
                    318: }
                    319: 
                    320: void
                    321: myaddr_close()
                    322: {
                    323:        myaddr_flush_list(&configured);
                    324:        myaddr_flush_list(&opened);
                    325:        if (lcconf->rtsock != -1) {
                    326:                unmonitor_fd(lcconf->rtsock);
                    327:                close(lcconf->rtsock);
                    328:        }
                    329: }
                    330: 
                    331: #if defined(USE_NETLINK)
                    332: 
                    333: static int netlink_fd = -1;
                    334: 
                    335: #define NLMSG_TAIL(nmsg) \
                    336:        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
                    337: 
                    338: static void
                    339: parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
                    340: {
                    341:        memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
                    342:        while (RTA_OK(rta, len)) {
                    343:                if (rta->rta_type <= max)
                    344:                        tb[rta->rta_type] = rta;
                    345:                rta = RTA_NEXT(rta,len);
                    346:        }
                    347: }
                    348: 
                    349: static int
                    350: netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
                    351:                     const void *data, int alen)
                    352: {
                    353:        int len = RTA_LENGTH(alen);
                    354:        struct rtattr *rta;
                    355: 
                    356:        if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
                    357:                return FALSE;
                    358: 
                    359:        rta = NLMSG_TAIL(n);
                    360:        rta->rta_type = type;
                    361:        rta->rta_len = len;
                    362:        memcpy(RTA_DATA(rta), data, alen);
                    363:        n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
                    364:        return TRUE;
                    365: }
                    366: 
                    367: static int
                    368: netlink_enumerate(fd, family, type)
                    369:        int fd;
                    370:        int family;
                    371:        int type;
                    372: {
                    373:        struct {
                    374:                struct nlmsghdr nlh;
                    375:                struct rtgenmsg g;
                    376:        } req;
                    377:        struct sockaddr_nl addr;
                    378:        static __u32 seq = 0;
                    379: 
                    380:        memset(&addr, 0, sizeof(addr));
                    381:        addr.nl_family = AF_NETLINK;
                    382: 
                    383:        memset(&req, 0, sizeof(req));
                    384:        req.nlh.nlmsg_len = sizeof(req);
                    385:        req.nlh.nlmsg_type = type;
                    386:        req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
                    387:        req.nlh.nlmsg_pid = 0;
                    388:        req.nlh.nlmsg_seq = ++seq;
                    389:        req.g.rtgen_family = family;
                    390: 
                    391:        return sendto(fd, (void *) &req, sizeof(req), 0,
                    392:                      (struct sockaddr *) &addr, sizeof(addr)) >= 0;
                    393: }
                    394: 
                    395: static void
                    396: netlink_add_del_address(int add, struct sockaddr *saddr)
                    397: {
                    398:        plog(LLV_DEBUG, LOCATION, NULL,
                    399:             "Netlink: address %s %s\n",
                    400:             saddrwop2str((struct sockaddr *) saddr),
                    401:             add ? "added" : "deleted");
                    402: 
                    403:        if (add)
                    404:                myaddr_open_all_configured(saddr);
                    405:        else
                    406:                myaddr_close_all_open(saddr);
                    407: }
                    408: 
                    409: #ifdef INET6
                    410: static int
                    411: netlink_process_addr(struct nlmsghdr *h)
                    412: {
                    413:        struct sockaddr_storage addr;
                    414:        struct ifaddrmsg *ifa;
                    415:        struct rtattr *rta[IFA_MAX+1];
                    416:        struct sockaddr_in6 *sin6;
                    417: 
                    418:        ifa = NLMSG_DATA(h);
                    419:        parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h));
                    420: 
                    421:        if (ifa->ifa_family != AF_INET6)
                    422:                return 0;
                    423:        if (ifa->ifa_flags & IFA_F_TENTATIVE)
                    424:                return 0;
                    425:        if (rta[IFA_LOCAL] == NULL)
                    426:                rta[IFA_LOCAL] = rta[IFA_ADDRESS];
                    427:        if (rta[IFA_LOCAL] == NULL)
                    428:                return 0;
                    429: 
                    430:        memset(&addr, 0, sizeof(addr));
                    431:        addr.ss_family = ifa->ifa_family;
                    432:        sin6 = (struct sockaddr_in6 *) &addr;
                    433:        memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]),
                    434:                sizeof(sin6->sin6_addr));
                    435:        if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
                    436:                return 0;
                    437:        sin6->sin6_scope_id = ifa->ifa_index;
                    438: 
                    439:        netlink_add_del_address(h->nlmsg_type == RTM_NEWADDR,
                    440:                                (struct sockaddr *) &addr);
                    441: 
                    442:        return 0;
                    443: }
                    444: #endif
                    445: 
                    446: static int
                    447: netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
                    448: {
                    449:        struct {
                    450:                struct nlmsghdr n;
                    451:                struct rtmsg    r;
                    452:                char            buf[1024];
                    453:        } req;
                    454:        struct rtmsg *r = NLMSG_DATA(&req.n);
                    455:        struct rtattr *rta[RTA_MAX+1];
                    456:        struct sockaddr_nl nladdr;
                    457:        ssize_t rlen;
                    458: 
                    459:        memset(&req, 0, sizeof(req));
                    460:        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
                    461:        req.n.nlmsg_flags = NLM_F_REQUEST;
                    462:        req.n.nlmsg_type = RTM_GETROUTE;
                    463:        req.r.rtm_family = family;
                    464:        netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
                    465:                             addr, addr_len);
                    466:        req.r.rtm_dst_len = addr_len * 8;
                    467: 
                    468:        memset(&nladdr, 0, sizeof(nladdr));
                    469:        nladdr.nl_family = AF_NETLINK;
                    470: 
                    471:        if (sendto(netlink_fd, &req, sizeof(req), 0,
                    472:                   (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
                    473:                return 0;
                    474:        rlen = recv(netlink_fd, &req, sizeof(req), 0);
                    475:        if (rlen < 0)
                    476:                return 0;
                    477: 
                    478:        return  req.n.nlmsg_type == RTM_NEWROUTE &&
                    479:                req.r.rtm_type == RTN_LOCAL;
                    480: }
                    481: 
                    482: static int
                    483: netlink_process_route(struct nlmsghdr *h)
                    484: {
                    485:        struct sockaddr_storage addr;
                    486:        struct rtmsg *rtm;
                    487:        struct rtattr *rta[RTA_MAX+1];
                    488:        struct sockaddr_in *sin;
                    489: #ifdef INET6
                    490:        struct sockaddr_in6 *sin6;
                    491: #endif
                    492: 
                    493:        rtm = NLMSG_DATA(h);
                    494: 
                    495:        /* local IP addresses get local route in the local table */
                    496:        if (rtm->rtm_type != RTN_LOCAL ||
                    497:            rtm->rtm_table != RT_TABLE_LOCAL)
                    498:                return 0;
                    499: 
                    500:        parse_rtattr(rta, IFA_MAX, RTM_RTA(rtm), IFA_PAYLOAD(h));
                    501:        if (rta[RTA_DST] == NULL)
                    502:                return 0;
                    503: 
                    504:        /* setup the socket address */
                    505:        memset(&addr, 0, sizeof(addr));
                    506:        addr.ss_family = rtm->rtm_family;
                    507:        switch (rtm->rtm_family) {
                    508:        case AF_INET:
                    509:                sin = (struct sockaddr_in *) &addr;
                    510:                memcpy(&sin->sin_addr, RTA_DATA(rta[RTA_DST]),
                    511:                        sizeof(sin->sin_addr));
                    512:                break;
                    513: #ifdef INET6
                    514:        case AF_INET6:
                    515:                sin6 = (struct sockaddr_in6 *) &addr;
                    516:                memcpy(&sin6->sin6_addr, RTA_DATA(rta[RTA_DST]),
                    517:                        sizeof(sin6->sin6_addr));
                    518:                /* Link-local addresses are handled with RTM_NEWADDR
                    519:                 * notifications */
                    520:                if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
                    521:                        return 0;
                    522:                break;
                    523: #endif
                    524:        default:
                    525:                return 0;
                    526:        }
                    527: 
                    528:        /* If local route was deleted, check if there is still local
                    529:         * route for the same IP on another interface */
                    530:        if (h->nlmsg_type == RTM_DELROUTE &&
                    531:            netlink_route_is_local(rtm->rtm_family,
                    532:                                   RTA_DATA(rta[RTA_DST]),
                    533:                                   RTA_PAYLOAD(rta[RTA_DST]))) {
                    534:                plog(LLV_DEBUG, LOCATION, NULL,
                    535:                        "Netlink: not deleting %s yet, it exists still\n",
                    536:                        saddrwop2str((struct sockaddr *) &addr));
                    537:                return 0;
                    538:        }
                    539: 
                    540:        netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
                    541:                                (struct sockaddr *) &addr);
                    542:        return 0;
                    543: }
                    544: 
                    545: static int
                    546: netlink_process(struct nlmsghdr *h)
                    547: {
                    548:        switch (h->nlmsg_type) {
                    549: #ifdef INET6
                    550:        case RTM_NEWADDR:
                    551:        case RTM_DELADDR:
                    552:                return netlink_process_addr(h);
                    553: #endif
                    554:        case RTM_NEWROUTE:
                    555:        case RTM_DELROUTE:
                    556:                return netlink_process_route(h);
                    557:        }
                    558:        return 0;
                    559: }
                    560: 
                    561: static int
                    562: kernel_receive(ctx, fd)
                    563:        void *ctx;
                    564:        int fd;
                    565: {
                    566:        struct sockaddr_nl nladdr;
                    567:        struct iovec iov;
                    568:        struct msghdr msg = {
                    569:                .msg_name = &nladdr,
                    570:                .msg_namelen = sizeof(nladdr),
                    571:                .msg_iov = &iov,
                    572:                .msg_iovlen = 1,
                    573:        };
                    574:        struct nlmsghdr *h;
                    575:        int len, status;
                    576:        char buf[16*1024];
                    577: 
                    578:        iov.iov_base = buf;
                    579:        while (1) {
                    580:                iov.iov_len = sizeof(buf);
                    581:                status = recvmsg(fd, &msg, MSG_DONTWAIT);
                    582:                if (status < 0) {
                    583:                        if (errno == EINTR)
                    584:                                continue;
                    585:                        if (errno == EAGAIN)
                    586:                                return FALSE;
                    587:                        continue;
                    588:                }
                    589:                if (status == 0)
                    590:                        return FALSE;
                    591: 
                    592:                h = (struct nlmsghdr *) buf;
                    593:                while (NLMSG_OK(h, status)) {
                    594:                        netlink_process(h);
                    595:                        h = NLMSG_NEXT(h, status);
                    596:                }
                    597:        }
                    598: 
                    599:        return TRUE;
                    600: }
                    601: 
                    602: static int
                    603: netlink_open_socket()
                    604: {
                    605:        int fd;
                    606: 
                    607:        fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
                    608:        if (fd < 0) {
                    609:                plog(LLV_ERROR, LOCATION, NULL,
                    610:                        "socket(PF_NETLINK) failed: %s",
                    611:                        strerror(errno));
                    612:                return -1;
                    613:        }
                    614:        close_on_exec(fd);
                    615:        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
                    616:                plog(LLV_WARNING, LOCATION, NULL,
                    617:                     "failed to put socket in non-blocking mode\n");
                    618: 
                    619:        return fd;
                    620: }
                    621: 
                    622: static int
                    623: kernel_open_socket()
                    624: {
                    625:        struct sockaddr_nl nl;
                    626:        int fd;
                    627: 
                    628:        if (netlink_fd < 0) {
                    629:                netlink_fd = netlink_open_socket();
                    630:                if (netlink_fd < 0)
                    631:                        return -1;
                    632:        }
                    633: 
                    634:        fd = netlink_open_socket();
                    635:        if (fd < 0)
                    636:                return fd;
                    637: 
                    638:        /* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
                    639:         * the get the RTN_LOCAL routes which are automatically added
                    640:         * by kernel. This is because:
                    641:         *  - Linux kernel has a bug that calling bind() immediately
                    642:         *    after IPv4 RTM_NEWADDR event can fail
                    643:         *  - if IP is configured in multiple interfaces, we get
                    644:         *    RTM_DELADDR for each of them. RTN_LOCAL gets deleted only
                    645:         *    after the last IP address is deconfigured.
                    646:         * The latter reason is also why I chose to use route
                    647:         * notifications for IPv6. However, we do need to use RTM_NEWADDR
                    648:         * for the link-local IPv6 addresses to get the interface index
                    649:         * that is needed in bind().
                    650:         */
                    651:        memset(&nl, 0, sizeof(nl));
                    652:        nl.nl_family = AF_NETLINK;
                    653:        nl.nl_groups = RTMGRP_IPV4_ROUTE 
                    654: #ifdef INET6
                    655:                        | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE
                    656: #endif
                    657:                        ;
                    658:        if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) {
                    659:                plog(LLV_ERROR, LOCATION, NULL,
                    660:                     "bind(PF_NETLINK) failed: %s\n",
                    661:                     strerror(errno));
                    662:                close(fd);
                    663:                return -1;
                    664:        }
                    665:        return fd;
                    666: }
                    667: 
                    668: static void
                    669: kernel_sync()
                    670: {
                    671:        int fd = lcconf->rtsock;
                    672: 
                    673:        /* refresh addresses */
                    674:        if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETROUTE)) {
                    675:                plog(LLV_ERROR, LOCATION, NULL,
                    676:                     "unable to enumerate addresses: %s\n",
                    677:                     strerror(errno));
                    678:        }
                    679:        while (kernel_receive(NULL, fd) == TRUE);
                    680: 
                    681: #ifdef INET6
                    682:        if (!netlink_enumerate(fd, PF_INET6, RTM_GETADDR)) {
                    683:                plog(LLV_ERROR, LOCATION, NULL,
                    684:                     "unable to enumerate addresses: %s\n",
                    685:                     strerror(errno));
                    686:        }
                    687:        while (kernel_receive(NULL, fd) == TRUE);
                    688: #endif
                    689: }
                    690: 
                    691: #elif defined(USE_ROUTE)
                    692: 
                    693: #define ROUNDUP(a) \
                    694:   ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
                    695: 
                    696: #define SAROUNDUP(X)   ROUNDUP(((struct sockaddr *)(X))->sa_len)
                    697: 
                    698: static size_t
                    699: parse_address(start, end, dest)
                    700:        caddr_t start;
                    701:        caddr_t end;
                    702:        struct sockaddr_storage *dest;
                    703: {
                    704:        int len;
                    705: 
                    706:        if (start >= end)
                    707:                return 0;
                    708: 
                    709:        len = SAROUNDUP(start);
                    710:        if (start + len > end)
                    711:                return end - start;
                    712: 
                    713:        if (dest != NULL && len <= sizeof(struct sockaddr_storage))
                    714:                memcpy(dest, start, len);
                    715: 
                    716:        return len;
                    717: }
                    718: 
                    719: static void
                    720: parse_addresses(start, end, flags, addr)
                    721:        caddr_t start;
                    722:        caddr_t end;
                    723:        int flags;
                    724:        struct sockaddr_storage *addr;
                    725: {
                    726:        memset(addr, 0, sizeof(*addr));
                    727:        if (flags & RTA_DST)
                    728:                start += parse_address(start, end, NULL);
                    729:        if (flags & RTA_GATEWAY)
                    730:                start += parse_address(start, end, NULL);
                    731:        if (flags & RTA_NETMASK)
                    732:                start += parse_address(start, end, NULL);
                    733:        if (flags & RTA_GENMASK)
                    734:                start += parse_address(start, end, NULL);
                    735:        if (flags & RTA_IFP)
                    736:                start += parse_address(start, end, NULL);
                    737:        if (flags & RTA_IFA)
                    738:                start += parse_address(start, end, addr);
                    739:        if (flags & RTA_AUTHOR)
                    740:                start += parse_address(start, end, NULL);
                    741:        if (flags & RTA_BRD)
                    742:                start += parse_address(start, end, NULL);
                    743: }
                    744: 
                    745: static void
                    746: kernel_handle_message(msg)
                    747:        caddr_t msg;
                    748: {
                    749:        struct rt_msghdr *rtm = (struct rt_msghdr *) msg;
                    750:        struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg;
                    751:        struct sockaddr_storage addr;
                    752: 
                    753:        switch (rtm->rtm_type) {
                    754:        case RTM_NEWADDR:
                    755:                parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
                    756:                                ifa->ifam_addrs, &addr);
                    757:                myaddr_open_all_configured((struct sockaddr *) &addr);
                    758:                break;
                    759:        case RTM_DELADDR:
                    760:                parse_addresses(ifa + 1, msg + ifa->ifam_msglen,
                    761:                                ifa->ifam_addrs, &addr);
                    762:                myaddr_close_all_open((struct sockaddr *) &addr);
                    763:                break;
                    764:        case RTM_ADD:
                    765:        case RTM_DELETE:
                    766:        case RTM_CHANGE:
1.1.1.2 ! misho     767:        case RTM_GET:
1.1       misho     768:        case RTM_MISS:
                    769:        case RTM_IFINFO:
                    770: #ifdef RTM_OIFINFO
                    771:        case RTM_OIFINFO:
                    772: #endif
                    773: #ifdef RTM_NEWMADDR
                    774:        case RTM_NEWMADDR:
                    775:        case RTM_DELMADDR:
                    776: #endif
                    777: #ifdef RTM_IFANNOUNCE
                    778:        case RTM_IFANNOUNCE:
                    779: #endif
                    780:                break;
                    781:        default:
                    782:                plog(LLV_WARNING, LOCATION, NULL,
1.1.1.2 ! misho     783:                     "unrecognized route message with rtm_type: %d\n",
1.1       misho     784:                     rtm->rtm_type);
                    785:                break;
                    786:        }
                    787: }
                    788: 
                    789: static int
                    790: kernel_receive(ctx, fd)
                    791:        void *ctx;
                    792:        int fd;
                    793: {
                    794:        char buf[16*1024];
                    795:        struct rt_msghdr *rtm = (struct rt_msghdr *) buf;
                    796:        int len;
                    797: 
                    798:        len = read(fd, &buf, sizeof(buf));
                    799:        if (len <= 0) {
                    800:                if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
                    801:                        plog(LLV_WARNING, LOCATION, NULL,
                    802:                             "routing socket error: %s", strerror(errno));
                    803:                return FALSE;
                    804:        }
                    805: 
                    806:        if (rtm->rtm_msglen != len) {
                    807:                plog(LLV_WARNING, LOCATION, NULL,
                    808:                     "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n",
                    809:                     rtm->rtm_msglen, len, rtm->rtm_type);
                    810:                return FALSE;
                    811:        }
                    812: 
                    813:        kernel_handle_message(buf);
                    814:        return TRUE;
                    815: }
                    816: 
                    817: static int
                    818: kernel_open_socket()
                    819: {
                    820:        int fd;
                    821: 
                    822:        fd = socket(PF_ROUTE, SOCK_RAW, 0);
                    823:        if (fd < 0) {
                    824:                plog(LLV_ERROR, LOCATION, NULL,
                    825:                        "socket(PF_ROUTE) failed: %s",
                    826:                        strerror(errno));
                    827:                return -1;
                    828:        }
                    829:        close_on_exec(fd);
                    830:        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
                    831:                plog(LLV_WARNING, LOCATION, NULL,
                    832:                     "failed to put socket in non-blocking mode\n");
                    833: 
                    834:        return fd;
                    835: }
                    836: 
                    837: static void
                    838: kernel_sync()
                    839: {
                    840:        caddr_t ref, buf, end;
                    841:        size_t bufsiz;
                    842:        struct if_msghdr *ifm;
                    843:        struct interface *ifp;
                    844: 
                    845: #define MIBSIZ 6
                    846:        int mib[MIBSIZ] = {
                    847:                CTL_NET,
                    848:                PF_ROUTE,
                    849:                0,
                    850:                0, /*  AF_INET & AF_INET6 */
                    851:                NET_RT_IFLIST,
                    852:                0
                    853:        };
                    854: 
                    855:        if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) {
                    856:                plog(LLV_WARNING, LOCATION, NULL,
                    857:                     "sysctl() error: %s", strerror(errno));
                    858:                return;
                    859:        }
                    860: 
                    861:        ref = buf = racoon_malloc(bufsiz);
                    862: 
                    863:        if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) {
                    864:                /* Parse both interfaces and addresses. */
                    865:                for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) {
                    866:                        ifm = (struct if_msghdr *) buf;
                    867:                        kernel_handle_message(buf);
                    868:                }
                    869:        } else {
                    870:                plog(LLV_WARNING, LOCATION, NULL,
                    871:                     "sysctl() error: %s", strerror(errno));
                    872:        }
                    873: 
                    874:        racoon_free(ref);
                    875: }
                    876: 
                    877: #else
                    878: 
                    879: #error No supported interface to monitor local addresses.
                    880: 
                    881: #endif

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