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