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