1 /* $NetBSD: grabmyaddr.c,v 1.42 2025/03/08 16:39:08 christos Exp $ */ 2 /* 3 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 4 * Copyright (C) 2008 Timo Teras <timo.teras (at) 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(void *ctx, int fd); 71 static int kernel_open_socket(void); 72 static void kernel_sync(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(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 92 static int 93 myaddr_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 108 static int 109 myaddr_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 134 static int 135 myaddr_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 175 static void 176 myaddr_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 191 static void 192 myaddr_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 202 void 203 myaddr_flush(void) 204 { 205 myaddr_flush_list(&configured); 206 } 207 208 int 209 myaddr_listen(struct sockaddr *addr, int udp_encap) 210 { 211 struct myaddr *my; 212 213 if (sysdep_sa_len(addr) > sizeof(my->addr)) { 214 plog(LLV_ERROR, LOCATION, NULL, 215 "sockaddr size larger than sockaddr_storage\n"); 216 return -1; 217 } 218 219 my = racoon_calloc(1, sizeof(struct myaddr)); 220 if (my == NULL) 221 return -1; 222 223 memcpy(&my->addr, addr, sysdep_sa_len(addr)); 224 my->udp_encap = udp_encap; 225 my->fd = -1; 226 LIST_INSERT_HEAD(&configured, my, chain); 227 228 return 0; 229 } 230 231 void 232 myaddr_sync() 233 { 234 struct myaddr *my, *next; 235 236 if (!lcconf->strict_address) { 237 kernel_sync(); 238 239 /* delete all existing listeners which are not configured */ 240 for (my = LIST_FIRST(&opened); my; my = next) { 241 next = LIST_NEXT(my, chain); 242 243 if (!myaddr_configured((struct sockaddr *) &my->addr)) 244 myaddr_delete(my); 245 } 246 } 247 } 248 249 int 250 myaddr_getfd(struct sockaddr *addr) 251 { 252 struct myaddr *my; 253 254 LIST_FOREACH(my, &opened, chain) { 255 if (cmpsaddr((struct sockaddr *) &my->addr, addr) <= CMPSADDR_WILDPORT_MATCH) 256 return my->fd; 257 } 258 259 return -1; 260 } 261 262 int 263 myaddr_getsport(struct sockaddr *addr) 264 { 265 struct myaddr *my; 266 int port = 0, wport; 267 268 LIST_FOREACH(my, &opened, chain) { 269 switch (cmpsaddr((struct sockaddr *) &my->addr, addr)) { 270 case CMPSADDR_MATCH: 271 return extract_port((struct sockaddr *) &my->addr); 272 case CMPSADDR_WILDPORT_MATCH: 273 wport = extract_port((struct sockaddr *) &my->addr); 274 if (port == 0 || wport < port) 275 port = wport; 276 break; 277 } 278 } 279 280 if (port == 0) 281 port = PORT_ISAKMP; 282 283 return port; 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 #ifndef RT_ROUNDUP 683 #define RT_ROUNDUP(a) \ 684 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 685 #endif 686 #define SAROUNDUP(X) RT_ROUNDUP(((struct sockaddr *)(X))->sa_len) 687 688 689 static size_t 690 parse_address(caddr_t start, caddr_t end, struct sockaddr_storage *dest) 691 { 692 size_t len; 693 694 if (start >= end) 695 return 0; 696 697 len = SAROUNDUP(start); 698 if (start + len > end) 699 return end - start; 700 701 if (dest != NULL && len <= sizeof(struct sockaddr_storage)) 702 memcpy(dest, start, len); 703 704 return len; 705 } 706 707 static void 708 parse_addresses(caddr_t start, caddr_t end, int flags, 709 struct sockaddr_storage *addr) 710 { 711 memset(addr, 0, sizeof(*addr)); 712 if (flags & RTA_DST) 713 start += parse_address(start, end, NULL); 714 if (flags & RTA_GATEWAY) 715 start += parse_address(start, end, NULL); 716 if (flags & RTA_NETMASK) 717 start += parse_address(start, end, NULL); 718 if (flags & RTA_GENMASK) 719 start += parse_address(start, end, NULL); 720 if (flags & RTA_IFP) 721 start += parse_address(start, end, NULL); 722 if (flags & RTA_IFA) 723 start += parse_address(start, end, addr); 724 if (flags & RTA_AUTHOR) 725 start += parse_address(start, end, NULL); 726 if (flags & RTA_BRD) 727 start += parse_address(start, end, NULL); 728 } 729 730 static void 731 kernel_handle_message(caddr_t msg) 732 { 733 struct rt_msghdr *rtm = (struct rt_msghdr *) msg; 734 struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg; 735 struct sockaddr_storage addr; 736 737 switch (rtm->rtm_type) { 738 case RTM_NEWADDR: 739 parse_addresses((caddr_t)(ifa + 1), msg + ifa->ifam_msglen, 740 ifa->ifam_addrs, &addr); 741 myaddr_open_all_configured((struct sockaddr *) &addr); 742 break; 743 case RTM_DELADDR: 744 parse_addresses((caddr_t)(ifa + 1), msg + ifa->ifam_msglen, 745 ifa->ifam_addrs, &addr); 746 myaddr_close_all_open((struct sockaddr *) &addr); 747 break; 748 case RTM_ADD: 749 case RTM_DELETE: 750 case RTM_CHANGE: 751 case RTM_GET: 752 case RTM_MISS: 753 #ifdef RTM_LOSING 754 case RTM_LOSING: 755 #endif 756 #ifdef RTM_REDIRECT 757 case RTM_REDIRECT: 758 #endif 759 case RTM_IFINFO: 760 #ifdef RTM_OIFINFO 761 case RTM_OIFINFO: 762 #endif 763 #ifdef RTM_NEWMADDR 764 case RTM_NEWMADDR: 765 case RTM_DELMADDR: 766 #endif 767 #ifdef RTM_IFANNOUNCE 768 case RTM_IFANNOUNCE: 769 #endif 770 #ifdef RTM_IEEE80211 771 case RTM_IEEE80211: 772 #endif 773 break; 774 default: 775 plog(LLV_WARNING, LOCATION, NULL, 776 "unrecognized route message with rtm_type: %d\n", 777 rtm->rtm_type); 778 break; 779 } 780 } 781 782 /*ARGSUSED*/ 783 static int 784 kernel_receive(void *ctx __unused, int fd) 785 { 786 char buf[16*1024]; 787 struct rt_msghdr *rtm = (struct rt_msghdr *) buf; 788 ssize_t len; 789 790 len = read(fd, &buf, sizeof(buf)); 791 if (len <= 0) { 792 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN) 793 plog(LLV_WARNING, LOCATION, NULL, 794 "routing socket error: %s", strerror(errno)); 795 return FALSE; 796 } 797 798 if (rtm->rtm_msglen != len) { 799 plog(LLV_WARNING, LOCATION, NULL, 800 "kernel_receive: rtm->rtm_msglen %d, len %zd, type %d\n", 801 rtm->rtm_msglen, len, rtm->rtm_type); 802 return FALSE; 803 } 804 805 kernel_handle_message(buf); 806 return TRUE; 807 } 808 809 static int 810 kernel_open_socket() 811 { 812 int fd; 813 #ifdef RO_MSGFILTER 814 unsigned char msgfilter[] = { RTM_NEWADDR, RTM_DELADDR }; 815 #endif 816 817 fd = socket(PF_ROUTE, SOCK_RAW, 0); 818 if (fd < 0) { 819 plog(LLV_ERROR, LOCATION, NULL, 820 "socket(PF_ROUTE) failed: %s", 821 strerror(errno)); 822 return -1; 823 } 824 #ifdef RO_MSGFILTER 825 if (setsockopt(fd, PF_ROUTE, RO_MSGFILTER, 826 &msgfilter, sizeof(msgfilter)) < 0) 827 plog(LLV_WARNING, LOCATION, NULL, 828 "setsockopt(RO_MSGFILER) failed: %s", 829 strerror(errno)); 830 #endif 831 close_on_exec(fd); 832 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) 833 plog(LLV_WARNING, LOCATION, NULL, 834 "failed to put socket in non-blocking mode\n"); 835 836 return fd; 837 } 838 839 static void 840 kernel_sync() 841 { 842 caddr_t ref, buf, end; 843 size_t bufsiz; 844 struct rt_msghdr *rtm; 845 846 #define MIBSIZ 6 847 int mib[MIBSIZ] = { 848 CTL_NET, 849 PF_ROUTE, 850 0, 851 0, /* AF_INET & AF_INET6 */ 852 NET_RT_IFLIST, 853 0 854 }; 855 856 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { 857 plog(LLV_WARNING, LOCATION, NULL, 858 "sysctl() error: %s", strerror(errno)); 859 return; 860 } 861 862 ref = buf = racoon_malloc(bufsiz); 863 864 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) { 865 /* Parse both interfaces and addresses. */ 866 for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) { 867 rtm = (struct rt_msghdr *) buf; 868 if (rtm->rtm_version != RTM_VERSION) 869 continue; 870 kernel_handle_message(buf); 871 } 872 } else { 873 plog(LLV_WARNING, LOCATION, NULL, 874 "sysctl() error: %s", strerror(errno)); 875 } 876 877 racoon_free(ref); 878 } 879 880 #else 881 882 #error No supported interface to monitor local addresses. 883 884 #endif 885