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