1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* -*- Mode: C; tab-width: 4 -*- 6 * 7 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 21 Change History (most recent first): 22 23 $Log: mDNSUNP.c,v $ 24 Revision 1.34 2006/08/14 23:24:47 cheshire 25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 26 27 Revision 1.33 2006/03/13 23:14:21 cheshire 28 <rdar://problem/4427969> Compile problems on FreeBSD 29 Use <netinet/in_var.h> instead of <netinet6/in6_var.h> 30 31 Revision 1.32 2005/12/21 02:56:43 cheshire 32 <rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined 33 34 Revision 1.31 2005/12/21 02:46:05 cheshire 35 <rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite 36 37 Revision 1.30 2005/11/29 20:03:02 mkrochma 38 Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN 39 40 Revision 1.29 2005/11/12 02:23:10 cheshire 41 <rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR 42 43 Revision 1.28 2005/10/31 22:09:45 cheshire 44 Buffer "char addr6[33]" was seven bytes too small 45 46 Revision 1.27 2005/06/29 15:54:21 cheshire 47 <rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD 48 Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS 49 50 Revision 1.26 2005/04/08 21:43:59 ksekar 51 <rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture 52 Submitted by Andrew de Quincey 53 54 Revision 1.25 2005/04/08 21:37:57 ksekar 55 <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux 56 57 Revision 1.24 2005/04/08 21:30:16 ksekar 58 <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9 59 Patch submitted by Bernd Kuhls 60 61 Revision 1.23 2004/12/01 04:25:05 cheshire 62 <rdar://problem/3872803> Darwin patches for Solaris and Suse 63 Provide daemon() for platforms that don't have it 64 65 Revision 1.22 2004/11/30 22:37:01 cheshire 66 Update copyright dates and add "Mode: C; tab-width: 4" headers 67 68 Revision 1.21 2004/11/08 22:13:59 rpantos 69 Create sockf6 lazily when v6 interface found. 70 71 Revision 1.20 2004/10/16 00:17:01 cheshire 72 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check 73 74 Revision 1.19 2004/07/20 01:47:36 rpantos 75 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr. 76 77 Revision 1.18 2004/07/08 21:30:21 rpantos 78 79 Revision 1.17 2004/06/25 00:26:27 rpantos 80 Changes to fix the Posix build on Solaris. 81 82 Revision 1.16 2004/03/20 05:37:09 cheshire 83 Fix contributed by Terry Lambert & Alfred Perlstein: 84 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x 85 86 Revision 1.15 2004/02/14 01:09:45 rpantos 87 Just use HAVE_IPV6 rather than defined(HAVE_IPV6). 88 89 Revision 1.14 2003/12/11 18:53:40 cheshire 90 Fix compiler warning reported by Paul Guyot 91 92 Revision 1.13 2003/12/08 20:47:02 rpantos 93 Add support for mDNSResponder on Linux. 94 95 Revision 1.12 2003/09/02 20:47:13 cheshire 96 Fix signed/unsigned warning 97 98 Revision 1.11 2003/08/12 19:56:26 cheshire 99 Update to APSL 2.0 100 101 Revision 1.10 2003/08/06 18:20:51 cheshire 102 Makefile cleanup 103 104 Revision 1.9 2003/07/14 18:11:54 cheshire 105 Fix stricter compiler warnings 106 107 Revision 1.8 2003/07/02 21:19:59 cheshire 108 <rdar://problem/3313413> Update copyright notices, etc., in source code comments 109 110 Revision 1.7 2003/03/20 21:10:31 cheshire 111 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris 112 113 Revision 1.6 2003/03/13 03:46:21 cheshire 114 Fixes to make the code build on Linux 115 116 Revision 1.5 2003/02/07 03:02:02 cheshire 117 Submitted by: Mitsutaka Watanabe 118 The code saying "index += 1;" was effectively making up random interface index values. 119 The right way to find the correct interface index is if_nametoindex(); 120 121 Revision 1.4 2002/12/23 22:13:31 jgraessl 122 123 Reviewed by: Stuart Cheshire 124 Initial IPv6 support for mDNSResponder. 125 126 Revision 1.3 2002/09/21 20:44:53 zarzycki 127 Added APSL info 128 129 Revision 1.2 2002/09/19 04:20:44 cheshire 130 Remove high-ascii characters that confuse some systems 131 132 Revision 1.1 2002/09/17 06:24:34 cheshire 133 First checkin 134 135 */ 136 137 #include "mDNSUNP.h" 138 139 #include "mDNSDebug.h" 140 141 #include <errno.h> 142 #include <assert.h> 143 #include <string.h> 144 #include <stdlib.h> 145 #include <sys/uio.h> 146 #include <sys/ioctl.h> 147 #include <unistd.h> 148 #include <stdio.h> 149 150 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P) 151 macro, usually defined in <sys/param.h> or someplace like that, to make sure the 152 CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO 153 should be set to the name of the header to include to get the ALIGN(P) macro. 154 */ 155 #ifdef NEED_ALIGN_MACRO 156 #include NEED_ALIGN_MACRO 157 #endif 158 159 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but 160 other platforms don't even have that include file. So, 161 if we haven't yet got a definition, let's try to find 162 <sys/sockio.h>. 163 */ 164 165 #ifndef SIOCGIFCONF 166 #include <sys/sockio.h> 167 #endif 168 169 /* sockaddr_dl is only referenced if we're using IP_RECVIF, 170 so only include the header in that case. 171 */ 172 173 #ifdef IP_RECVIF 174 #include <net/if_dl.h> 175 #endif 176 177 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX 178 #if !HAVE_SOLARIS 179 #include <net/if_var.h> 180 #else 181 #include <alloca.h> 182 #ifdef HAVE_SOLARIS_ZONES 183 #include <zone.h> 184 #endif /* HAVE_SOLARIS_ZONES */ 185 #endif /* !HAVE_SOLARIS */ 186 #include <netinet/in_var.h> 187 // NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us 188 #endif 189 190 #if defined(AF_INET6) && HAVE_IPV6 191 192 #if HAVE_LINUX 193 #include <netdb.h> 194 #include <arpa/inet.h> 195 196 /* Converts a prefix length to IPv6 network mask */ 197 void plen_to_mask(int plen, char *addr) { 198 int i; 199 int colons=7; /* Number of colons in IPv6 address */ 200 int bits_in_block=16; /* Bits per IPv6 block */ 201 for(i=0;i<=colons;i++) { 202 int block, ones=0xffff, ones_in_block; 203 if(plen>bits_in_block) ones_in_block=bits_in_block; 204 else ones_in_block=plen; 205 block = ones & (ones << (bits_in_block-ones_in_block)); 206 i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block); 207 plen -= ones_in_block; 208 } 209 } 210 211 /* Gets IPv6 interface information from the /proc filesystem in linux*/ 212 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 213 { 214 struct ifi_info *ifi, *ifihead, **ifipnext; 215 FILE *fp; 216 char addr[8][5]; 217 int flags, myflags, index, plen, scope; 218 char ifname[8], lastname[IFNAMSIZ]; 219 char addr6[32+7+1]; /* don't forget the seven ':' */ 220 struct addrinfo hints, *res0; 221 struct sockaddr_in6 *sin6; 222 struct in6_addr *addrptr; 223 int err; 224 225 res0=NULL; 226 ifihead = NULL; 227 ifipnext = &ifihead; 228 lastname[0] = 0; 229 230 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { 231 while (fscanf(fp, 232 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", 233 addr[0],addr[1],addr[2],addr[3], 234 addr[4],addr[5],addr[6],addr[7], 235 &index, &plen, &scope, &flags, ifname) != EOF) { 236 237 myflags = 0; 238 if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { 239 if (doaliases == 0) 240 continue; /* already processed this interface */ 241 myflags = IFI_ALIAS; 242 } 243 memcpy(lastname, ifname, IFNAMSIZ); 244 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 245 if (ifi == NULL) { 246 goto gotError; 247 } 248 249 *ifipnext = ifi; /* prev points to this new one */ 250 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 251 252 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", 253 addr[0],addr[1],addr[2],addr[3], 254 addr[4],addr[5],addr[6],addr[7]); 255 256 /* Add address of the interface */ 257 memset(&hints, 0, sizeof(hints)); 258 hints.ai_family = AF_INET6; 259 hints.ai_flags = AI_NUMERICHOST; 260 err = getaddrinfo(addr6, NULL, &hints, &res0); 261 if (err) { 262 goto gotError; 263 } 264 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 265 if (ifi->ifi_addr == NULL) { 266 goto gotError; 267 } 268 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6)); 269 270 /* Add netmask of the interface */ 271 char ipv6addr[INET6_ADDRSTRLEN]; 272 plen_to_mask(plen, ipv6addr); 273 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); 274 if (ifi->ifi_addr == NULL) { 275 goto gotError; 276 } 277 sin6=calloc(1, sizeof(struct sockaddr_in6)); 278 addrptr=calloc(1, sizeof(struct in6_addr)); 279 inet_pton(family, ipv6addr, addrptr); 280 sin6->sin6_family=family; 281 sin6->sin6_addr=*addrptr; 282 sin6->sin6_scope_id=scope; 283 memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6)); 284 free(sin6); 285 286 287 /* Add interface name */ 288 memcpy(ifi->ifi_name, ifname, IFI_NAME); 289 290 /* Add interface index */ 291 ifi->ifi_index = index; 292 293 /* If interface is in /proc then it is up*/ 294 ifi->ifi_flags = IFF_UP; 295 296 freeaddrinfo(res0); 297 res0=NULL; 298 } 299 } 300 goto done; 301 302 gotError: 303 if (ifihead != NULL) { 304 free_ifi_info(ifihead); 305 ifihead = NULL; 306 } 307 if (res0 != NULL) { 308 freeaddrinfo(res0); 309 res0=NULL; 310 } 311 done: 312 return(ifihead); /* pointer to first structure in linked list */ 313 } 314 315 #endif /* LINUX */ 316 #endif /* defined(AF_INET6) && HAVE_IPV6 */ 317 318 #if HAVE_SOLARIS 319 320 /* 321 * Converts prefix length to network mask. Assumes 322 * addr points to a zeroed out buffer and prefix <= sizeof(addr) 323 * Unlike plen_to_mask returns netmask in binary form and not 324 * in text form. 325 */ 326 static void plen_to_netmask(int prefix, unsigned char *addr) { 327 for (; prefix > 8; prefix -= 8) 328 *addr++ = 0xff; 329 for (; prefix > 0; prefix--) 330 *addr = (*addr >> 1) | 0x80; 331 } 332 333 /* 334 * This function goes through all the IP interfaces associated with a 335 * physical interface and finds the best matched one for use by mDNS. 336 * Returns NULL when none of the IP interfaces associated with a physical 337 * interface are usable. Otherwise returns the best matched interface 338 * information and a pointer to the best matched lifreq. 339 */ 340 struct ifi_info * 341 select_src_ifi_info_solaris(int sockfd, int numifs, 342 struct lifreq *lifrlist, const char *curifname, 343 struct lifreq **best_lifr) 344 { 345 struct lifreq *lifr; 346 struct lifreq lifrcopy; 347 struct ifi_info *ifi; 348 char *chptr; 349 char cmpifname[LIFNAMSIZ]; 350 int i; 351 uint64_t best_lifrflags; 352 uint64_t ifflags; 353 354 *best_lifr = NULL; 355 356 /* 357 * Check all logical interfaces associated with the physical 358 * interface and figure out which one works best for us. 359 */ 360 for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) { 361 362 if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname)) 363 continue; /* skip interface */ 364 365 /* Strip logical interface number before checking ifname */ 366 if ((chptr = strchr(cmpifname, ':')) != NULL) 367 *chptr = '\0'; 368 369 /* 370 * Check ifname to see if the logical interface is associated 371 * with the physical interface we are interested in. 372 */ 373 if (strcmp(cmpifname, curifname) != 0) 374 continue; 375 376 #ifdef HAVE_SOLARIS_ZONES 377 /* Check the zone associated with the address */ 378 lifrcopy = *lifr; 379 if (ioctl(sockfd, SIOCGLIFZONE, &lifrcopy) < 0) { 380 /* interface removed */ 381 if (errno == ENXIO) 382 continue; 383 return(NULL); 384 } 385 if (lifrcopy.lifr_zoneid != getzoneid()) 386 continue; 387 #endif 388 389 lifrcopy = *lifr; 390 if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) { 391 /* interface removed */ 392 if (errno == ENXIO) 393 continue; 394 return(NULL); 395 } 396 ifflags = lifrcopy.lifr_flags; 397 398 /* ignore address if not up */ 399 if ((ifflags & IFF_UP) == 0) 400 continue; 401 /* 402 * Avoid address if any of the following flags are set: 403 * IFF_NOXMIT: no packets transmitted over interface 404 * IFF_NOLOCAL: no address 405 * IFF_PRIVATE: is not advertised 406 */ 407 if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE)) 408 continue; 409 410 /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */ 411 if (lifr->lifr_addr.ss_family == AF_INET) { 412 struct sockaddr_in *sinptr; 413 414 sinptr = (struct sockaddr_in *) &lifr->lifr_addr; 415 if (sinptr->sin_addr.s_addr == INADDR_ANY) 416 continue; 417 } 418 419 if (*best_lifr != NULL) { 420 /* 421 * Check if we found a better interface by checking 422 * the flags. If flags are identical we prefer 423 * the new found interface. 424 */ 425 uint64_t diff_flags = best_lifrflags ^ ifflags; 426 427 /* If interface has a different set of flags */ 428 if (diff_flags != 0) { 429 /* Check flags in increasing order of ones we prefer */ 430 431 /* Address temporary? */ 432 if ((diff_flags & IFF_TEMPORARY) && 433 (ifflags & IFF_TEMPORARY)) 434 continue; 435 /* Deprecated address? */ 436 if ((diff_flags & IFF_DEPRECATED) && 437 (ifflags & IFF_DEPRECATED)) 438 continue; 439 /* Last best-matched interface address has preferred? */ 440 if ((diff_flags & IFF_PREFERRED) && 441 ((ifflags & IFF_PREFERRED) == 0)) 442 continue; 443 } 444 } 445 446 /* Set best match interface & flags */ 447 *best_lifr = lifr; 448 best_lifrflags = ifflags; 449 } 450 451 if (*best_lifr == NULL) 452 return(NULL); 453 454 /* Found a match: return the interface information */ 455 ifi = calloc(1, sizeof(struct ifi_info)); 456 if (ifi == NULL) 457 return(NULL); 458 459 ifi->ifi_flags = best_lifrflags; 460 ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name); 461 if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) { 462 free(ifi); 463 return(NULL); 464 } 465 return(ifi); 466 } 467 468 /* 469 * Returns a list of IP interface information on Solaris. The function 470 * returns all IP interfaces on the system with IPv4 address assigned 471 * when passed AF_INET and returns IP interfaces with IPv6 address assigned 472 * when AF_INET6 is passed. 473 */ 474 struct ifi_info *get_ifi_info_solaris(int family) 475 { 476 struct ifi_info *ifi, *ifihead, **ifipnext; 477 int sockfd; 478 int len; 479 char *buf; 480 char *cptr; 481 char ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ]; 482 struct sockaddr_in *sinptr; 483 struct lifnum lifn; 484 struct lifconf lifc; 485 struct lifreq *lifrp, *best_lifr; 486 struct lifreq lifrcopy; 487 int numifs, nlifr, n; 488 #if defined(AF_INET6) && HAVE_IPV6 489 struct sockaddr_in6 *sinptr6; 490 #endif 491 492 ifihead = NULL; 493 494 sockfd = socket(family, SOCK_DGRAM, 0); 495 if (sockfd < 0) 496 goto gotError; 497 498 again: 499 lifn.lifn_family = family; 500 lifn.lifn_flags = 0; 501 if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0) 502 goto gotError; 503 /* 504 * Pad interface count to detect & retrieve any 505 * additional interfaces between IFNUM & IFCONF calls. 506 */ 507 lifn.lifn_count += 4; 508 numifs = lifn.lifn_count; 509 len = numifs * sizeof (struct lifreq); 510 buf = alloca(len); 511 512 lifc.lifc_family = family; 513 lifc.lifc_len = len; 514 lifc.lifc_buf = buf; 515 lifc.lifc_flags = 0; 516 517 if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0) 518 goto gotError; 519 520 nlifr = lifc.lifc_len / sizeof(struct lifreq); 521 if (nlifr >= numifs) 522 goto again; 523 524 lifrp = lifc.lifc_req; 525 ifipnext = &ifihead; 526 527 for (n = nlifr; n > 0; n--, lifrp++) { 528 529 if (lifrp->lifr_addr.ss_family != family) 530 continue; 531 532 /* 533 * See if we have already processed the interface 534 * by checking the interface names. 535 */ 536 if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname)) 537 goto gotError; 538 if ((cptr = strchr(ifname, ':')) != NULL) 539 *cptr = '\0'; 540 541 /* 542 * If any of the interfaces found so far share the physical 543 * interface name then we have already processed the interface. 544 */ 545 for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) { 546 547 /* Retrieve physical interface name */ 548 (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname)); 549 550 /* Strip logical interface number before checking ifname */ 551 if ((cptr = strchr(cmpifname, ':')) != NULL) 552 *cptr = '\0'; 553 554 if (strcmp(cmpifname, ifname) == 0) 555 break; 556 } 557 if (ifi != NULL) 558 continue; /* already processed */ 559 560 /* 561 * New interface, find the one with the preferred source 562 * address for our use in Multicast DNS. 563 */ 564 if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr, 565 lifc.lifc_req, ifname, &best_lifr)) == NULL) 566 continue; 567 568 assert(best_lifr != NULL); 569 assert((best_lifr->lifr_addr.ss_family == AF_INET6) || 570 (best_lifr->lifr_addr.ss_family == AF_INET)); 571 572 switch (best_lifr->lifr_addr.ss_family) { 573 574 #if defined(AF_INET6) && HAVE_IPV6 575 case AF_INET6: 576 sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr; 577 ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6)); 578 if (ifi->ifi_addr == NULL) 579 goto gotError; 580 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); 581 582 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); 583 if (ifi->ifi_netmask == NULL) 584 goto gotError; 585 sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask); 586 sinptr6->sin6_family = AF_INET6; 587 plen_to_netmask(best_lifr->lifr_addrlen, 588 (unsigned char *) &(sinptr6->sin6_addr)); 589 break; 590 #endif 591 592 case AF_INET: 593 sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr; 594 ifi->ifi_addr = malloc(sizeof(struct sockaddr_in)); 595 if (ifi->ifi_addr == NULL) 596 goto gotError; 597 598 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 599 600 lifrcopy = *best_lifr; 601 if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) { 602 /* interface removed */ 603 if (errno == ENXIO) { 604 free(ifi->ifi_addr); 605 free(ifi); 606 continue; 607 } 608 goto gotError; 609 } 610 611 ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in)); 612 if (ifi->ifi_netmask == NULL) 613 goto gotError; 614 sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr; 615 sinptr->sin_family = AF_INET; 616 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); 617 break; 618 619 default: 620 /* never reached */ 621 break; 622 } 623 624 *ifipnext = ifi; /* prev points to this new one */ 625 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 626 } 627 628 (void) close(sockfd); 629 return(ifihead); /* pointer to first structure in linked list */ 630 631 gotError: 632 if (sockfd != -1) 633 (void) close(sockfd); 634 if (ifihead != NULL) 635 free_ifi_info(ifihead); 636 return(NULL); 637 } 638 639 #endif /* HAVE_SOLARIS */ 640 641 struct ifi_info *get_ifi_info(int family, int doaliases) 642 { 643 int junk; 644 struct ifi_info *ifi, *ifihead, **ifipnext; 645 int sockfd, sockf6, len, lastlen, flags, myflags; 646 #ifdef NOT_HAVE_IF_NAMETOINDEX 647 int index = 200; 648 #endif 649 char *ptr, *buf, lastname[IFNAMSIZ], *cptr; 650 struct ifconf ifc; 651 struct ifreq *ifr, ifrcopy; 652 struct sockaddr_in *sinptr; 653 654 #if defined(AF_INET6) && HAVE_IPV6 655 struct sockaddr_in6 *sinptr6; 656 #endif 657 658 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 659 if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); 660 #elif HAVE_SOLARIS 661 return get_ifi_info_solaris(family); 662 #endif 663 664 sockfd = -1; 665 sockf6 = -1; 666 buf = NULL; 667 ifihead = NULL; 668 669 sockfd = socket(AF_INET, SOCK_DGRAM, 0); 670 if (sockfd < 0) { 671 goto gotError; 672 } 673 674 lastlen = 0; 675 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 676 for ( ; ; ) { 677 buf = (char*)malloc(len); 678 if (buf == NULL) { 679 goto gotError; 680 } 681 ifc.ifc_len = len; 682 ifc.ifc_buf = buf; 683 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 684 if (errno != EINVAL || lastlen != 0) { 685 goto gotError; 686 } 687 } else { 688 if (ifc.ifc_len == lastlen) 689 break; /* success, len has not changed */ 690 lastlen = ifc.ifc_len; 691 } 692 len += 10 * sizeof(struct ifreq); /* increment */ 693 free(buf); 694 } 695 ifihead = NULL; 696 ifipnext = &ifihead; 697 lastname[0] = 0; 698 /* end get_ifi_info1 */ 699 700 /* include get_ifi_info2 */ 701 for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 702 ifr = (struct ifreq *) ptr; 703 704 /* Advance to next one in buffer */ 705 if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr)) 706 ptr += sizeof(struct ifreq); 707 else 708 ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr); 709 710 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family); 711 712 if (ifr->ifr_addr.sa_family != family) 713 continue; /* ignore if not desired address family */ 714 715 myflags = 0; 716 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 717 *cptr = 0; /* replace colon will null */ 718 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 719 if (doaliases == 0) 720 continue; /* already processed this interface */ 721 myflags = IFI_ALIAS; 722 } 723 memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 724 725 ifrcopy = *ifr; 726 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) { 727 goto gotError; 728 } 729 730 flags = ifrcopy.ifr_flags; 731 if ((flags & IFF_UP) == 0) 732 continue; /* ignore if interface not up */ 733 734 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 735 if (ifi == NULL) { 736 goto gotError; 737 } 738 *ifipnext = ifi; /* prev points to this new one */ 739 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 740 741 ifi->ifi_flags = flags; /* IFF_xxx values */ 742 ifi->ifi_myflags = myflags; /* IFI_xxx values */ 743 #ifndef NOT_HAVE_IF_NAMETOINDEX 744 ifi->ifi_index = if_nametoindex(ifr->ifr_name); 745 #else 746 ifrcopy = *ifr; 747 #ifdef SIOCGIFINDEX 748 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy)) 749 ifi->ifi_index = ifrcopy.ifr_index; 750 else 751 #endif 752 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */ 753 #endif 754 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 755 ifi->ifi_name[IFI_NAME-1] = '\0'; 756 /* end get_ifi_info2 */ 757 /* include get_ifi_info3 */ 758 switch (ifr->ifr_addr.sa_family) { 759 case AF_INET: 760 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 761 if (ifi->ifi_addr == NULL) { 762 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 763 if (ifi->ifi_addr == NULL) { 764 goto gotError; 765 } 766 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 767 768 #ifdef SIOCGIFNETMASK 769 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError; 770 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 771 if (ifi->ifi_netmask == NULL) goto gotError; 772 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; 773 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 774 #ifndef NOT_HAVE_SA_LEN 775 sinptr->sin_len = sizeof(struct sockaddr_in); 776 #endif 777 sinptr->sin_family = AF_INET; 778 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); 779 #endif 780 781 #ifdef SIOCGIFBRDADDR 782 if (flags & IFF_BROADCAST) { 783 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) { 784 goto gotError; 785 } 786 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 787 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 788 #ifndef NOT_HAVE_SA_LEN 789 sinptr->sin_len = sizeof( struct sockaddr_in ); 790 #endif 791 sinptr->sin_family = AF_INET; 792 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 793 if (ifi->ifi_brdaddr == NULL) { 794 goto gotError; 795 } 796 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); 797 } 798 #endif 799 800 #ifdef SIOCGIFDSTADDR 801 if (flags & IFF_POINTOPOINT) { 802 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) { 803 goto gotError; 804 } 805 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; 806 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 807 #ifndef NOT_HAVE_SA_LEN 808 sinptr->sin_len = sizeof( struct sockaddr_in ); 809 #endif 810 sinptr->sin_family = AF_INET; 811 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 812 if (ifi->ifi_dstaddr == NULL) { 813 goto gotError; 814 } 815 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); 816 } 817 #endif 818 } 819 break; 820 821 #if defined(AF_INET6) && HAVE_IPV6 822 case AF_INET6: 823 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; 824 if (ifi->ifi_addr == NULL) { 825 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 826 if (ifi->ifi_addr == NULL) { 827 goto gotError; 828 } 829 830 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */ 831 /* We need to strip that out */ 832 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr)) 833 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0; 834 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); 835 836 #ifdef SIOCGIFNETMASK_IN6 837 { 838 struct in6_ifreq ifr6; 839 if (sockf6 == -1) 840 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); 841 bzero(&ifr6, sizeof(ifr6)); 842 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); 843 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); 844 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError; 845 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); 846 if (ifi->ifi_netmask == NULL) goto gotError; 847 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; 848 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6)); 849 } 850 #endif 851 } 852 break; 853 #endif 854 855 default: 856 break; 857 } 858 } 859 goto done; 860 861 gotError: 862 if (ifihead != NULL) { 863 free_ifi_info(ifihead); 864 ifihead = NULL; 865 } 866 867 done: 868 if (buf != NULL) { 869 free(buf); 870 } 871 if (sockfd != -1) { 872 junk = close(sockfd); 873 assert(junk == 0); 874 } 875 if (sockf6 != -1) { 876 junk = close(sockf6); 877 assert(junk == 0); 878 } 879 return(ifihead); /* pointer to first structure in linked list */ 880 } 881 /* end get_ifi_info3 */ 882 883 /* include free_ifi_info */ 884 void 885 free_ifi_info(struct ifi_info *ifihead) 886 { 887 struct ifi_info *ifi, *ifinext; 888 889 for (ifi = ifihead; ifi != NULL; ifi = ifinext) { 890 if (ifi->ifi_addr != NULL) 891 free(ifi->ifi_addr); 892 if (ifi->ifi_brdaddr != NULL) 893 free(ifi->ifi_brdaddr); 894 if (ifi->ifi_dstaddr != NULL) 895 free(ifi->ifi_dstaddr); 896 if (ifi->ifi_netmask != NULL) 897 free(ifi->ifi_netmask); 898 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ 899 free(ifi); /* the ifi_info{} itself */ 900 } 901 } 902 /* end free_ifi_info */ 903 904 ssize_t 905 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 906 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl) 907 { 908 struct msghdr msg; 909 struct iovec iov[1]; 910 ssize_t n; 911 912 #ifdef CMSG_FIRSTHDR 913 struct cmsghdr *cmptr; 914 union { 915 struct cmsghdr cm; 916 char control[1024]; 917 pad64_t align8; /* ensure structure is 8-byte aligned on sparc */ 918 } control_un; 919 920 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 921 922 msg.msg_control = (void *) control_un.control; 923 msg.msg_controllen = sizeof(control_un.control); 924 msg.msg_flags = 0; 925 #else 926 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 927 #endif /* CMSG_FIRSTHDR */ 928 929 msg.msg_name = (char *) sa; 930 msg.msg_namelen = *salenptr; 931 iov[0].iov_base = (char *)ptr; 932 iov[0].iov_len = nbytes; 933 msg.msg_iov = iov; 934 msg.msg_iovlen = 1; 935 936 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 937 return(n); 938 939 *salenptr = msg.msg_namelen; /* pass back results */ 940 if (pktp) { 941 /* 0.0.0.0, i/f = -1 */ 942 /* We set the interface to -1 so that the caller can 943 tell whether we returned a meaningful value or 944 just some default. Previously this code just 945 set the value to 0, but I'm concerned that 0 946 might be a valid interface value. 947 */ 948 memset(pktp, 0, sizeof(struct my_in_pktinfo)); 949 pktp->ipi_ifindex = -1; 950 } 951 /* end recvfrom_flags1 */ 952 953 /* include recvfrom_flags2 */ 954 #ifndef CMSG_FIRSTHDR 955 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 956 *flagsp = 0; /* pass back results */ 957 return(n); 958 #else 959 960 *flagsp = msg.msg_flags; /* pass back results */ 961 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 962 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 963 return(n); 964 965 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 966 cmptr = CMSG_NXTHDR(&msg, cmptr)) { 967 968 #ifdef IP_PKTINFO 969 #if in_pktinfo_definition_is_missing 970 struct in_pktinfo 971 { 972 int ipi_ifindex; 973 struct in_addr ipi_spec_dst; 974 struct in_addr ipi_addr; 975 }; 976 #endif 977 if (cmptr->cmsg_level == IPPROTO_IP && 978 cmptr->cmsg_type == IP_PKTINFO) { 979 struct in_pktinfo *tmp; 980 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 981 982 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 983 sin->sin_family = AF_INET; 984 sin->sin_addr = tmp->ipi_addr; 985 sin->sin_port = 0; 986 pktp->ipi_ifindex = tmp->ipi_ifindex; 987 continue; 988 } 989 #endif 990 991 #ifdef IP_RECVDSTADDR 992 if (cmptr->cmsg_level == IPPROTO_IP && 993 cmptr->cmsg_type == IP_RECVDSTADDR) { 994 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 995 996 sin->sin_family = AF_INET; 997 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 998 sin->sin_port = 0; 999 continue; 1000 } 1001 #endif 1002 1003 #ifdef IP_RECVIF 1004 if (cmptr->cmsg_level == IPPROTO_IP && 1005 cmptr->cmsg_type == IP_RECVIF) { 1006 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 1007 #ifndef HAVE_BROKEN_RECVIF_NAME 1008 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 1009 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 1010 #endif 1011 (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t)); 1012 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 1013 // null terminated because of memset above 1014 continue; 1015 } 1016 #endif 1017 1018 #ifdef IP_RECVTTL 1019 if (cmptr->cmsg_level == IPPROTO_IP && 1020 cmptr->cmsg_type == IP_RECVTTL) { 1021 *ttl = *(u_char*)CMSG_DATA(cmptr); 1022 continue; 1023 } 1024 else if (cmptr->cmsg_level == IPPROTO_IP && 1025 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 1026 *ttl = *(int*)CMSG_DATA(cmptr); 1027 continue; 1028 } 1029 #endif 1030 1031 #if defined(IPV6_PKTINFO) && HAVE_IPV6 1032 if (cmptr->cmsg_level == IPPROTO_IPV6 && 1033 cmptr->cmsg_type == IPV6_PKTINFO) { 1034 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 1035 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 1036 1037 sin6->sin6_family = AF_INET6; 1038 #ifndef NOT_HAVE_SA_LEN 1039 sin6->sin6_len = sizeof(*sin6); 1040 #endif 1041 sin6->sin6_addr = ip6_info->ipi6_addr; 1042 sin6->sin6_flowinfo = 0; 1043 sin6->sin6_scope_id = 0; 1044 sin6->sin6_port = 0; 1045 pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 1046 continue; 1047 } 1048 #endif 1049 1050 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 1051 if (cmptr->cmsg_level == IPPROTO_IPV6 && 1052 cmptr->cmsg_type == IPV6_HOPLIMIT) { 1053 *ttl = *(int*)CMSG_DATA(cmptr); 1054 continue; 1055 } 1056 #endif 1057 assert(0); // unknown ancillary data 1058 } 1059 return(n); 1060 #endif /* CMSG_FIRSTHDR */ 1061 } 1062 1063 // ********************************************************************************************** 1064 1065 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4. 1066 // Returns 0 on success, -1 on failure. 1067 1068 #ifdef NOT_HAVE_DAEMON 1069 #include <fcntl.h> 1070 #include <sys/stat.h> 1071 #include <signal.h> 1072 1073 int daemon(int nochdir, int noclose) 1074 { 1075 switch (fork()) 1076 { 1077 case -1: return (-1); // Fork failed 1078 case 0: break; // Child -- continue 1079 default: _exit(0); // Parent -- exit 1080 } 1081 1082 if (setsid() == -1) return(-1); 1083 1084 signal(SIGHUP, SIG_IGN); 1085 1086 switch (fork()) // Fork again, primarily for reasons of Unix trivia 1087 { 1088 case -1: return (-1); // Fork failed 1089 case 0: break; // Child -- continue 1090 default: _exit(0); // Parent -- exit 1091 } 1092 1093 if (!nochdir) (void)chdir("/"); 1094 umask(0); 1095 1096 if (!noclose) 1097 { 1098 int fd = open("/dev/null", O_RDWR, 0); 1099 if (fd != -1) 1100 { 1101 // Avoid unnecessarily duplicating a file descriptor to itself 1102 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO); 1103 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO); 1104 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO); 1105 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 1106 (void)close (fd); 1107 } 1108 } 1109 return (0); 1110 } 1111 #endif /* NOT_HAVE_DAEMON */ 1112