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 Change History (most recent first): 18 19 Log: mDNSUNP.c,v $ 20 Revision 1.40 2009/01/13 05:31:34 mkrochma 21 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy 22 23 Revision 1.39 2009/01/11 03:20:06 mkrochma 24 <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris 25 26 Revision 1.38 2009/01/10 22:54:42 mkrochma 27 <rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux 28 29 Revision 1.37 2008/10/23 22:33:24 cheshire 30 Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu 31 32 Revision 1.36 2008/04/21 18:21:22 mkrochma 33 <rdar://problem/5877307> Need to free ifi_netmask 34 Submitted by Igor Seleznev 35 36 Revision 1.35 2007/11/15 21:36:19 cheshire 37 <rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6() 38 39 Revision 1.34 2006/08/14 23:24:47 cheshire 40 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 41 42 Revision 1.33 2006/03/13 23:14:21 cheshire 43 <rdar://problem/4427969> Compile problems on FreeBSD 44 Use <netinet/in_var.h> instead of <netinet6/in6_var.h> 45 46 Revision 1.32 2005/12/21 02:56:43 cheshire 47 <rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined 48 49 Revision 1.31 2005/12/21 02:46:05 cheshire 50 <rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite 51 52 Revision 1.30 2005/11/29 20:03:02 mkrochma 53 Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN 54 55 Revision 1.29 2005/11/12 02:23:10 cheshire 56 <rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR 57 58 Revision 1.28 2005/10/31 22:09:45 cheshire 59 Buffer "char addr6[33]" was seven bytes too small 60 61 Revision 1.27 2005/06/29 15:54:21 cheshire 62 <rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD 63 Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS 64 65 Revision 1.26 2005/04/08 21:43:59 ksekar 66 <rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture 67 Submitted by Andrew de Quincey 68 69 Revision 1.25 2005/04/08 21:37:57 ksekar 70 <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux 71 72 Revision 1.24 2005/04/08 21:30:16 ksekar 73 <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9 74 Patch submitted by Bernd Kuhls 75 76 Revision 1.23 2004/12/01 04:25:05 cheshire 77 <rdar://problem/3872803> Darwin patches for Solaris and Suse 78 Provide daemon() for platforms that don't have it 79 80 Revision 1.22 2004/11/30 22:37:01 cheshire 81 Update copyright dates and add "Mode: C; tab-width: 4" headers 82 83 Revision 1.21 2004/11/08 22:13:59 rpantos 84 Create sockf6 lazily when v6 interface found. 85 86 Revision 1.20 2004/10/16 00:17:01 cheshire 87 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check 88 89 Revision 1.19 2004/07/20 01:47:36 rpantos 90 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr. 91 92 Revision 1.18 2004/07/08 21:30:21 rpantos 93 94 Revision 1.17 2004/06/25 00:26:27 rpantos 95 Changes to fix the Posix build on Solaris. 96 97 Revision 1.16 2004/03/20 05:37:09 cheshire 98 Fix contributed by Terry Lambert & Alfred Perlstein: 99 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x 100 101 Revision 1.15 2004/02/14 01:09:45 rpantos 102 Just use HAVE_IPV6 rather than defined(HAVE_IPV6). 103 104 Revision 1.14 2003/12/11 18:53:40 cheshire 105 Fix compiler warning reported by Paul Guyot 106 107 Revision 1.13 2003/12/08 20:47:02 rpantos 108 Add support for mDNSResponder on Linux. 109 110 Revision 1.12 2003/09/02 20:47:13 cheshire 111 Fix signed/unsigned warning 112 113 Revision 1.11 2003/08/12 19:56:26 cheshire 114 Update to APSL 2.0 115 116 Revision 1.10 2003/08/06 18:20:51 cheshire 117 Makefile cleanup 118 119 Revision 1.9 2003/07/14 18:11:54 cheshire 120 Fix stricter compiler warnings 121 122 Revision 1.8 2003/07/02 21:19:59 cheshire 123 <rdar://problem/3313413> Update copyright notices, etc., in source code comments 124 125 Revision 1.7 2003/03/20 21:10:31 cheshire 126 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris 127 128 Revision 1.6 2003/03/13 03:46:21 cheshire 129 Fixes to make the code build on Linux 130 131 Revision 1.5 2003/02/07 03:02:02 cheshire 132 Submitted by: Mitsutaka Watanabe 133 The code saying "index += 1;" was effectively making up random interface index values. 134 The right way to find the correct interface index is if_nametoindex(); 135 136 Revision 1.4 2002/12/23 22:13:31 jgraessl 137 138 Reviewed by: Stuart Cheshire 139 Initial IPv6 support for mDNSResponder. 140 141 Revision 1.3 2002/09/21 20:44:53 zarzycki 142 Added APSL info 143 144 Revision 1.2 2002/09/19 04:20:44 cheshire 145 Remove high-ascii characters that confuse some systems 146 147 Revision 1.1 2002/09/17 06:24:34 cheshire 148 First checkin 149 150 */ 151 152 #include "mDNSUNP.h" 153 154 #include <errno.h> 155 #include <assert.h> 156 #include <string.h> 157 #include <stdlib.h> 158 #include <sys/uio.h> 159 #include <sys/ioctl.h> 160 #include <signal.h> 161 #include <unistd.h> 162 #include <stdio.h> 163 164 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P) 165 macro, usually defined in <sys/param.h> or someplace like that, to make sure the 166 CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO 167 should be set to the name of the header to include to get the ALIGN(P) macro. 168 */ 169 #ifdef NEED_ALIGN_MACRO 170 #include NEED_ALIGN_MACRO 171 #endif 172 173 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but 174 other platforms don't even have that include file. So, 175 if we haven't yet got a definition, let's try to find 176 <sys/sockio.h>. 177 */ 178 179 #ifndef SIOCGIFCONF 180 #include <sys/sockio.h> 181 #endif 182 183 /* sockaddr_dl is only referenced if we're using IP_RECVIF, 184 so only include the header in that case. 185 */ 186 187 #ifdef IP_RECVIF 188 #include <net/if_dl.h> 189 #endif 190 191 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX && !defined(sun) 192 #if defined(__FreeBSD__) || defined(__DragonFly__) 193 #include <net/if_var.h> 194 #endif 195 #include <netinet/in_var.h> 196 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us 197 #endif 198 199 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 200 #include <netdb.h> 201 #include <arpa/inet.h> 202 203 /* Converts a prefix length to IPv6 network mask */ 204 void plen_to_mask(int plen, char *addr) { 205 int i; 206 int colons=7; /* Number of colons in IPv6 address */ 207 int bits_in_block=16; /* Bits per IPv6 block */ 208 for(i=0;i<=colons;i++) { 209 int block, ones=0xffff, ones_in_block; 210 if(plen>bits_in_block) ones_in_block=bits_in_block; 211 else ones_in_block=plen; 212 block = ones & (ones << (bits_in_block-ones_in_block)); 213 i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block); 214 plen -= ones_in_block; 215 } 216 } 217 218 /* Gets IPv6 interface information from the /proc filesystem in linux*/ 219 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 220 { 221 struct ifi_info *ifi, *ifihead, **ifipnext; 222 FILE *fp; 223 char addr[8][5]; 224 int flags, myflags, index, plen, scope; 225 char ifname[9], lastname[IFNAMSIZ]; 226 char addr6[32+7+1]; /* don't forget the seven ':' */ 227 struct addrinfo hints, *res0; 228 struct sockaddr_in6 *sin6; 229 struct in6_addr *addrptr; 230 int err; 231 232 res0=NULL; 233 ifihead = NULL; 234 ifipnext = &ifihead; 235 lastname[0] = 0; 236 237 if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { 238 while (fscanf(fp, 239 "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", 240 addr[0],addr[1],addr[2],addr[3], 241 addr[4],addr[5],addr[6],addr[7], 242 &index, &plen, &scope, &flags, ifname) != EOF) { 243 244 myflags = 0; 245 if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { 246 if (doaliases == 0) 247 continue; /* already processed this interface */ 248 myflags = IFI_ALIAS; 249 } 250 memcpy(lastname, ifname, IFNAMSIZ); 251 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 252 if (ifi == NULL) { 253 goto gotError; 254 } 255 256 *ifipnext = ifi; /* prev points to this new one */ 257 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 258 259 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", 260 addr[0],addr[1],addr[2],addr[3], 261 addr[4],addr[5],addr[6],addr[7]); 262 263 /* Add address of the interface */ 264 memset(&hints, 0, sizeof(hints)); 265 hints.ai_family = AF_INET6; 266 hints.ai_flags = AI_NUMERICHOST; 267 err = getaddrinfo(addr6, NULL, &hints, &res0); 268 if (err) { 269 goto gotError; 270 } 271 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 272 if (ifi->ifi_addr == NULL) { 273 goto gotError; 274 } 275 memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6)); 276 277 /* Add netmask of the interface */ 278 char ipv6addr[INET6_ADDRSTRLEN]; 279 plen_to_mask(plen, ipv6addr); 280 ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); 281 if (ifi->ifi_addr == NULL) { 282 goto gotError; 283 } 284 sin6=calloc(1, sizeof(struct sockaddr_in6)); 285 addrptr=calloc(1, sizeof(struct in6_addr)); 286 inet_pton(family, ipv6addr, addrptr); 287 sin6->sin6_family=family; 288 sin6->sin6_addr=*addrptr; 289 sin6->sin6_scope_id=scope; 290 memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6)); 291 free(sin6); 292 293 294 /* Add interface name */ 295 memcpy(ifi->ifi_name, ifname, IFI_NAME); 296 297 /* Add interface index */ 298 ifi->ifi_index = index; 299 300 /* If interface is in /proc then it is up*/ 301 ifi->ifi_flags = IFF_UP; 302 303 freeaddrinfo(res0); 304 res0=NULL; 305 } 306 } 307 goto done; 308 309 gotError: 310 if (ifihead != NULL) { 311 free_ifi_info(ifihead); 312 ifihead = NULL; 313 } 314 if (res0 != NULL) { 315 freeaddrinfo(res0); 316 res0=NULL; 317 } 318 done: 319 return(ifihead); /* pointer to first structure in linked list */ 320 } 321 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 322 323 struct ifi_info *get_ifi_info(int family, int doaliases) 324 { 325 int junk; 326 struct ifi_info *ifi, *ifihead, **ifipnext; 327 int sockfd, sockf6, len, lastlen, flags, myflags; 328 #ifdef NOT_HAVE_IF_NAMETOINDEX 329 int index = 200; 330 #endif 331 char *ptr, *buf, lastname[IFNAMSIZ], *cptr; 332 struct ifconf ifc; 333 struct ifreq *ifr, ifrcopy; 334 struct sockaddr_in *sinptr; 335 336 #if defined(AF_INET6) && HAVE_IPV6 337 struct sockaddr_in6 *sinptr6; 338 #endif 339 340 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 341 if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); 342 #endif 343 344 sockfd = -1; 345 sockf6 = -1; 346 buf = NULL; 347 ifihead = NULL; 348 349 sockfd = socket(AF_INET, SOCK_DGRAM, 0); 350 if (sockfd < 0) { 351 goto gotError; 352 } 353 354 lastlen = 0; 355 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 356 for ( ; ; ) { 357 buf = (char*)malloc(len); 358 if (buf == NULL) { 359 goto gotError; 360 } 361 ifc.ifc_len = len; 362 ifc.ifc_buf = buf; 363 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 364 if (errno != EINVAL || lastlen != 0) { 365 goto gotError; 366 } 367 } else { 368 if (ifc.ifc_len == lastlen) 369 break; /* success, len has not changed */ 370 lastlen = ifc.ifc_len; 371 } 372 len += 10 * sizeof(struct ifreq); /* increment */ 373 free(buf); 374 } 375 ifihead = NULL; 376 ifipnext = &ifihead; 377 lastname[0] = 0; 378 /* end get_ifi_info1 */ 379 380 /* include get_ifi_info2 */ 381 for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 382 ifr = (struct ifreq *) ptr; 383 384 /* Advance to next one in buffer */ 385 if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr)) 386 ptr += sizeof(struct ifreq); 387 else 388 ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr); 389 390 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family); 391 392 if (ifr->ifr_addr.sa_family != family) 393 continue; /* ignore if not desired address family */ 394 395 myflags = 0; 396 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 397 *cptr = 0; /* replace colon will null */ 398 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 399 if (doaliases == 0) 400 continue; /* already processed this interface */ 401 myflags = IFI_ALIAS; 402 } 403 memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 404 405 ifrcopy = *ifr; 406 if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) { 407 goto gotError; 408 } 409 410 flags = ifrcopy.ifr_flags; 411 if ((flags & IFF_UP) == 0) 412 continue; /* ignore if interface not up */ 413 414 ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 415 if (ifi == NULL) { 416 goto gotError; 417 } 418 *ifipnext = ifi; /* prev points to this new one */ 419 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 420 421 ifi->ifi_flags = flags; /* IFF_xxx values */ 422 ifi->ifi_myflags = myflags; /* IFI_xxx values */ 423 #ifndef NOT_HAVE_IF_NAMETOINDEX 424 ifi->ifi_index = if_nametoindex(ifr->ifr_name); 425 #else 426 ifrcopy = *ifr; 427 #ifdef SIOCGIFINDEX 428 if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy)) 429 ifi->ifi_index = ifrcopy.ifr_index; 430 else 431 #endif 432 ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */ 433 #endif 434 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 435 ifi->ifi_name[IFI_NAME-1] = '\0'; 436 /* end get_ifi_info2 */ 437 /* include get_ifi_info3 */ 438 switch (ifr->ifr_addr.sa_family) { 439 case AF_INET: 440 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 441 if (ifi->ifi_addr == NULL) { 442 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 443 if (ifi->ifi_addr == NULL) { 444 goto gotError; 445 } 446 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 447 448 #ifdef SIOCGIFNETMASK 449 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError; 450 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 451 if (ifi->ifi_netmask == NULL) goto gotError; 452 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; 453 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 454 #ifndef NOT_HAVE_SA_LEN 455 sinptr->sin_len = sizeof(struct sockaddr_in); 456 #endif 457 sinptr->sin_family = AF_INET; 458 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); 459 #endif 460 461 #ifdef SIOCGIFBRDADDR 462 if (flags & IFF_BROADCAST) { 463 if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) { 464 goto gotError; 465 } 466 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 467 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 468 #ifndef NOT_HAVE_SA_LEN 469 sinptr->sin_len = sizeof( struct sockaddr_in ); 470 #endif 471 sinptr->sin_family = AF_INET; 472 ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 473 if (ifi->ifi_brdaddr == NULL) { 474 goto gotError; 475 } 476 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); 477 } 478 #endif 479 480 #ifdef SIOCGIFDSTADDR 481 if (flags & IFF_POINTOPOINT) { 482 if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) { 483 goto gotError; 484 } 485 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; 486 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 487 #ifndef NOT_HAVE_SA_LEN 488 sinptr->sin_len = sizeof( struct sockaddr_in ); 489 #endif 490 sinptr->sin_family = AF_INET; 491 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 492 if (ifi->ifi_dstaddr == NULL) { 493 goto gotError; 494 } 495 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); 496 } 497 #endif 498 } 499 break; 500 501 #if defined(AF_INET6) && HAVE_IPV6 502 case AF_INET6: 503 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; 504 if (ifi->ifi_addr == NULL) { 505 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 506 if (ifi->ifi_addr == NULL) { 507 goto gotError; 508 } 509 510 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */ 511 /* We need to strip that out */ 512 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr)) 513 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0; 514 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); 515 516 #ifdef SIOCGIFNETMASK_IN6 517 { 518 struct in6_ifreq ifr6; 519 if (sockf6 == -1) 520 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); 521 memset(&ifr6, 0, sizeof(ifr6)); 522 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); 523 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); 524 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError; 525 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); 526 if (ifi->ifi_netmask == NULL) goto gotError; 527 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; 528 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6)); 529 } 530 #endif 531 } 532 break; 533 #endif 534 535 default: 536 break; 537 } 538 } 539 goto done; 540 541 gotError: 542 if (ifihead != NULL) { 543 free_ifi_info(ifihead); 544 ifihead = NULL; 545 } 546 547 done: 548 if (buf != NULL) { 549 free(buf); 550 } 551 if (sockfd != -1) { 552 junk = close(sockfd); 553 assert(junk == 0); 554 } 555 if (sockf6 != -1) { 556 junk = close(sockf6); 557 assert(junk == 0); 558 } 559 return(ifihead); /* pointer to first structure in linked list */ 560 } 561 /* end get_ifi_info3 */ 562 563 /* include free_ifi_info */ 564 void 565 free_ifi_info(struct ifi_info *ifihead) 566 { 567 struct ifi_info *ifi, *ifinext; 568 569 for (ifi = ifihead; ifi != NULL; ifi = ifinext) { 570 if (ifi->ifi_addr != NULL) 571 free(ifi->ifi_addr); 572 if (ifi->ifi_netmask != NULL) 573 free(ifi->ifi_netmask); 574 if (ifi->ifi_brdaddr != NULL) 575 free(ifi->ifi_brdaddr); 576 if (ifi->ifi_dstaddr != NULL) 577 free(ifi->ifi_dstaddr); 578 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ 579 free(ifi); /* the ifi_info{} itself */ 580 } 581 } 582 /* end free_ifi_info */ 583 584 ssize_t 585 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 586 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl) 587 { 588 struct msghdr msg; 589 struct iovec iov[1]; 590 ssize_t n; 591 592 #ifdef CMSG_FIRSTHDR 593 struct cmsghdr *cmptr; 594 union { 595 struct cmsghdr cm; 596 char control[1024]; 597 } control_un; 598 599 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 600 601 msg.msg_control = control_un.control; 602 msg.msg_controllen = sizeof(control_un.control); 603 msg.msg_flags = 0; 604 #else 605 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 606 #endif /* CMSG_FIRSTHDR */ 607 608 msg.msg_name = (char *) sa; 609 msg.msg_namelen = *salenptr; 610 iov[0].iov_base = (char *)ptr; 611 iov[0].iov_len = nbytes; 612 msg.msg_iov = iov; 613 msg.msg_iovlen = 1; 614 615 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 616 return(n); 617 618 *salenptr = msg.msg_namelen; /* pass back results */ 619 if (pktp) { 620 /* 0.0.0.0, i/f = -1 */ 621 /* We set the interface to -1 so that the caller can 622 tell whether we returned a meaningful value or 623 just some default. Previously this code just 624 set the value to 0, but I'm concerned that 0 625 might be a valid interface value. 626 */ 627 memset(pktp, 0, sizeof(struct my_in_pktinfo)); 628 pktp->ipi_ifindex = -1; 629 } 630 /* end recvfrom_flags1 */ 631 632 /* include recvfrom_flags2 */ 633 #ifndef CMSG_FIRSTHDR 634 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 635 *flagsp = 0; /* pass back results */ 636 return(n); 637 #else 638 639 *flagsp = msg.msg_flags; /* pass back results */ 640 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 641 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 642 return(n); 643 644 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 645 cmptr = CMSG_NXTHDR(&msg, cmptr)) { 646 647 #ifdef IP_PKTINFO 648 #if in_pktinfo_definition_is_missing 649 struct in_pktinfo 650 { 651 int ipi_ifindex; 652 struct in_addr ipi_spec_dst; 653 struct in_addr ipi_addr; 654 }; 655 #endif 656 if (cmptr->cmsg_level == IPPROTO_IP && 657 cmptr->cmsg_type == IP_PKTINFO) { 658 struct in_pktinfo *tmp; 659 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 660 661 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 662 sin->sin_family = AF_INET; 663 sin->sin_addr = tmp->ipi_addr; 664 sin->sin_port = 0; 665 pktp->ipi_ifindex = tmp->ipi_ifindex; 666 continue; 667 } 668 #endif 669 670 #ifdef IP_RECVDSTADDR 671 if (cmptr->cmsg_level == IPPROTO_IP && 672 cmptr->cmsg_type == IP_RECVDSTADDR) { 673 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 674 675 sin->sin_family = AF_INET; 676 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 677 sin->sin_port = 0; 678 continue; 679 } 680 #endif 681 682 #ifdef IP_RECVIF 683 if (cmptr->cmsg_level == IPPROTO_IP && 684 cmptr->cmsg_type == IP_RECVIF) { 685 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 686 #ifndef HAVE_BROKEN_RECVIF_NAME 687 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 688 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 689 #endif 690 pktp->ipi_ifindex = sdl->sdl_index; 691 #ifdef HAVE_BROKEN_RECVIF_NAME 692 if (sdl->sdl_index == 0) { 693 pktp->ipi_ifindex = *(uint_t*)sdl; 694 } 695 #endif 696 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 697 // null terminated because of memset above 698 continue; 699 } 700 #endif 701 702 #ifdef IP_RECVTTL 703 if (cmptr->cmsg_level == IPPROTO_IP && 704 cmptr->cmsg_type == IP_RECVTTL) { 705 *ttl = *(u_char*)CMSG_DATA(cmptr); 706 continue; 707 } 708 else if (cmptr->cmsg_level == IPPROTO_IP && 709 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 710 *ttl = *(int*)CMSG_DATA(cmptr); 711 continue; 712 } 713 #endif 714 715 #if defined(IPV6_PKTINFO) && HAVE_IPV6 716 if (cmptr->cmsg_level == IPPROTO_IPV6 && 717 cmptr->cmsg_type == IPV6_PKTINFO) { 718 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 719 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 720 721 sin6->sin6_family = AF_INET6; 722 #ifndef NOT_HAVE_SA_LEN 723 sin6->sin6_len = sizeof(*sin6); 724 #endif 725 sin6->sin6_addr = ip6_info->ipi6_addr; 726 sin6->sin6_flowinfo = 0; 727 sin6->sin6_scope_id = 0; 728 sin6->sin6_port = 0; 729 pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 730 continue; 731 } 732 #endif 733 734 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 735 if (cmptr->cmsg_level == IPPROTO_IPV6 && 736 cmptr->cmsg_type == IPV6_HOPLIMIT) { 737 *ttl = *(int*)CMSG_DATA(cmptr); 738 continue; 739 } 740 #endif 741 assert(0); // unknown ancillary data 742 } 743 return(n); 744 #endif /* CMSG_FIRSTHDR */ 745 } 746 747 // ********************************************************************************************** 748 749 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4. 750 // Returns 0 on success, -1 on failure. 751 752 #ifdef NOT_HAVE_DAEMON 753 #include <fcntl.h> 754 #include <sys/stat.h> 755 #include <sys/signal.h> 756 757 int daemon(int nochdir, int noclose) 758 { 759 switch (fork()) 760 { 761 case -1: return (-1); // Fork failed 762 case 0: break; // Child -- continue 763 default: _exit(0); // Parent -- exit 764 } 765 766 if (setsid() == -1) return(-1); 767 768 signal(SIGHUP, SIG_IGN); 769 770 switch (fork()) // Fork again, primarily for reasons of Unix trivia 771 { 772 case -1: return (-1); // Fork failed 773 case 0: break; // Child -- continue 774 default: _exit(0); // Parent -- exit 775 } 776 777 if (!nochdir) (void)chdir("/"); 778 umask(0); 779 780 if (!noclose) 781 { 782 int fd = open("/dev/null", O_RDWR, 0); 783 if (fd != -1) 784 { 785 // Avoid unnecessarily duplicating a file descriptor to itself 786 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO); 787 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO); 788 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO); 789 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 790 (void)close (fd); 791 } 792 } 793 return (0); 794 } 795 #endif /* NOT_HAVE_DAEMON */ 796