xref: /netbsd-src/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSUNP.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
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