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