grabmyaddr.c revision 1.35
1/* $NetBSD: grabmyaddr.c,v 1.35 2017/04/12 16:47:39 roy 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 70static int kernel_receive __P((void *ctx, int fd)); 71static int kernel_open_socket __P((void)); 72static void kernel_sync __P((void)); 73 74struct myaddr { 75 LIST_ENTRY(myaddr) chain; 76 struct sockaddr_storage addr; 77 int fd; 78 int udp_encap; 79}; 80 81static LIST_HEAD(_myaddr_list_, myaddr) configured, opened; 82 83static void 84myaddr_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 93static int 94myaddr_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 110static int 111myaddr_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 138static int 139myaddr_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 180static void 181myaddr_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 197static void 198myaddr_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 209void 210myaddr_flush() 211{ 212 myaddr_flush_list(&configured); 213} 214 215int 216myaddr_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 240void 241myaddr_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 258int 259myaddr_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 272int 273myaddr_getsport(addr) 274 struct sockaddr *addr; 275{ 276 struct myaddr *my; 277 int port = 0, wport; 278 279 LIST_FOREACH(my, &opened, chain) { 280 switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) { 281 case CMPSADDR_MATCH: 282 return extract_port((struct sockaddr *) &my->addr); 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 } 289 } 290 291 if (port == 0) 292 port = PORT_ISAKMP; 293 294 return port; 295} 296 297void 298myaddr_init_lists() 299{ 300 LIST_INIT(&configured); 301 LIST_INIT(&opened); 302} 303 304int 305myaddr_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 320void 321myaddr_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 333static int netlink_fd = -1; 334 335#define NLMSG_TAIL(nmsg) \ 336 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 337 338static void 339parse_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 349static int 350netlink_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 367static int 368netlink_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 395static void 396netlink_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 410static int 411netlink_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 446static int 447netlink_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 482static int 483netlink_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 545static int 546netlink_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 561static int 562kernel_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 602static int 603netlink_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 622static int 623kernel_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 668static void 669kernel_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 698static size_t 699parse_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 719static void 720parse_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 745static void 746kernel_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: 767 case RTM_GET: 768 case RTM_MISS: 769#ifdef RTM_LOSING 770 case RTM_LOSING: 771#endif 772#ifdef RTM_REDIRECT 773 case RTM_REDIRECT: 774#endif 775 case RTM_IFINFO: 776#ifdef RTM_OIFINFO 777 case RTM_OIFINFO: 778#endif 779#ifdef RTM_NEWMADDR 780 case RTM_NEWMADDR: 781 case RTM_DELMADDR: 782#endif 783#ifdef RTM_IFANNOUNCE 784 case RTM_IFANNOUNCE: 785#endif 786#ifdef RTM_IEEE80211 787 case RTM_IEEE80211: 788#endif 789 break; 790 default: 791 plog(LLV_WARNING, LOCATION, NULL, 792 "unrecognized route message with rtm_type: %d\n", 793 rtm->rtm_type); 794 break; 795 } 796} 797 798static int 799kernel_receive(ctx, fd) 800 void *ctx; 801 int fd; 802{ 803 char buf[16*1024]; 804 struct rt_msghdr *rtm = (struct rt_msghdr *) buf; 805 int len; 806 807 len = read(fd, &buf, sizeof(buf)); 808 if (len <= 0) { 809 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN) 810 plog(LLV_WARNING, LOCATION, NULL, 811 "routing socket error: %s", strerror(errno)); 812 return FALSE; 813 } 814 815 if (rtm->rtm_msglen != len) { 816 plog(LLV_WARNING, LOCATION, NULL, 817 "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n", 818 rtm->rtm_msglen, len, rtm->rtm_type); 819 return FALSE; 820 } 821 822 kernel_handle_message(buf); 823 return TRUE; 824} 825 826static int 827kernel_open_socket() 828{ 829 int fd; 830#ifdef RO_MSGFILTER 831 unsigned char msgfilter[] = { RTM_NEWADDR, RTM_DELADDR }; 832#endif 833 834 fd = socket(PF_ROUTE, SOCK_RAW, 0); 835 if (fd < 0) { 836 plog(LLV_ERROR, LOCATION, NULL, 837 "socket(PF_ROUTE) failed: %s", 838 strerror(errno)); 839 return -1; 840 } 841#ifdef RO_MSGFILTER 842 if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER, 843 &msgfilter, sizeof(msgfilter)) < 0) 844 plog(LLV_WARNING, LOCATION, NULL, 845 "setsockopt(RO_MSGFILER) failed: %s", 846 strerror(errno)); 847#endif 848 close_on_exec(fd); 849 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) 850 plog(LLV_WARNING, LOCATION, NULL, 851 "failed to put socket in non-blocking mode\n"); 852 853 return fd; 854} 855 856static void 857kernel_sync() 858{ 859 caddr_t ref, buf, end; 860 size_t bufsiz; 861 struct if_msghdr *ifm; 862 struct interface *ifp; 863 864#define MIBSIZ 6 865 int mib[MIBSIZ] = { 866 CTL_NET, 867 PF_ROUTE, 868 0, 869 0, /* AF_INET & AF_INET6 */ 870 NET_RT_IFLIST, 871 0 872 }; 873 874 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { 875 plog(LLV_WARNING, LOCATION, NULL, 876 "sysctl() error: %s", strerror(errno)); 877 return; 878 } 879 880 ref = buf = racoon_malloc(bufsiz); 881 882 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) { 883 /* Parse both interfaces and addresses. */ 884 for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { 885 ifm = (struct if_msghdr *) buf; 886 kernel_handle_message(buf); 887 } 888 } else { 889 plog(LLV_WARNING, LOCATION, NULL, 890 "sysctl() error: %s", strerror(errno)); 891 } 892 893 racoon_free(ref); 894} 895 896#else 897 898#error No supported interface to monitor local addresses. 899 900#endif 901