1/* $Id: grabmyaddr.c,v 1.23.4.2 2005/07/16 04:41:01 monas Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 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 <sys/types.h> 35#include <sys/param.h> 36#include <sys/socket.h> 37#include <sys/ioctl.h> 38 39#include <net/if.h> 40#include <net/if_var.h> 41#include <netinet/in.h> 42#include <netinet6/in6_var.h> 43#include <net/route.h> 44 45#include <stdlib.h> 46#include <stdio.h> 47#include <string.h> 48#include <errno.h> 49#ifdef HAVE_UNISTD_H 50#include <unistd.h> 51#endif 52#include <netdb.h> 53#ifdef HAVE_GETIFADDRS 54#include <ifaddrs.h> 55#include <net/if.h> 56#endif 57#include <fcntl.h> 58 59#include "var.h" 60#include "misc.h" 61#include "vmbuf.h" 62#include "plog.h" 63#include "sockmisc.h" 64#include "debug.h" 65 66#include "localconf.h" 67#include "handler.h" 68#include "grabmyaddr.h" 69#include "sockmisc.h" 70#include "isakmp_var.h" 71#include "gcmalloc.h" 72#include "nattraversal.h" 73 74#ifndef HAVE_GETIFADDRS 75static unsigned int if_maxindex (void); 76#endif 77 78static int suitable_ifaddr (const char *, const struct sockaddr *); 79#ifdef INET6 80static int suitable_ifaddr6 (const char *, const struct sockaddr *); 81#endif 82 83#ifndef HAVE_GETIFADDRS 84static unsigned int 85if_maxindex() 86{ 87 struct if_nameindex *p, *p0; 88 unsigned int max = 0; 89 90 p0 = if_nameindex(); 91 for (p = p0; p && p->if_index && p->if_name; p++) { 92 if (max < p->if_index) 93 max = p->if_index; 94 } 95 if_freenameindex(p0); 96 return max; 97} 98#endif 99 100 101void 102clear_myaddr() 103{ 104 struct myaddrs *p, *next; 105 106 for (p = lcconf->myaddrs; p; p = next) { 107 next = p->next; 108 109 delmyaddr(p); 110 } 111 112 lcconf->myaddrs = NULL; 113 114} 115 116 117struct myaddrs * 118find_myaddr(addr, udp_encap) 119 struct sockaddr *addr; 120 int udp_encap; 121{ 122 struct myaddrs *q; 123 char h1[NI_MAXHOST], h2[NI_MAXHOST]; 124 125 if (getnameinfo(addr, sysdep_sa_len(addr), h1, sizeof(h1), NULL, 0, 126 NI_NUMERICHOST | niflags) != 0) 127 return NULL; 128 129 for (q = lcconf->myaddrs; q; q = q->next) { 130 if (!q->addr) 131 continue; 132 if ((q->udp_encap && !udp_encap) 133 || (!q->udp_encap && udp_encap)) 134 continue; 135 if (addr->sa_family != q->addr->ss_family) 136 continue; 137 if (getnameinfo((struct sockaddr *)q->addr, sysdep_sa_len((struct sockaddr *)q->addr), h2, sizeof(h2), 138 NULL, 0, NI_NUMERICHOST | niflags) != 0) 139 return NULL; 140 if (strcmp(h1, h2) == 0) 141 return q; 142 } 143 144 return NULL; 145} 146 147 148// modified to avoid closing and opening sockets for 149// all interfaces each time an interface change occurs. 150// on return: addrcount = zero indicates address no longer used 151// sock = -1 indicates a new address - no socket opened yet. 152void 153grab_myaddrs() 154{ 155 struct myaddrs *p, *q; 156 struct ifaddrs *ifa0, *ifap; 157 158 char addr1[NI_MAXHOST]; 159 160 if (getifaddrs(&ifa0)) { 161 plog(ASL_LEVEL_ERR, 162 "getifaddrs failed: %s\n", strerror(errno)); 163 exit(1); 164 /*NOTREACHED*/ 165 } 166 167 // clear the in_use flag for each address in the list 168 for (p = lcconf->myaddrs; p; p = p->next) 169 p->in_use = 0; 170 171 for (ifap = ifa0; ifap; ifap = ifap->ifa_next) { 172 173 if (ifap->ifa_addr->sa_family != AF_INET 174#ifdef INET6 175 && ifap->ifa_addr->sa_family != AF_INET6 176#endif 177 ) 178 continue; 179 180 if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) { 181 plog(ASL_LEVEL_DEBUG, 182 "unsuitable address: %s %s\n", 183 ifap->ifa_name, 184 saddrwop2str(ifap->ifa_addr)); 185 continue; 186 } 187 188 p = find_myaddr(ifap->ifa_addr, 0); 189 if (p) { 190 p->in_use = 1; 191#ifdef ENABLE_NATT 192 q = find_myaddr(ifap->ifa_addr, 1); 193 if (q) 194 q->in_use = 1; 195 else if (natt_enabled_in_rmconf ()) { 196 q = dupmyaddr(p); 197 if (q == NULL) { 198 plog(ASL_LEVEL_ERR, 199 "unable to allocate space for natt addr.\n"); 200 exit(1); 201 } 202 q->udp_encap = 1; 203 } 204#endif 205 } else { 206 p = newmyaddr(); 207 if (p == NULL) { 208 plog(ASL_LEVEL_ERR, 209 "unable to allocate space for addr.\n"); 210 exit(1); 211 /*NOTREACHED*/ 212 } 213 p->addr = dupsaddr(ALIGNED_CAST(struct sockaddr_storage*)ifap->ifa_addr); 214 if (p->addr == NULL) { 215 plog(ASL_LEVEL_ERR, 216 "unable to duplicate addr.\n"); 217 exit(1); 218 /*NOTREACHED*/ 219 } 220 p->ifname = racoon_strdup(ifap->ifa_name); 221 if (p->ifname == NULL) { 222 plog(ASL_LEVEL_ERR, 223 "unable to duplicate ifname.\n"); 224 exit(1); 225 /*NOTREACHED*/ 226 } 227 p->in_use = 1; 228 229 if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len, 230 addr1, sizeof(addr1), 231 NULL, 0, 232 NI_NUMERICHOST | niflags)) 233 strlcpy(addr1, "(invalid)", sizeof(addr1)); 234 plog(ASL_LEVEL_DEBUG, 235 "my interface: %s (%s)\n", 236 addr1, ifap->ifa_name); 237 238 p->next = lcconf->myaddrs; 239 lcconf->myaddrs = p; 240 241#ifdef ENABLE_NATT 242 if (natt_enabled_in_rmconf ()) { 243 q = dupmyaddr(p); 244 if (q == NULL) { 245 plog(ASL_LEVEL_ERR, 246 "unable to allocate space for natt addr.\n"); 247 exit(1); 248 } 249 q->udp_encap = 1; 250 } 251#endif 252 253 } 254 } 255 256 freeifaddrs(ifa0); 257} 258 259 260/* 261 * check the interface is suitable or not 262 */ 263static int 264suitable_ifaddr(ifname, ifaddr) 265 const char *ifname; 266 const struct sockaddr *ifaddr; 267{ 268#if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID 269 /* Exclude any address we got through ISAKMP mode config */ 270 if (exclude_cfg_addr(ifaddr) == 0) 271 return 0; 272#endif 273 switch(ifaddr->sa_family) { 274 case AF_INET: 275 return 1; 276#ifdef INET6 277 case AF_INET6: 278 return suitable_ifaddr6(ifname, ifaddr); 279#endif 280 default: 281 return 0; 282 } 283 /*NOTREACHED*/ 284} 285 286#ifdef INET6 287static int 288suitable_ifaddr6(ifname, ifaddr) 289 const char *ifname; 290 const struct sockaddr *ifaddr; 291{ 292 struct in6_ifreq ifr6; 293 int s; 294 295 if (ifaddr->sa_family != AF_INET6) 296 return 0; 297 298 s = socket(PF_INET6, SOCK_DGRAM, 0); 299 if (s == -1) { 300 plog(ASL_LEVEL_ERR, 301 "socket(SOCK_DGRAM) failed:%s\n", strerror(errno)); 302 return 0; 303 } 304 305 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { 306 plog(ASL_LEVEL_ERR, "failed to put IPv6 socket in non-blocking mode\n"); 307 } 308 309 memset(&ifr6, 0, sizeof(ifr6)); 310 strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)); 311 312 memcpy(&ifr6.ifr_addr, ifaddr, sizeof(struct sockaddr_in6)); // Wcast-align fix - copy instread of assign with cast 313 314 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { 315 plog(ASL_LEVEL_ERR, 316 "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno)); 317 close(s); 318 return 0; 319 } 320 321 close(s); 322 323 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED 324 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED 325 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST 326 /* Deprecated addresses will now be dropped by isakmp_close_unused */ 327 || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) 328 return 0; 329 330 /* suitable */ 331 return 1; 332} 333#endif 334 335 336/* 337 * initialize default port for ISAKMP to send, if no "listen" 338 * directive is specified in config file. 339 * 340 * DO NOT listen to wildcard addresses. if you receive packets to 341 * wildcard address, you'll be in trouble (DoS attack possible by 342 * broadcast storm). 343 */ 344int 345autoconf_myaddrsport() 346{ 347 struct myaddrs *p; 348 int n; 349 350 plog(ASL_LEVEL_DEBUG, 351 "configuring default isakmp port.\n"); 352 353 for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) { 354 set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp); 355 } 356 plog(ASL_LEVEL_DEBUG, 357 "%d addrs are configured successfully\n", n); 358 359 return 0; 360} 361 362/* 363 * get a port number to which racoon binded. 364 * NOTE: network byte order returned. 365 */ 366u_short 367getmyaddrsport(local) 368 struct sockaddr_storage *local; 369{ 370 struct myaddrs *p, *bestmatch = NULL; 371 u_short bestmatch_port = PORT_ISAKMP; 372 373 /* get a relative port */ 374 for (p = lcconf->myaddrs; p; p = p->next) { 375 if (!p->addr) 376 continue; 377 if (!cmpsaddrwop(local, p->addr)) { 378 if (! bestmatch) { 379 bestmatch = p; 380 continue; 381 } 382 383 switch (p->addr->ss_family) { 384 case AF_INET: 385 if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) { 386 bestmatch = p; 387 bestmatch_port = ((struct sockaddr_in *)p->addr)->sin_port; 388 break; 389 } 390 break; 391#ifdef INET6 392 case AF_INET6: 393 if (((struct sockaddr_in6 *)p->addr)->sin6_port == PORT_ISAKMP) { 394 bestmatch = p; 395 bestmatch_port = ((struct sockaddr_in6 *)p->addr)->sin6_port; 396 break; 397 } 398 break; 399#endif 400 default: 401 plog(ASL_LEVEL_ERR, 402 "unsupported AF %d\n", p->addr->ss_family); 403 continue; 404 } 405 } 406 } 407 408 return htons(bestmatch_port); 409} 410 411struct myaddrs * 412newmyaddr() 413{ 414 struct myaddrs *new; 415 416 new = racoon_calloc(1, sizeof(*new)); 417 if (new == NULL) { 418 plog(ASL_LEVEL_ERR, 419 "failed to allocate buffer for myaddrs.\n"); 420 return NULL; 421 } 422 423 new->next = NULL; 424 new->addr = NULL; 425 new->source = NULL; 426 new->sock = -1; 427#ifdef __APPLE_ 428 new->ifname = NULL; 429#endif 430 431 return new; 432} 433 434struct myaddrs * 435dupmyaddr(struct myaddrs *old) 436{ 437 struct myaddrs *new; 438 439 new = racoon_calloc(1, sizeof(*new)); 440 if (new == NULL) { 441 plog(ASL_LEVEL_ERR, 442 "failed to allocate buffer for myaddrs.\n"); 443 return NULL; 444 } 445 446 /* Copy the whole structure and set the differences. */ 447 memcpy (new, old, sizeof (*new)); 448 new->addr = dupsaddr (old->addr); 449 if (new->addr == NULL) { 450 plog(ASL_LEVEL_ERR, 451 "failed to allocate buffer for duplicate addr.\n"); 452 racoon_free(new); 453 return NULL; 454 } 455 if (old->ifname) { 456 new->ifname = racoon_strdup(old->ifname); 457 if (new->ifname == NULL) { 458 plog(ASL_LEVEL_ERR, 459 "failed to allocate buffer for duplicate ifname.\n"); 460 racoon_free(new->addr); 461 racoon_free(new); 462 return NULL; 463 } 464 } 465 new->source = NULL; 466 new->sock = -1; 467 468 new->next = old->next; 469 old->next = new; 470 471 return new; 472} 473 474void 475insmyaddr(new, head) 476 struct myaddrs *new; 477 struct myaddrs **head; 478{ 479 new->next = *head; 480 *head = new; 481} 482 483void 484delmyaddr(myaddr) 485 struct myaddrs *myaddr; 486{ 487 if (myaddr->addr) 488 racoon_free(myaddr->addr); 489 if (myaddr->ifname) 490 racoon_free(myaddr->ifname); 491 racoon_free(myaddr); 492} 493 494void 495update_myaddrs(void *unused) 496{ 497 grab_myaddrs(); 498 isakmp_close_unused(); 499 autoconf_myaddrsport(); 500 isakmp_open(); 501} 502 503 504int 505initmyaddr(void) 506{ 507 508 if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) { 509 grab_myaddrs(); 510 511 if (autoconf_myaddrsport() < 0) 512 return -1; 513 } 514 515 return 0; 516} 517 518 519/* select the socket to be sent */ 520/* should implement other method. */ 521int 522getsockmyaddr(struct sockaddr *my) 523{ 524 struct myaddrs *p, *lastresort = NULL; 525 526 for (p = lcconf->myaddrs; p; p = p->next) { 527 if (p->addr == NULL) 528 continue; 529 if (my->sa_family == p->addr->ss_family) { 530 lastresort = p; 531 } else continue; 532 if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr) 533 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) { 534 break; 535 } 536 } 537 if (!p) 538 p = lastresort; 539 if (!p) { 540 plog(ASL_LEVEL_ERR, 541 "no socket matches address family %d\n", 542 my->sa_family); 543 return -1; 544 } 545 546 return p->sock; 547} 548 549void 550pfroute_handler(void *unused) 551{ 552 553 struct rtmessage { // Wcast-align fix - force alignment 554 struct rt_msghdr rtm; 555 char discard[BUFSIZ]; 556 } msg; 557 558 int len; 559 560 while((len = read(lcconf->rtsock, &msg, sizeof(msg))) < 0) { 561 if (errno == EINTR) 562 continue; 563 plog(ASL_LEVEL_DEBUG, 564 "read(PF_ROUTE) failed: %s\n", 565 strerror(errno)); 566 return; 567 } 568 if (len < msg.rtm.rtm_msglen) { 569 plog(ASL_LEVEL_DEBUG, 570 "read(PF_ROUTE) short read\n"); 571 return; 572 } 573 switch (msg.rtm.rtm_type) { 574 case RTM_NEWADDR: 575 case RTM_DELADDR: 576 case RTM_DELETE: 577 case RTM_IFINFO: 578 break; 579 case RTM_MISS: 580 /* ignore this message silently */ 581 return; 582 default: 583 //plog(ASL_LEVEL_DEBUG, 584 // "msg %d not interesting\n", msg.rtm.rtm_type); 585 return; 586 } 587 /* XXX more filters here? */ 588 589 plog(ASL_LEVEL_DEBUG, 590 "caught rtm:%d, need update interface address list\n", 591 msg.rtm.rtm_type); 592 593 // Interface changes occurred - update addrs 594 update_myaddrs(NULL); 595} 596 597void 598pfroute_close(void) 599{ 600 601 dispatch_source_cancel(lcconf->rt_source); 602 lcconf->rt_source = NULL; 603} 604 605int 606pfroute_init(void) 607{ 608 int sock; 609 610 /* initialize routing socket */ 611 lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 612 if (lcconf->rtsock < 0) { 613 plog(ASL_LEVEL_DEBUG, 614 "socket(PF_ROUTE) failed: %s", 615 strerror(errno)); 616 return -1; 617 } 618 if (fcntl(lcconf->rtsock, F_SETFL, O_NONBLOCK) == -1) { 619 plog(ASL_LEVEL_DEBUG, "failed to put PF_ROUTE socket in non-blocking mode\n"); 620 } 621 622 lcconf->rt_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->rtsock, 0, dispatch_get_main_queue()); 623 if (lcconf->rt_source == NULL) { 624 plog(ASL_LEVEL_DEBUG, "could not create pfroute socket source."); 625 return -1; 626 } 627 dispatch_source_set_event_handler_f(lcconf->rt_source, pfroute_handler); 628 sock = lcconf->rtsock; 629 dispatch_source_set_cancel_handler(lcconf->rt_source, 630 ^{ 631 close(sock); 632 }); 633 dispatch_resume(lcconf->rt_source); 634 return 0; 635} 636 637 638 639