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