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