grabmyaddr.c revision 1.25
1/* $NetBSD: grabmyaddr.c,v 1.25 2010/10/21 06:15:28 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 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) == 0) 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) == 0) 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) != 0) 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) == 0) 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 278 LIST_FOREACH(my, &opened, chain) { 279 if (cmpsaddr((struct sockaddr *) &my->addr, addr) == 0) 280 return extract_port((struct sockaddr *) &my->addr); 281 } 282 283 return PORT_ISAKMP; 284} 285 286void 287myaddr_init_lists() 288{ 289 LIST_INIT(&configured); 290 LIST_INIT(&opened); 291} 292 293int 294myaddr_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 309void 310myaddr_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 322static void 323parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 324{ 325 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 326 while (RTA_OK(rta, len)) { 327 if (rta->rta_type <= max) 328 tb[rta->rta_type] = rta; 329 rta = RTA_NEXT(rta,len); 330 } 331} 332 333static int 334netlink_enumerate(fd, family, type) 335 int fd; 336 int family; 337 int type; 338{ 339 struct { 340 struct nlmsghdr nlh; 341 struct rtgenmsg g; 342 } req; 343 struct sockaddr_nl addr; 344 static __u32 seq = 0; 345 346 memset(&addr, 0, sizeof(addr)); 347 addr.nl_family = AF_NETLINK; 348 349 memset(&req, 0, sizeof(req)); 350 req.nlh.nlmsg_len = sizeof(req); 351 req.nlh.nlmsg_type = type; 352 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; 353 req.nlh.nlmsg_pid = 0; 354 req.nlh.nlmsg_seq = ++seq; 355 req.g.rtgen_family = family; 356 357 return sendto(fd, (void *) &req, sizeof(req), 0, 358 (struct sockaddr *) &addr, sizeof(addr)) >= 0; 359} 360 361static int 362netlink_process(struct nlmsghdr *h) 363{ 364 struct sockaddr_storage addr; 365 struct ifaddrmsg *ifa; 366 struct rtattr *rta[IFA_MAX+1]; 367 struct sockaddr_in *sin; 368#ifdef INET6 369 struct sockaddr_in6 *sin6; 370#endif 371 372 /* is this message interesting? */ 373 if (h->nlmsg_type != RTM_NEWADDR && 374 h->nlmsg_type != RTM_DELADDR) 375 return 0; 376 377 ifa = NLMSG_DATA(h); 378 parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h)); 379 380 if (ifa->ifa_flags & IFA_F_TENTATIVE) 381 return 0; 382 383 if (rta[IFA_LOCAL] == NULL) 384 rta[IFA_LOCAL] = rta[IFA_ADDRESS]; 385 if (rta[IFA_LOCAL] == NULL) 386 return 0; 387 388 /* setup the socket address */ 389 memset(&addr, 0, sizeof(addr)); 390 addr.ss_family = ifa->ifa_family; 391 switch (ifa->ifa_family) { 392 case AF_INET: 393 sin = (struct sockaddr_in *) &addr; 394 memcpy(&sin->sin_addr, RTA_DATA(rta[IFA_LOCAL]), 395 sizeof(sin->sin_addr)); 396 break; 397#ifdef INET6 398 case AF_INET6: 399 sin6 = (struct sockaddr_in6 *) &addr; 400 memcpy(&sin6->sin6_addr, RTA_DATA(rta[IFA_LOCAL]), 401 sizeof(sin6->sin6_addr)); 402 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 403 sin6->sin6_scope_id = ifa->ifa_index; 404 break; 405#endif 406 default: 407 return 0; 408 } 409 410 plog(LLV_DEBUG, LOCATION, NULL, 411 "Netlink: address %s %s\n", 412 saddrwop2str((struct sockaddr *) &addr), 413 h->nlmsg_type == RTM_NEWADDR ? "added" : "deleted"); 414 415 if (h->nlmsg_type == RTM_NEWADDR) 416 myaddr_open_all_configured((struct sockaddr *) &addr); 417 else 418 myaddr_close_all_open((struct sockaddr *) &addr); 419 420 return 0; 421} 422 423static int 424kernel_receive(ctx, fd) 425 void *ctx; 426 int fd; 427{ 428 struct sockaddr_nl nladdr; 429 struct iovec iov; 430 struct msghdr msg = { 431 .msg_name = &nladdr, 432 .msg_namelen = sizeof(nladdr), 433 .msg_iov = &iov, 434 .msg_iovlen = 1, 435 }; 436 struct nlmsghdr *h; 437 int len, status; 438 char buf[16*1024]; 439 440 iov.iov_base = buf; 441 while (1) { 442 iov.iov_len = sizeof(buf); 443 status = recvmsg(fd, &msg, MSG_DONTWAIT); 444 if (status < 0) { 445 if (errno == EINTR) 446 continue; 447 if (errno == EAGAIN) 448 return FALSE; 449 continue; 450 } 451 if (status == 0) 452 return FALSE; 453 454 h = (struct nlmsghdr *) buf; 455 while (NLMSG_OK(h, status)) { 456 netlink_process(h); 457 h = NLMSG_NEXT(h, status); 458 } 459 } 460 461 return TRUE; 462} 463 464static int 465kernel_open_socket() 466{ 467 struct sockaddr_nl nl; 468 int fd; 469 470 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 471 if (fd < 0) { 472 plog(LLV_ERROR, LOCATION, NULL, 473 "socket(PF_NETLINK) failed: %s", 474 strerror(errno)); 475 return -1; 476 } 477 close_on_exec(fd); 478 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) 479 plog(LLV_WARNING, LOCATION, NULL, 480 "failed to put socket in non-blocking mode\n"); 481 482 memset(&nl, 0, sizeof(nl)); 483 nl.nl_family = AF_NETLINK; 484 nl.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; 485 if (bind(fd, (struct sockaddr*) &nl, sizeof(nl)) < 0) { 486 plog(LLV_ERROR, LOCATION, NULL, 487 "bind(PF_NETLINK) failed: %s\n", 488 strerror(errno)); 489 close(fd); 490 return -1; 491 } 492 return fd; 493} 494 495static void 496kernel_sync() 497{ 498 int fd = lcconf->rtsock; 499 500 /* refresh addresses */ 501 if (!netlink_enumerate(fd, PF_UNSPEC, RTM_GETADDR)) { 502 plog(LLV_ERROR, LOCATION, NULL, 503 "unable to enumerate addresses: %s\n", 504 strerror(errno)); 505 return; 506 } 507 508 /* receive replies */ 509 while (kernel_receive(NULL, fd) == TRUE); 510} 511 512#elif defined(USE_ROUTE) 513 514#define ROUNDUP(a) \ 515 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 516 517#define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) 518 519static size_t 520parse_address(start, end, dest) 521 caddr_t start; 522 caddr_t end; 523 struct sockaddr_storage *dest; 524{ 525 int len; 526 527 if (start >= end) 528 return 0; 529 530 len = SAROUNDUP(start); 531 if (start + len > end) 532 return end - start; 533 534 if (dest != NULL && len <= sizeof(struct sockaddr_storage)) 535 memcpy(dest, start, len); 536 537 return len; 538} 539 540static void 541parse_addresses(start, end, flags, addr) 542 caddr_t start; 543 caddr_t end; 544 int flags; 545 struct sockaddr_storage *addr; 546{ 547 memset(addr, 0, sizeof(*addr)); 548 if (flags & RTA_DST) 549 start += parse_address(start, end, NULL); 550 if (flags & RTA_GATEWAY) 551 start += parse_address(start, end, NULL); 552 if (flags & RTA_NETMASK) 553 start += parse_address(start, end, NULL); 554 if (flags & RTA_GENMASK) 555 start += parse_address(start, end, NULL); 556 if (flags & RTA_IFP) 557 start += parse_address(start, end, NULL); 558 if (flags & RTA_IFA) 559 start += parse_address(start, end, addr); 560 if (flags & RTA_AUTHOR) 561 start += parse_address(start, end, NULL); 562 if (flags & RTA_BRD) 563 start += parse_address(start, end, NULL); 564} 565 566static void 567kernel_handle_message(msg) 568 caddr_t msg; 569{ 570 struct rt_msghdr *rtm = (struct rt_msghdr *) msg; 571 struct ifa_msghdr *ifa = (struct ifa_msghdr *) msg; 572 struct sockaddr_storage addr; 573 574 switch (rtm->rtm_type) { 575 case RTM_NEWADDR: 576 parse_addresses(ifa + 1, msg + ifa->ifam_msglen, 577 ifa->ifam_addrs, &addr); 578 myaddr_open_all_configured((struct sockaddr *) &addr); 579 break; 580 case RTM_DELADDR: 581 parse_addresses(ifa + 1, msg + ifa->ifam_msglen, 582 ifa->ifam_addrs, &addr); 583 myaddr_close_all_open((struct sockaddr *) &addr); 584 break; 585 case RTM_ADD: 586 case RTM_DELETE: 587 case RTM_CHANGE: 588 case RTM_MISS: 589 case RTM_IFINFO: 590#ifdef RTM_OIFINFO 591 case RTM_OIFINFO: 592#endif 593#ifdef RTM_NEWMADDR 594 case RTM_NEWMADDR: 595 case RTM_DELMADDR: 596#endif 597#ifdef RTM_IFANNOUNCE 598 case RTM_IFANNOUNCE: 599#endif 600 break; 601 default: 602 plog(LLV_WARNING, LOCATION, NULL, 603 "unrecognized route message with rtm_type: %d", 604 rtm->rtm_type); 605 break; 606 } 607} 608 609static int 610kernel_receive(ctx, fd) 611 void *ctx; 612 int fd; 613{ 614 char buf[16*1024]; 615 struct rt_msghdr *rtm = (struct rt_msghdr *) buf; 616 int len; 617 618 len = read(fd, &buf, sizeof(buf)); 619 if (len <= 0) { 620 if (len < 0 && errno != EWOULDBLOCK && errno != EAGAIN) 621 plog(LLV_WARNING, LOCATION, NULL, 622 "routing socket error: %s", strerror(errno)); 623 return FALSE; 624 } 625 626 if (rtm->rtm_msglen != len) { 627 plog(LLV_WARNING, LOCATION, NULL, 628 "kernel_receive: rtm->rtm_msglen %d, len %d, type %d\n", 629 rtm->rtm_msglen, len, rtm->rtm_type); 630 return FALSE; 631 } 632 633 kernel_handle_message(buf); 634 return TRUE; 635} 636 637static int 638kernel_open_socket() 639{ 640 int fd; 641 642 fd = socket(PF_ROUTE, SOCK_RAW, 0); 643 if (fd < 0) { 644 plog(LLV_ERROR, LOCATION, NULL, 645 "socket(PF_ROUTE) failed: %s", 646 strerror(errno)); 647 return -1; 648 } 649 close_on_exec(fd); 650 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) 651 plog(LLV_WARNING, LOCATION, NULL, 652 "failed to put socket in non-blocking mode\n"); 653 654 return fd; 655} 656 657static void 658kernel_sync() 659{ 660 caddr_t ref, buf, end; 661 size_t bufsiz; 662 struct if_msghdr *ifm; 663 struct interface *ifp; 664 665#define MIBSIZ 6 666 int mib[MIBSIZ] = { 667 CTL_NET, 668 PF_ROUTE, 669 0, 670 0, /* AF_INET & AF_INET6 */ 671 NET_RT_IFLIST, 672 0 673 }; 674 675 if (sysctl(mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { 676 plog(LLV_WARNING, LOCATION, NULL, 677 "sysctl() error: %s", strerror(errno)); 678 return; 679 } 680 681 ref = buf = racoon_malloc(bufsiz); 682 683 if (sysctl(mib, MIBSIZ, buf, &bufsiz, NULL, 0) >= 0) { 684 /* Parse both interfaces and addresses. */ 685 for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { 686 ifm = (struct if_msghdr *) buf; 687 kernel_handle_message(buf); 688 } 689 } else { 690 plog(LLV_WARNING, LOCATION, NULL, 691 "sysctl() error: %s", strerror(errno)); 692 } 693 694 racoon_free(ref); 695} 696 697#else 698 699#error No supported interface to monitor local addresses. 700 701#endif 702