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 defined(__FreeBSD__) || defined(__DragonFly__) 59 #include <net/if_var.h> 60 #endif 61 #include <netinet/in_var.h> 62 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us 63 #endif 64 65 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 66 #include <netdb.h> 67 #include <arpa/inet.h> 68 69 /* Converts a prefix length to IPv6 network mask */ 70 void plen_to_mask(int plen, char *addr) { 71 int i; 72 int colons=7; /* Number of colons in IPv6 address */ 73 int bits_in_block=16; /* Bits per IPv6 block */ 74 for(i=0; i<=colons; i++) { 75 int block, ones=0xffff, ones_in_block; 76 if (plen>bits_in_block) ones_in_block=bits_in_block; 77 else ones_in_block=plen; 78 block = ones & (ones << (bits_in_block-ones_in_block)); 79 i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block); 80 plen -= ones_in_block; 81 } 82 } 83 84 /* Gets IPv6 interface information from the /proc filesystem in linux*/ 85 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 86 { 87 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; 88 FILE *fp = NULL; 89 char addr[8][5]; 90 int flags, myflags, index, plen, scope; 91 char ifname[9], lastname[IFNAMSIZ]; 92 char addr6[32+7+1]; /* don't forget the seven ':' */ 93 struct addrinfo hints, *res0; 94 int err; 95 int sockfd = -1; 96 struct ifreq ifr; 97 98 res0=NULL; 99 ifihead = NULL; 100 ifipnext = &ifihead; 101 lastname[0] = 0; 102 103 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { 104 sockfd = socket(AF_INET6, SOCK_DGRAM, 0); 105 if (sockfd < 0) { 106 goto gotError; 107 } 108 while (fscanf(fp, 109 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", 110 addr[0],addr[1],addr[2],addr[3], 111 addr[4],addr[5],addr[6],addr[7], 112 &index, &plen, &scope, &flags, ifname) != EOF) { 113 114 myflags = 0; 115 if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { 116 if (doaliases == 0) 117 continue; /* already processed this interface */ 118 myflags = IFI_ALIAS; 119 } 120 memcpy(lastname, ifname, IFNAMSIZ); 121 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 122 if (ifi == NULL) { 123 goto gotError; 124 } 125 126 ifipold = *ifipnext; /* need this later */ 127 ifiptr = ifipnext; 128 *ifipnext = ifi; /* prev points to this new one */ 129 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 130 131 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", 132 addr[0],addr[1],addr[2],addr[3], 133 addr[4],addr[5],addr[6],addr[7]); 134 135 /* Add address of the interface */ 136 memset(&hints, 0, sizeof(hints)); 137 hints.ai_family = AF_INET6; 138 hints.ai_flags = AI_NUMERICHOST; 139 err = getaddrinfo(addr6, NULL, &hints, &res0); 140 if (err) { 141 goto gotError; 142 } 143 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 144 if (ifi->ifi_addr == NULL) { 145 goto gotError; 146 } 147 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6)); 148 149 /* Add netmask of the interface */ 150 char ipv6addr[INET6_ADDRSTRLEN]; 151 plen_to_mask(plen, ipv6addr); 152 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); 153 if (ifi->ifi_netmask == NULL) { 154 goto gotError; 155 } 156 157 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family; 158 ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope; 159 inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr); 160 161 /* Add interface name */ 162 memcpy(ifi->ifi_name, ifname, IFI_NAME); 163 164 /* Add interface index */ 165 ifi->ifi_index = index; 166 167 /* Add interface flags*/ 168 memcpy(ifr.ifr_name, ifname, IFNAMSIZ); 169 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 170 if (errno == EADDRNOTAVAIL) { 171 /* 172 * If the main interface is configured with no IP address but 173 * an alias interface exists with an IP address, you get 174 * EADDRNOTAVAIL for the main interface 175 */ 176 free(ifi->ifi_addr); 177 free(ifi->ifi_netmask); 178 free(ifi); 179 ifipnext = ifiptr; 180 *ifipnext = ifipold; 181 continue; 182 } else { 183 goto gotError; 184 } 185 } 186 ifi->ifi_flags = ifr.ifr_flags; 187 freeaddrinfo(res0); 188 res0=NULL; 189 } 190 } 191 goto done; 192 193 gotError: 194 if (ifihead != NULL) { 195 free_ifi_info(ifihead); 196 ifihead = NULL; 197 } 198 if (res0 != NULL) { 199 freeaddrinfo(res0); 200 res0=NULL; 201 } 202 done: 203 if (sockfd != -1) { 204 int rv; 205 rv = close(sockfd); 206 assert(rv == 0); 207 } 208 if (fp != NULL) { 209 fclose(fp); 210 } 211 return(ifihead); /* pointer to first structure in linked list */ 212 } 213 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 214 215 struct ifi_info *get_ifi_info(int family, int doaliases) 216 { 217 int junk; 218 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; 219 int sockfd, sockf6, len, lastlen, flags, myflags; 220 #ifdef NOT_HAVE_IF_NAMETOINDEX 221 int index = 200; 222 #endif 223 char *ptr, *buf, lastname[IFNAMSIZ], *cptr; 224 struct ifconf ifc; 225 struct ifreq *ifr, ifrcopy; 226 struct sockaddr_in *sinptr; 227 228 #if defined(AF_INET6) && HAVE_IPV6 229 struct sockaddr_in6 *sinptr6; 230 #endif 231 232 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 233 if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); 234 #endif 235 236 sockfd = -1; 237 sockf6 = -1; 238 buf = NULL; 239 ifihead = NULL; 240 241 sockfd = socket(AF_INET, SOCK_DGRAM, 0); 242 if (sockfd < 0) { 243 goto gotError; 244 } 245 246 lastlen = 0; 247 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 248 for ( ; ; ) { 249 buf = (char*)malloc(len); 250 if (buf == NULL) { 251 goto gotError; 252 } 253 ifc.ifc_len = len; 254 ifc.ifc_buf = buf; 255 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 256 if (errno != EINVAL || lastlen != 0) { 257 goto gotError; 258 } 259 } else { 260 if (ifc.ifc_len == lastlen) 261 break; /* success, len has not changed */ 262 lastlen = ifc.ifc_len; 263 } 264 len += 10 * sizeof(struct ifreq); /* increment */ 265 free(buf); 266 } 267 ifihead = NULL; 268 ifipnext = &ifihead; 269 lastname[0] = 0; 270 /* end get_ifi_info1 */ 271 272 /* include get_ifi_info2 */ 273 for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 274 ifr = (struct ifreq *) ptr; 275 276 /* Advance to next one in buffer */ 277 if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr)) 278 ptr += sizeof(struct ifreq); 279 else 280 ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr); 281 282 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family); 283 284 if (ifr->ifr_addr.sa_family != family) 285 continue; /* ignore if not desired address family */ 286 287 myflags = 0; 288 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 289 *cptr = 0; /* replace colon will null */ 290 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 291 if (doaliases == 0) 292 continue; /* already processed this interface */ 293 myflags = IFI_ALIAS; 294 } 295 memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 296 297 ifrcopy = *ifr; 298 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) { 299 goto gotError; 300 } 301 302 flags = ifrcopy.ifr_flags; 303 if ((flags & IFF_UP) == 0) 304 continue; /* ignore if interface not up */ 305 306 307 #ifdef notdef 308 /* 309 * Include the loopback so that we return at least one 310 * address, so that mdnsd does not exit before we get 311 * a dhcp address 312 */ 313 if ((flags & IFF_LOOPBACK)) 314 continue; /* ignore loopback interfaces */ 315 #endif 316 317 /* Skip addresses we can't use */ 318 #ifdef SIOCGIFAFLAG_IN 319 if (ifr->ifr_addr.sa_family == AF_INET) { 320 ifrcopy = *ifr; 321 if (ioctl(sockfd, SIOCGIFAFLAG_IN, &ifrcopy) < 0) 322 goto gotError; 323 if (ifrcopy.ifr_addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) 324 continue; 325 } 326 #endif 327 #ifdef SIOCGIFAFLAG_IN6 328 if (ifr->ifr_addr.sa_family == AF_INET6) { 329 struct in6_ifreq ifr6; 330 331 if (sockf6 == -1) 332 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); 333 memset(&ifr6, 0, sizeof(ifr6)); 334 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name)); 335 memcpy(&ifr6.ifr_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_addr)); 336 if (ioctl(sockf6, SIOCGIFAFLAG_IN6, &ifr6) < 0) 337 goto gotError; 338 if (ifr6.ifr_ifru.ifru_flags6 & 339 (IN6_IFF_NOTREADY | IN6_IFF_DETACHED)) 340 continue; 341 } 342 #endif 343 344 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 345 if (ifi == NULL) { 346 goto gotError; 347 } 348 ifipold = *ifipnext; /* need this later */ 349 ifiptr = ifipnext; 350 *ifipnext = ifi; /* prev points to this new one */ 351 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 352 353 ifi->ifi_flags = flags; /* IFF_xxx values */ 354 ifi->ifi_myflags = myflags; /* IFI_xxx values */ 355 #ifndef NOT_HAVE_IF_NAMETOINDEX 356 ifi->ifi_index = if_nametoindex(ifr->ifr_name); 357 #else 358 ifrcopy = *ifr; 359 #ifdef SIOCGIFINDEX 360 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy)) 361 ifi->ifi_index = ifrcopy.ifr_index; 362 else 363 #endif 364 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */ 365 #endif 366 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 367 ifi->ifi_name[IFI_NAME-1] = '\0'; 368 /* end get_ifi_info2 */ 369 /* include get_ifi_info3 */ 370 switch (ifr->ifr_addr.sa_family) { 371 case AF_INET: 372 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 373 if (ifi->ifi_addr == NULL) { 374 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 375 if (ifi->ifi_addr == NULL) { 376 goto gotError; 377 } 378 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 379 380 #ifdef SIOCGIFNETMASK 381 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) { 382 if (errno == EADDRNOTAVAIL) { 383 /* 384 * If the main interface is configured with no IP address but 385 * an alias interface exists with an IP address, you get 386 * EADDRNOTAVAIL for the main interface 387 */ 388 free(ifi->ifi_addr); 389 free(ifi); 390 ifipnext = ifiptr; 391 *ifipnext = ifipold; 392 continue; 393 } else { 394 goto gotError; 395 } 396 } 397 398 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 399 if (ifi->ifi_netmask == NULL) goto gotError; 400 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; 401 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 402 #ifndef NOT_HAVE_SA_LEN 403 sinptr->sin_len = sizeof(struct sockaddr_in); 404 #endif 405 sinptr->sin_family = AF_INET; 406 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); 407 #endif 408 409 #ifdef SIOCGIFBRDADDR 410 if (flags & IFF_BROADCAST) { 411 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) { 412 goto gotError; 413 } 414 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 415 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 416 #ifndef NOT_HAVE_SA_LEN 417 sinptr->sin_len = sizeof( struct sockaddr_in ); 418 #endif 419 sinptr->sin_family = AF_INET; 420 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 421 if (ifi->ifi_brdaddr == NULL) { 422 goto gotError; 423 } 424 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); 425 } 426 #endif 427 428 #ifdef SIOCGIFDSTADDR 429 if (flags & IFF_POINTOPOINT) { 430 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) { 431 goto gotError; 432 } 433 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; 434 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 435 #ifndef NOT_HAVE_SA_LEN 436 sinptr->sin_len = sizeof( struct sockaddr_in ); 437 #endif 438 sinptr->sin_family = AF_INET; 439 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 440 if (ifi->ifi_dstaddr == NULL) { 441 goto gotError; 442 } 443 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); 444 } 445 #endif 446 } 447 break; 448 449 #if defined(AF_INET6) && HAVE_IPV6 450 case AF_INET6: 451 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; 452 if (ifi->ifi_addr == NULL) { 453 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 454 if (ifi->ifi_addr == NULL) { 455 goto gotError; 456 } 457 458 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */ 459 /* We need to strip that out */ 460 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr)) 461 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0; 462 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); 463 464 #ifdef SIOCGIFNETMASK_IN6 465 { 466 struct in6_ifreq ifr6; 467 if (sockf6 == -1) 468 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); 469 memset(&ifr6, 0, sizeof(ifr6)); 470 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); 471 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); 472 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) { 473 if (errno == EADDRNOTAVAIL) { 474 /* 475 * If the main interface is configured with no IP address but 476 * an alias interface exists with an IP address, you get 477 * EADDRNOTAVAIL for the main interface 478 */ 479 free(ifi->ifi_addr); 480 free(ifi); 481 ifipnext = ifiptr; 482 *ifipnext = ifipold; 483 continue; 484 } else { 485 goto gotError; 486 } 487 } 488 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); 489 if (ifi->ifi_netmask == NULL) goto gotError; 490 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; 491 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6)); 492 } 493 #endif 494 } 495 break; 496 #endif 497 498 default: 499 break; 500 } 501 } 502 goto done; 503 504 gotError: 505 if (ifihead != NULL) { 506 free_ifi_info(ifihead); 507 ifihead = NULL; 508 } 509 510 done: 511 if (buf != NULL) { 512 free(buf); 513 } 514 if (sockfd != -1) { 515 junk = close(sockfd); 516 assert(junk == 0); 517 } 518 if (sockf6 != -1) { 519 junk = close(sockf6); 520 assert(junk == 0); 521 } 522 return(ifihead); /* pointer to first structure in linked list */ 523 } 524 /* end get_ifi_info3 */ 525 526 /* include free_ifi_info */ 527 void 528 free_ifi_info(struct ifi_info *ifihead) 529 { 530 struct ifi_info *ifi, *ifinext; 531 532 for (ifi = ifihead; ifi != NULL; ifi = ifinext) { 533 if (ifi->ifi_addr != NULL) 534 free(ifi->ifi_addr); 535 if (ifi->ifi_netmask != NULL) 536 free(ifi->ifi_netmask); 537 if (ifi->ifi_brdaddr != NULL) 538 free(ifi->ifi_brdaddr); 539 if (ifi->ifi_dstaddr != NULL) 540 free(ifi->ifi_dstaddr); 541 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ 542 free(ifi); /* the ifi_info{} itself */ 543 } 544 } 545 /* end free_ifi_info */ 546 547 ssize_t 548 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 549 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl) 550 { 551 struct msghdr msg; 552 struct iovec iov[1]; 553 ssize_t n; 554 555 #ifdef CMSG_FIRSTHDR 556 struct cmsghdr *cmptr; 557 union { 558 struct cmsghdr cm; 559 char control[1024]; 560 } control_un; 561 562 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 563 564 msg.msg_control = control_un.control; 565 msg.msg_controllen = sizeof(control_un.control); 566 msg.msg_flags = 0; 567 #else 568 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 569 #endif /* CMSG_FIRSTHDR */ 570 571 msg.msg_name = (char *) sa; 572 msg.msg_namelen = *salenptr; 573 iov[0].iov_base = (char *)ptr; 574 iov[0].iov_len = nbytes; 575 msg.msg_iov = iov; 576 msg.msg_iovlen = 1; 577 578 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 579 return(n); 580 581 *salenptr = msg.msg_namelen; /* pass back results */ 582 if (pktp) { 583 /* 0.0.0.0, i/f = -1 */ 584 /* We set the interface to -1 so that the caller can 585 tell whether we returned a meaningful value or 586 just some default. Previously this code just 587 set the value to 0, but I'm concerned that 0 588 might be a valid interface value. 589 */ 590 memset(pktp, 0, sizeof(struct my_in_pktinfo)); 591 pktp->ipi_ifindex = -1; 592 } 593 /* end recvfrom_flags1 */ 594 595 /* include recvfrom_flags2 */ 596 #ifndef CMSG_FIRSTHDR 597 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 598 *flagsp = 0; /* pass back results */ 599 return(n); 600 #else 601 602 *flagsp = msg.msg_flags; /* pass back results */ 603 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 604 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 605 return(n); 606 607 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 608 cmptr = CMSG_NXTHDR(&msg, cmptr)) { 609 610 #ifdef IP_PKTINFO 611 #if in_pktinfo_definition_is_missing 612 struct in_pktinfo 613 { 614 int ipi_ifindex; 615 struct in_addr ipi_spec_dst; 616 struct in_addr ipi_addr; 617 }; 618 #endif 619 if (cmptr->cmsg_level == IPPROTO_IP && 620 cmptr->cmsg_type == IP_PKTINFO) { 621 struct in_pktinfo *tmp; 622 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 623 624 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 625 sin->sin_family = AF_INET; 626 sin->sin_addr = tmp->ipi_addr; 627 sin->sin_port = 0; 628 pktp->ipi_ifindex = tmp->ipi_ifindex; 629 continue; 630 } 631 #endif 632 633 #ifdef IP_RECVDSTADDR 634 if (cmptr->cmsg_level == IPPROTO_IP && 635 cmptr->cmsg_type == IP_RECVDSTADDR) { 636 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 637 638 sin->sin_family = AF_INET; 639 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 640 sin->sin_port = 0; 641 continue; 642 } 643 #endif 644 645 #ifdef IP_RECVIF 646 if (cmptr->cmsg_level == IPPROTO_IP && 647 cmptr->cmsg_type == IP_RECVIF) { 648 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 649 #ifndef HAVE_BROKEN_RECVIF_NAME 650 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 651 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 652 #endif 653 pktp->ipi_ifindex = sdl->sdl_index; 654 #ifdef HAVE_BROKEN_RECVIF_NAME 655 if (sdl->sdl_index == 0) { 656 pktp->ipi_ifindex = *(uint_t*)sdl; 657 } 658 #endif 659 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 660 // null terminated because of memset above 661 continue; 662 } 663 #endif 664 665 #ifdef IP_RECVTTL 666 if (cmptr->cmsg_level == IPPROTO_IP && 667 cmptr->cmsg_type == IP_RECVTTL) { 668 *ttl = *(u_char*)CMSG_DATA(cmptr); 669 continue; 670 } 671 else if (cmptr->cmsg_level == IPPROTO_IP && 672 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 673 *ttl = *(int*)CMSG_DATA(cmptr); 674 continue; 675 } 676 #endif 677 678 #if defined(IPV6_PKTINFO) && HAVE_IPV6 679 if (cmptr->cmsg_level == IPPROTO_IPV6 && 680 cmptr->cmsg_type == IPV6_2292_PKTINFO) { 681 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 682 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 683 684 sin6->sin6_family = AF_INET6; 685 #ifndef NOT_HAVE_SA_LEN 686 sin6->sin6_len = sizeof(*sin6); 687 #endif 688 sin6->sin6_addr = ip6_info->ipi6_addr; 689 sin6->sin6_flowinfo = 0; 690 sin6->sin6_scope_id = 0; 691 sin6->sin6_port = 0; 692 pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 693 continue; 694 } 695 #endif 696 697 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 698 if (cmptr->cmsg_level == IPPROTO_IPV6 && 699 cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { 700 *ttl = *(int*)CMSG_DATA(cmptr); 701 continue; 702 } 703 #endif 704 assert(0); // unknown ancillary data 705 } 706 return(n); 707 #endif /* CMSG_FIRSTHDR */ 708 } 709 710 // ********************************************************************************************** 711 712 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4. 713 // Returns 0 on success, -1 on failure. 714 715 #ifdef NOT_HAVE_DAEMON 716 #include <fcntl.h> 717 #include <sys/stat.h> 718 #include <sys/signal.h> 719 720 int daemon(int nochdir, int noclose) 721 { 722 switch (fork()) 723 { 724 case -1: return (-1); // Fork failed 725 case 0: break; // Child -- continue 726 default: _exit(0); // Parent -- exit 727 } 728 729 if (setsid() == -1) return(-1); 730 731 signal(SIGHUP, SIG_IGN); 732 733 switch (fork()) // Fork again, primarily for reasons of Unix trivia 734 { 735 case -1: return (-1); // Fork failed 736 case 0: break; // Child -- continue 737 default: _exit(0); // Parent -- exit 738 } 739 740 if (!nochdir) (void)chdir("/"); 741 umask(0); 742 743 if (!noclose) 744 { 745 int fd = open("/dev/null", O_RDWR, 0); 746 if (fd != -1) 747 { 748 // Avoid unnecessarily duplicating a file descriptor to itself 749 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO); 750 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO); 751 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO); 752 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 753 (void)close (fd); 754 } 755 } 756 return (0); 757 } 758 #endif /* NOT_HAVE_DAEMON */ 759