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