xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSUNP.c (revision b88604e3d674a4c82f27e5c41d05b8774a7547e4)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /* -*- Mode: C; tab-width: 4 -*-
6  *
7  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20 
21     Change History (most recent first):
22 
23 $Log: mDNSUNP.c,v $
24 Revision 1.34  2006/08/14 23:24:47  cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26 
27 Revision 1.33  2006/03/13 23:14:21  cheshire
28 <rdar://problem/4427969> Compile problems on FreeBSD
29 Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
30 
31 Revision 1.32  2005/12/21 02:56:43  cheshire
32 <rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
33 
34 Revision 1.31  2005/12/21 02:46:05  cheshire
35 <rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
36 
37 Revision 1.30  2005/11/29 20:03:02  mkrochma
38 Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
39 
40 Revision 1.29  2005/11/12 02:23:10  cheshire
41 <rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
42 
43 Revision 1.28  2005/10/31 22:09:45  cheshire
44 Buffer "char addr6[33]" was seven bytes too small
45 
46 Revision 1.27  2005/06/29 15:54:21  cheshire
47 <rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
48 Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
49 
50 Revision 1.26  2005/04/08 21:43:59  ksekar
51 <rdar://problem/4083426>  mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
52 Submitted by Andrew de Quincey
53 
54 Revision 1.25  2005/04/08 21:37:57  ksekar
55 <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
56 
57 Revision 1.24  2005/04/08 21:30:16  ksekar
58 <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
59 Patch submitted by Bernd Kuhls
60 
61 Revision 1.23  2004/12/01 04:25:05  cheshire
62 <rdar://problem/3872803> Darwin patches for Solaris and Suse
63 Provide daemon() for platforms that don't have it
64 
65 Revision 1.22  2004/11/30 22:37:01  cheshire
66 Update copyright dates and add "Mode: C; tab-width: 4" headers
67 
68 Revision 1.21  2004/11/08 22:13:59  rpantos
69 Create sockf6 lazily when v6 interface found.
70 
71 Revision 1.20  2004/10/16 00:17:01  cheshire
72 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
73 
74 Revision 1.19  2004/07/20 01:47:36  rpantos
75 NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
76 
77 Revision 1.18  2004/07/08 21:30:21  rpantos
78 
79 Revision 1.17  2004/06/25 00:26:27  rpantos
80 Changes to fix the Posix build on Solaris.
81 
82 Revision 1.16  2004/03/20 05:37:09  cheshire
83 Fix contributed by Terry Lambert & Alfred Perlstein:
84 Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
85 
86 Revision 1.15  2004/02/14 01:09:45  rpantos
87 Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
88 
89 Revision 1.14  2003/12/11 18:53:40  cheshire
90 Fix compiler warning reported by Paul Guyot
91 
92 Revision 1.13  2003/12/08 20:47:02  rpantos
93 Add support for mDNSResponder on Linux.
94 
95 Revision 1.12  2003/09/02 20:47:13  cheshire
96 Fix signed/unsigned warning
97 
98 Revision 1.11  2003/08/12 19:56:26  cheshire
99 Update to APSL 2.0
100 
101 Revision 1.10  2003/08/06 18:20:51  cheshire
102 Makefile cleanup
103 
104 Revision 1.9  2003/07/14 18:11:54  cheshire
105 Fix stricter compiler warnings
106 
107 Revision 1.8  2003/07/02 21:19:59  cheshire
108 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
109 
110 Revision 1.7  2003/03/20 21:10:31  cheshire
111 Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
112 
113 Revision 1.6  2003/03/13 03:46:21  cheshire
114 Fixes to make the code build on Linux
115 
116 Revision 1.5  2003/02/07 03:02:02  cheshire
117 Submitted by: Mitsutaka Watanabe
118 The code saying "index += 1;" was effectively making up random interface index values.
119 The right way to find the correct interface index is if_nametoindex();
120 
121 Revision 1.4  2002/12/23 22:13:31  jgraessl
122 
123 Reviewed by: Stuart Cheshire
124 Initial IPv6 support for mDNSResponder.
125 
126 Revision 1.3  2002/09/21 20:44:53  zarzycki
127 Added APSL info
128 
129 Revision 1.2  2002/09/19 04:20:44  cheshire
130 Remove high-ascii characters that confuse some systems
131 
132 Revision 1.1  2002/09/17 06:24:34  cheshire
133 First checkin
134 
135 */
136 
137 #include "mDNSUNP.h"
138 
139 #include "mDNSDebug.h"
140 
141 #include <errno.h>
142 #include <assert.h>
143 #include <string.h>
144 #include <stdlib.h>
145 #include <sys/uio.h>
146 #include <sys/ioctl.h>
147 #include <unistd.h>
148 #include <stdio.h>
149 
150 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
151    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
152    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
153    should be set to the name of the header to include to get the ALIGN(P) macro.
154 */
155 #ifdef NEED_ALIGN_MACRO
156 #include NEED_ALIGN_MACRO
157 #endif
158 
159 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
160    other platforms don't even have that include file.  So,
161    if we haven't yet got a definition, let's try to find
162    <sys/sockio.h>.
163 */
164 
165 #ifndef SIOCGIFCONF
166     #include <sys/sockio.h>
167 #endif
168 
169 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
170    so only include the header in that case.
171 */
172 
173 #ifdef  IP_RECVIF
174     #include <net/if_dl.h>
175 #endif
176 
177 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
178 #if !HAVE_SOLARIS
179 #include <net/if_var.h>
180 #else
181 #include <alloca.h>
182 #ifdef HAVE_SOLARIS_ZONES
183 #include <zone.h>
184 #endif /* HAVE_SOLARIS_ZONES */
185 #endif /* !HAVE_SOLARIS */
186 #include <netinet/in_var.h>
187 // NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
188 #endif
189 
190 #if defined(AF_INET6) && HAVE_IPV6
191 
192 #if HAVE_LINUX
193 #include <netdb.h>
194 #include <arpa/inet.h>
195 
196 /* Converts a prefix length to IPv6 network mask */
197 void plen_to_mask(int plen, char *addr) {
198 	int i;
199 	int colons=7; /* Number of colons in IPv6 address */
200 	int bits_in_block=16; /* Bits per IPv6 block */
201 	for(i=0;i<=colons;i++) {
202 		int block, ones=0xffff, ones_in_block;
203 		if(plen>bits_in_block) ones_in_block=bits_in_block;
204 		else                   ones_in_block=plen;
205 		block = ones & (ones << (bits_in_block-ones_in_block));
206 		i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
207 		plen -= ones_in_block;
208 		}
209 	}
210 
211 /* Gets IPv6 interface information from the /proc filesystem in linux*/
212 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
213 	{
214 	struct ifi_info *ifi, *ifihead, **ifipnext;
215 	FILE *fp;
216 	char addr[8][5];
217 	int flags, myflags, index, plen, scope;
218 	char ifname[8], lastname[IFNAMSIZ];
219 	char addr6[32+7+1]; /* don't forget the seven ':' */
220 	struct addrinfo hints, *res0;
221 	struct sockaddr_in6 *sin6;
222 	struct in6_addr *addrptr;
223 	int err;
224 
225 	res0=NULL;
226 	ifihead = NULL;
227 	ifipnext = &ifihead;
228 	lastname[0] = 0;
229 
230 	if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
231 		while (fscanf(fp,
232 					  "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
233 					  addr[0],addr[1],addr[2],addr[3],
234 					  addr[4],addr[5],addr[6],addr[7],
235 					  &index, &plen, &scope, &flags, ifname) != EOF) {
236 
237 			myflags = 0;
238 			if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
239 				if (doaliases == 0)
240 					continue;   /* already processed this interface */
241 				myflags = IFI_ALIAS;
242 				}
243 			memcpy(lastname, ifname, IFNAMSIZ);
244 			ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
245 			if (ifi == NULL) {
246 				goto gotError;
247 				}
248 
249 			*ifipnext = ifi;            /* prev points to this new one */
250 			ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
251 
252 			sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
253 					addr[0],addr[1],addr[2],addr[3],
254 					addr[4],addr[5],addr[6],addr[7]);
255 
256 			/* Add address of the interface */
257 			memset(&hints, 0, sizeof(hints));
258 			hints.ai_family = AF_INET6;
259 			hints.ai_flags = AI_NUMERICHOST;
260 			err = getaddrinfo(addr6, NULL, &hints, &res0);
261 			if (err) {
262 				goto gotError;
263 				}
264 			ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
265 			if (ifi->ifi_addr == NULL) {
266 				goto gotError;
267 				}
268 			memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
269 
270 			/* Add netmask of the interface */
271 			char ipv6addr[INET6_ADDRSTRLEN];
272 			plen_to_mask(plen, ipv6addr);
273 			ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
274 			if (ifi->ifi_addr == NULL) {
275 				goto gotError;
276 				}
277 			sin6=calloc(1, sizeof(struct sockaddr_in6));
278 			addrptr=calloc(1, sizeof(struct in6_addr));
279 			inet_pton(family, ipv6addr, addrptr);
280 			sin6->sin6_family=family;
281 			sin6->sin6_addr=*addrptr;
282 			sin6->sin6_scope_id=scope;
283 			memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
284 			free(sin6);
285 
286 
287 			/* Add interface name */
288 			memcpy(ifi->ifi_name, ifname, IFI_NAME);
289 
290 			/* Add interface index */
291 			ifi->ifi_index = index;
292 
293 			/* If interface is in /proc then it is up*/
294 			ifi->ifi_flags = IFF_UP;
295 
296 			freeaddrinfo(res0);
297 			res0=NULL;
298 			}
299 		}
300 	goto done;
301 
302 	gotError:
303 	if (ifihead != NULL) {
304 		free_ifi_info(ifihead);
305 		ifihead = NULL;
306 		}
307 	if (res0 != NULL) {
308 		freeaddrinfo(res0);
309 		res0=NULL;
310 		}
311 	done:
312 	return(ifihead);    /* pointer to first structure in linked list */
313 	}
314 
315 #endif  /* LINUX */
316 #endif  /* defined(AF_INET6) && HAVE_IPV6 */
317 
318 #if HAVE_SOLARIS
319 
320 /*
321  * Converts prefix length to network mask. Assumes
322  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
323  * Unlike plen_to_mask returns netmask in binary form and not
324  * in text form.
325  */
326 static void plen_to_netmask(int prefix, unsigned char *addr) {
327     for (; prefix > 8; prefix -= 8)
328         *addr++ = 0xff;
329     for (; prefix > 0; prefix--)
330         *addr = (*addr >> 1) | 0x80;
331 }
332 
333 /*
334  * This function goes through all the IP interfaces associated with a
335  * physical interface and finds the best matched one for use by mDNS.
336  * Returns NULL when none of the IP interfaces associated with a physical
337  * interface are usable. Otherwise returns the best matched interface
338  * information and a pointer to the best matched lifreq.
339  */
340 struct ifi_info *
341 select_src_ifi_info_solaris(int sockfd, int numifs,
342         struct lifreq *lifrlist, const char *curifname,
343         struct lifreq **best_lifr)
344 {
345     struct lifreq *lifr;
346     struct lifreq lifrcopy;
347     struct ifi_info *ifi;
348     char *chptr;
349     char cmpifname[LIFNAMSIZ];
350     int i;
351     uint64_t best_lifrflags;
352     uint64_t ifflags;
353 
354     *best_lifr = NULL;
355 
356     /*
357      * Check all logical interfaces associated with the physical
358      * interface and figure out which one works best for us.
359      */
360     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
361 
362         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
363             continue; /* skip interface */
364 
365         /* Strip logical interface number before checking ifname */
366         if ((chptr = strchr(cmpifname, ':')) != NULL)
367             *chptr = '\0';
368 
369         /*
370          * Check ifname to see if the logical interface is associated
371          * with the physical interface we are interested in.
372          */
373         if (strcmp(cmpifname, curifname) != 0)
374             continue;
375 
376 #ifdef HAVE_SOLARIS_ZONES
377         /* Check the zone associated with the address */
378         lifrcopy = *lifr;
379         if (ioctl(sockfd, SIOCGLIFZONE, &lifrcopy) < 0) {
380             /* interface removed */
381             if (errno == ENXIO)
382                 continue;
383             return(NULL);
384         }
385         if (lifrcopy.lifr_zoneid != getzoneid())
386             continue;
387 #endif
388 
389         lifrcopy = *lifr;
390         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
391             /* interface removed */
392             if (errno == ENXIO)
393                 continue;
394             return(NULL);
395         }
396         ifflags = lifrcopy.lifr_flags;
397 
398         /* ignore address if not up */
399         if ((ifflags & IFF_UP) == 0)
400             continue;
401         /*
402          * Avoid address if any of the following flags are set:
403          *  IFF_NOXMIT: no packets transmitted over interface
404          *  IFF_NOLOCAL: no address
405          *  IFF_PRIVATE: is not advertised
406          */
407         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
408             continue;
409 
410 	/* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
411         if (lifr->lifr_addr.ss_family == AF_INET) {
412 		struct sockaddr_in *sinptr;
413 
414 		sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
415 		if (sinptr->sin_addr.s_addr == INADDR_ANY)
416 			continue;
417 	}
418 
419         if (*best_lifr != NULL) {
420             /*
421              * Check if we found a better interface by checking
422              * the flags. If flags are identical we prefer
423              * the new found interface.
424              */
425             uint64_t diff_flags = best_lifrflags ^ ifflags;
426 
427             /* If interface has a different set of flags */
428             if (diff_flags != 0) {
429                 /* Check flags in increasing order of ones we prefer */
430 
431                 /* Address temporary? */
432                 if ((diff_flags & IFF_TEMPORARY) &&
433                     (ifflags & IFF_TEMPORARY))
434                     continue;
435                 /* Deprecated address? */
436                 if ((diff_flags & IFF_DEPRECATED) &&
437                     (ifflags & IFF_DEPRECATED))
438                     continue;
439                 /* Last best-matched interface address has preferred? */
440                 if ((diff_flags & IFF_PREFERRED) &&
441                     ((ifflags & IFF_PREFERRED) == 0))
442                     continue;
443             }
444         }
445 
446         /* Set best match interface & flags */
447         *best_lifr = lifr;
448         best_lifrflags = ifflags;
449     }
450 
451     if (*best_lifr == NULL)
452         return(NULL);
453 
454     /* Found a match: return the interface information */
455     ifi = calloc(1, sizeof(struct ifi_info));
456     if (ifi == NULL)
457         return(NULL);
458 
459     ifi->ifi_flags = best_lifrflags;
460     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
461     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
462         free(ifi);
463         return(NULL);
464     }
465     return(ifi);
466 }
467 
468 /*
469  * Returns a list of IP interface information on Solaris. The function
470  * returns all IP interfaces on the system with IPv4 address assigned
471  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
472  * when AF_INET6 is passed.
473  */
474 struct ifi_info *get_ifi_info_solaris(int family)
475 {
476     struct ifi_info     *ifi, *ifihead, **ifipnext;
477     int   sockfd;
478     int  len;
479     char  *buf;
480     char *cptr;
481     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
482     struct sockaddr_in *sinptr;
483     struct lifnum lifn;
484     struct lifconf lifc;
485     struct lifreq *lifrp, *best_lifr;
486     struct lifreq lifrcopy;
487     int numifs, nlifr, n;
488 #if defined(AF_INET6) && HAVE_IPV6
489     struct sockaddr_in6 *sinptr6;
490 #endif
491 
492     ifihead = NULL;
493 
494     sockfd = socket(family, SOCK_DGRAM, 0);
495     if (sockfd < 0)
496         goto gotError;
497 
498 again:
499     lifn.lifn_family = family;
500     lifn.lifn_flags = 0;
501     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
502         goto gotError;
503     /*
504      * Pad interface count to detect & retrieve any
505      * additional interfaces between IFNUM & IFCONF calls.
506      */
507     lifn.lifn_count += 4;
508     numifs = lifn.lifn_count;
509     len = numifs * sizeof (struct lifreq);
510     buf = alloca(len);
511 
512     lifc.lifc_family = family;
513     lifc.lifc_len = len;
514     lifc.lifc_buf = buf;
515     lifc.lifc_flags = 0;
516 
517     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
518         goto gotError;
519 
520     nlifr = lifc.lifc_len / sizeof(struct lifreq);
521     if (nlifr >= numifs)
522         goto again;
523 
524     lifrp = lifc.lifc_req;
525     ifipnext = &ifihead;
526 
527     for (n = nlifr; n > 0; n--, lifrp++) {
528 
529         if (lifrp->lifr_addr.ss_family != family)
530             continue;
531 
532         /*
533          * See if we have already processed the interface
534          * by checking the interface names.
535          */
536         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
537             goto gotError;
538         if ((cptr = strchr(ifname, ':')) != NULL)
539             *cptr = '\0';
540 
541         /*
542          * If any of the interfaces found so far share the physical
543          * interface name then we have already processed the interface.
544          */
545         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
546 
547             /* Retrieve physical interface name */
548             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
549 
550             /* Strip logical interface number before checking ifname */
551             if ((cptr = strchr(cmpifname, ':')) != NULL)
552                 *cptr = '\0';
553 
554             if (strcmp(cmpifname, ifname) == 0)
555                 break;
556         }
557         if (ifi != NULL)
558             continue; /* already processed */
559 
560         /*
561          * New interface, find the one with the preferred source
562          * address for our use in Multicast DNS.
563          */
564         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
565             lifc.lifc_req, ifname, &best_lifr)) == NULL)
566             continue;
567 
568         assert(best_lifr != NULL);
569         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
570                (best_lifr->lifr_addr.ss_family == AF_INET));
571 
572         switch (best_lifr->lifr_addr.ss_family) {
573 
574 #if defined(AF_INET6) && HAVE_IPV6
575         case AF_INET6:
576             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
577             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
578             if (ifi->ifi_addr == NULL)
579                 goto gotError;
580             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
581 
582             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
583             if (ifi->ifi_netmask == NULL)
584                 goto gotError;
585             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
586             sinptr6->sin6_family = AF_INET6;
587             plen_to_netmask(best_lifr->lifr_addrlen,
588                     (unsigned char *) &(sinptr6->sin6_addr));
589             break;
590 #endif
591 
592         case AF_INET:
593             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
594             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
595             if (ifi->ifi_addr == NULL)
596                 goto gotError;
597 
598             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
599 
600             lifrcopy = *best_lifr;
601             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
602                 /* interface removed */
603                 if (errno == ENXIO) {
604                     free(ifi->ifi_addr);
605                     free(ifi);
606                     continue;
607                 }
608                 goto gotError;
609             }
610 
611             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
612             if (ifi->ifi_netmask == NULL)
613                 goto gotError;
614             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
615             sinptr->sin_family = AF_INET;
616             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
617             break;
618 
619         default:
620             /* never reached */
621             break;
622         }
623 
624         *ifipnext = ifi;            /* prev points to this new one */
625         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
626     }
627 
628     (void) close(sockfd);
629     return(ifihead);    /* pointer to first structure in linked list */
630 
631 gotError:
632     if (sockfd != -1)
633         (void) close(sockfd);
634     if (ifihead != NULL)
635         free_ifi_info(ifihead);
636     return(NULL);
637 }
638 
639 #endif /* HAVE_SOLARIS */
640 
641 struct ifi_info *get_ifi_info(int family, int doaliases)
642 {
643     int                 junk;
644     struct ifi_info     *ifi, *ifihead, **ifipnext;
645     int                 sockfd, sockf6, len, lastlen, flags, myflags;
646 #ifdef NOT_HAVE_IF_NAMETOINDEX
647     int                 index = 200;
648 #endif
649     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
650     struct ifconf       ifc;
651     struct ifreq        *ifr, ifrcopy;
652     struct sockaddr_in  *sinptr;
653 
654 #if defined(AF_INET6) && HAVE_IPV6
655     struct sockaddr_in6 *sinptr6;
656 #endif
657 
658 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
659     if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
660 #elif HAVE_SOLARIS
661     return get_ifi_info_solaris(family);
662 #endif
663 
664     sockfd = -1;
665     sockf6 = -1;
666     buf = NULL;
667     ifihead = NULL;
668 
669     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
670     if (sockfd < 0) {
671         goto gotError;
672     }
673 
674     lastlen = 0;
675     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
676     for ( ; ; ) {
677         buf = (char*)malloc(len);
678         if (buf == NULL) {
679             goto gotError;
680         }
681         ifc.ifc_len = len;
682         ifc.ifc_buf = buf;
683         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
684             if (errno != EINVAL || lastlen != 0) {
685                 goto gotError;
686             }
687         } else {
688             if (ifc.ifc_len == lastlen)
689                 break;      /* success, len has not changed */
690             lastlen = ifc.ifc_len;
691         }
692         len += 10 * sizeof(struct ifreq);   /* increment */
693         free(buf);
694     }
695     ifihead = NULL;
696     ifipnext = &ifihead;
697     lastname[0] = 0;
698 /* end get_ifi_info1 */
699 
700 /* include get_ifi_info2 */
701     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
702         ifr = (struct ifreq *) ptr;
703 
704         /* Advance to next one in buffer */
705         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
706             ptr += sizeof(struct ifreq);
707         else
708             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
709 
710 //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
711 
712         if (ifr->ifr_addr.sa_family != family)
713             continue;   /* ignore if not desired address family */
714 
715         myflags = 0;
716         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
717             *cptr = 0;      /* replace colon will null */
718         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
719             if (doaliases == 0)
720                 continue;   /* already processed this interface */
721             myflags = IFI_ALIAS;
722         }
723         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
724 
725         ifrcopy = *ifr;
726         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
727             goto gotError;
728         }
729 
730         flags = ifrcopy.ifr_flags;
731         if ((flags & IFF_UP) == 0)
732             continue;   /* ignore if interface not up */
733 
734         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
735         if (ifi == NULL) {
736             goto gotError;
737         }
738         *ifipnext = ifi;            /* prev points to this new one */
739         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
740 
741         ifi->ifi_flags = flags;     /* IFF_xxx values */
742         ifi->ifi_myflags = myflags; /* IFI_xxx values */
743 #ifndef NOT_HAVE_IF_NAMETOINDEX
744         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
745 #else
746         ifrcopy = *ifr;
747 #ifdef SIOCGIFINDEX
748         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
749             ifi->ifi_index = ifrcopy.ifr_index;
750         else
751 #endif
752             ifi->ifi_index = index++;	/* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
753 #endif
754         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
755         ifi->ifi_name[IFI_NAME-1] = '\0';
756 /* end get_ifi_info2 */
757 /* include get_ifi_info3 */
758         switch (ifr->ifr_addr.sa_family) {
759         case AF_INET:
760             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
761             if (ifi->ifi_addr == NULL) {
762                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
763                 if (ifi->ifi_addr == NULL) {
764                     goto gotError;
765                 }
766                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
767 
768 #ifdef  SIOCGIFNETMASK
769 				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
770 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
771 				if (ifi->ifi_netmask == NULL) goto gotError;
772 				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
773 				/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
774 #ifndef NOT_HAVE_SA_LEN
775 				sinptr->sin_len    = sizeof(struct sockaddr_in);
776 #endif
777 				sinptr->sin_family = AF_INET;
778 				memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
779 #endif
780 
781 #ifdef  SIOCGIFBRDADDR
782                 if (flags & IFF_BROADCAST) {
783                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
784                         goto gotError;
785                     }
786                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
787 					/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
788 #ifndef NOT_HAVE_SA_LEN
789 					sinptr->sin_len    = sizeof( struct sockaddr_in );
790 #endif
791 					sinptr->sin_family = AF_INET;
792                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
793                     if (ifi->ifi_brdaddr == NULL) {
794                         goto gotError;
795                     }
796                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
797                 }
798 #endif
799 
800 #ifdef  SIOCGIFDSTADDR
801                 if (flags & IFF_POINTOPOINT) {
802                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
803                         goto gotError;
804                     }
805                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
806                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
807 #ifndef NOT_HAVE_SA_LEN
808 					sinptr->sin_len    = sizeof( struct sockaddr_in );
809 #endif
810 					sinptr->sin_family = AF_INET;
811                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
812                     if (ifi->ifi_dstaddr == NULL) {
813                         goto gotError;
814                     }
815                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
816                 }
817 #endif
818             }
819             break;
820 
821 #if defined(AF_INET6) && HAVE_IPV6
822         case AF_INET6:
823             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
824             if (ifi->ifi_addr == NULL) {
825                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
826                 if (ifi->ifi_addr == NULL) {
827                     goto gotError;
828                 }
829 
830                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
831                 /* We need to strip that out */
832                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
833                 	sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
834                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
835 
836 #ifdef  SIOCGIFNETMASK_IN6
837 				{
838 				struct in6_ifreq ifr6;
839 				if (sockf6 == -1)
840 					sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
841 				bzero(&ifr6, sizeof(ifr6));
842 				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
843 				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
844 				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
845 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
846 				if (ifi->ifi_netmask == NULL) goto gotError;
847 				sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
848 				memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
849 				}
850 #endif
851             }
852             break;
853 #endif
854 
855         default:
856             break;
857         }
858     }
859     goto done;
860 
861 gotError:
862     if (ifihead != NULL) {
863         free_ifi_info(ifihead);
864         ifihead = NULL;
865     }
866 
867 done:
868     if (buf != NULL) {
869         free(buf);
870     }
871     if (sockfd != -1) {
872         junk = close(sockfd);
873         assert(junk == 0);
874     }
875     if (sockf6 != -1) {
876         junk = close(sockf6);
877         assert(junk == 0);
878     }
879     return(ifihead);    /* pointer to first structure in linked list */
880 }
881 /* end get_ifi_info3 */
882 
883 /* include free_ifi_info */
884 void
885 free_ifi_info(struct ifi_info *ifihead)
886 {
887     struct ifi_info *ifi, *ifinext;
888 
889     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
890         if (ifi->ifi_addr != NULL)
891             free(ifi->ifi_addr);
892         if (ifi->ifi_brdaddr != NULL)
893             free(ifi->ifi_brdaddr);
894         if (ifi->ifi_dstaddr != NULL)
895             free(ifi->ifi_dstaddr);
896         if (ifi->ifi_netmask != NULL)
897             free(ifi->ifi_netmask);
898         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
899         free(ifi);                  /* the ifi_info{} itself */
900     }
901 }
902 /* end free_ifi_info */
903 
904 ssize_t
905 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
906                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
907 {
908     struct msghdr   msg;
909     struct iovec    iov[1];
910     ssize_t         n;
911 
912 #ifdef CMSG_FIRSTHDR
913     struct cmsghdr  *cmptr;
914     union {
915       struct cmsghdr    cm;
916       char              control[1024];
917       pad64_t	align8; /* ensure structure is 8-byte aligned on sparc */
918     } control_un;
919 
920 	*ttl = 255;			// If kernel fails to provide TTL data then assume the TTL was 255 as it should be
921 
922     msg.msg_control = (void *) control_un.control;
923     msg.msg_controllen = sizeof(control_un.control);
924     msg.msg_flags = 0;
925 #else
926     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
927 #endif /* CMSG_FIRSTHDR */
928 
929     msg.msg_name = (char *) sa;
930     msg.msg_namelen = *salenptr;
931     iov[0].iov_base = (char *)ptr;
932     iov[0].iov_len = nbytes;
933     msg.msg_iov = iov;
934     msg.msg_iovlen = 1;
935 
936     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
937         return(n);
938 
939     *salenptr = msg.msg_namelen;    /* pass back results */
940     if (pktp) {
941         /* 0.0.0.0, i/f = -1 */
942         /* We set the interface to -1 so that the caller can
943            tell whether we returned a meaningful value or
944            just some default.  Previously this code just
945            set the value to 0, but I'm concerned that 0
946            might be a valid interface value.
947         */
948         memset(pktp, 0, sizeof(struct my_in_pktinfo));
949         pktp->ipi_ifindex = -1;
950     }
951 /* end recvfrom_flags1 */
952 
953 /* include recvfrom_flags2 */
954 #ifndef CMSG_FIRSTHDR
955 	#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
956     *flagsp = 0;                    /* pass back results */
957     return(n);
958 #else
959 
960     *flagsp = msg.msg_flags;        /* pass back results */
961     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
962         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
963         return(n);
964 
965     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
966          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
967 
968 #ifdef  IP_PKTINFO
969 #if in_pktinfo_definition_is_missing
970 struct in_pktinfo
971 {
972         int             ipi_ifindex;
973         struct in_addr  ipi_spec_dst;
974         struct in_addr  ipi_addr;
975 };
976 #endif
977         if (cmptr->cmsg_level == IPPROTO_IP &&
978             cmptr->cmsg_type == IP_PKTINFO) {
979             struct in_pktinfo *tmp;
980             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
981 
982             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
983             sin->sin_family = AF_INET;
984             sin->sin_addr = tmp->ipi_addr;
985             sin->sin_port = 0;
986             pktp->ipi_ifindex = tmp->ipi_ifindex;
987             continue;
988         }
989 #endif
990 
991 #ifdef  IP_RECVDSTADDR
992         if (cmptr->cmsg_level == IPPROTO_IP &&
993             cmptr->cmsg_type == IP_RECVDSTADDR) {
994             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
995 
996             sin->sin_family = AF_INET;
997             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
998             sin->sin_port = 0;
999             continue;
1000         }
1001 #endif
1002 
1003 #ifdef  IP_RECVIF
1004         if (cmptr->cmsg_level == IPPROTO_IP &&
1005             cmptr->cmsg_type == IP_RECVIF) {
1006             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
1007 #ifndef HAVE_BROKEN_RECVIF_NAME
1008             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
1009             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
1010 #endif
1011 	    (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
1012             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
1013             // null terminated because of memset above
1014             continue;
1015         }
1016 #endif
1017 
1018 #ifdef  IP_RECVTTL
1019         if (cmptr->cmsg_level == IPPROTO_IP &&
1020             cmptr->cmsg_type == IP_RECVTTL) {
1021 			*ttl = *(u_char*)CMSG_DATA(cmptr);
1022             continue;
1023         }
1024         else if (cmptr->cmsg_level == IPPROTO_IP &&
1025             cmptr->cmsg_type == IP_TTL) {		// some implementations seem to send IP_TTL instead of IP_RECVTTL
1026 			*ttl = *(int*)CMSG_DATA(cmptr);
1027             continue;
1028         }
1029 #endif
1030 
1031 #if defined(IPV6_PKTINFO) && HAVE_IPV6
1032         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
1033             cmptr->cmsg_type == IPV6_PKTINFO) {
1034             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
1035 			struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
1036 
1037             sin6->sin6_family   = AF_INET6;
1038 #ifndef NOT_HAVE_SA_LEN
1039             sin6->sin6_len      = sizeof(*sin6);
1040 #endif
1041             sin6->sin6_addr     = ip6_info->ipi6_addr;
1042             sin6->sin6_flowinfo = 0;
1043             sin6->sin6_scope_id = 0;
1044             sin6->sin6_port     = 0;
1045 			pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
1046             continue;
1047         }
1048 #endif
1049 
1050 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
1051         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
1052             cmptr->cmsg_type == IPV6_HOPLIMIT) {
1053 			*ttl = *(int*)CMSG_DATA(cmptr);
1054             continue;
1055         }
1056 #endif
1057         assert(0);  // unknown ancillary data
1058     }
1059     return(n);
1060 #endif /* CMSG_FIRSTHDR */
1061 }
1062 
1063 // **********************************************************************************************
1064 
1065 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
1066 // Returns 0 on success, -1 on failure.
1067 
1068 #ifdef NOT_HAVE_DAEMON
1069 #include <fcntl.h>
1070 #include <sys/stat.h>
1071 #include <signal.h>
1072 
1073 int daemon(int nochdir, int noclose)
1074     {
1075 	switch (fork())
1076 		{
1077 		case -1: return (-1);	// Fork failed
1078 		case 0:  break;			// Child -- continue
1079 		default: _exit(0);		// Parent -- exit
1080 		}
1081 
1082 	if (setsid() == -1) return(-1);
1083 
1084 	signal(SIGHUP, SIG_IGN);
1085 
1086 	switch (fork())				// Fork again, primarily for reasons of Unix trivia
1087 		{
1088 		case -1: return (-1);	// Fork failed
1089 		case 0:  break;			// Child -- continue
1090 		default: _exit(0);		// Parent -- exit
1091 		}
1092 
1093 	if (!nochdir) (void)chdir("/");
1094 	umask(0);
1095 
1096 	if (!noclose)
1097 		{
1098 		int fd = open("/dev/null", O_RDWR, 0);
1099 		if (fd != -1)
1100 			{
1101 			// Avoid unnecessarily duplicating a file descriptor to itself
1102 			if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
1103 			if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
1104 			if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
1105 			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
1106 				(void)close (fd);
1107 			}
1108 		}
1109 	return (0);
1110     }
1111 #endif /* NOT_HAVE_DAEMON */
1112