Return to grabmyaddr.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / racoon |
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