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