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