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 $
24Revision 1.34  2006/08/14 23:24:47  cheshire
25Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26
27Revision 1.33  2006/03/13 23:14:21  cheshire
28<rdar://problem/4427969> Compile problems on FreeBSD
29Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
30
31Revision 1.32  2005/12/21 02:56:43  cheshire
32<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
33
34Revision 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
37Revision 1.30  2005/11/29 20:03:02  mkrochma
38Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
39
40Revision 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
43Revision 1.28  2005/10/31 22:09:45  cheshire
44Buffer "char addr6[33]" was seven bytes too small
45
46Revision 1.27  2005/06/29 15:54:21  cheshire
47<rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
48Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
49
50Revision 1.26  2005/04/08 21:43:59  ksekar
51<rdar://problem/4083426>  mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
52Submitted by Andrew de Quincey
53
54Revision 1.25  2005/04/08 21:37:57  ksekar
55<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
56
57Revision 1.24  2005/04/08 21:30:16  ksekar
58<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
59Patch submitted by Bernd Kuhls
60
61Revision 1.23  2004/12/01 04:25:05  cheshire
62<rdar://problem/3872803> Darwin patches for Solaris and Suse
63Provide daemon() for platforms that don't have it
64
65Revision 1.22  2004/11/30 22:37:01  cheshire
66Update copyright dates and add "Mode: C; tab-width: 4" headers
67
68Revision 1.21  2004/11/08 22:13:59  rpantos
69Create sockf6 lazily when v6 interface found.
70
71Revision 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
74Revision 1.19  2004/07/20 01:47:36  rpantos
75NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
76
77Revision 1.18  2004/07/08 21:30:21  rpantos
78
79Revision 1.17  2004/06/25 00:26:27  rpantos
80Changes to fix the Posix build on Solaris.
81
82Revision 1.16  2004/03/20 05:37:09  cheshire
83Fix contributed by Terry Lambert & Alfred Perlstein:
84Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
85
86Revision 1.15  2004/02/14 01:09:45  rpantos
87Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
88
89Revision 1.14  2003/12/11 18:53:40  cheshire
90Fix compiler warning reported by Paul Guyot
91
92Revision 1.13  2003/12/08 20:47:02  rpantos
93Add support for mDNSResponder on Linux.
94
95Revision 1.12  2003/09/02 20:47:13  cheshire
96Fix signed/unsigned warning
97
98Revision 1.11  2003/08/12 19:56:26  cheshire
99Update to APSL 2.0
100
101Revision 1.10  2003/08/06 18:20:51  cheshire
102Makefile cleanup
103
104Revision 1.9  2003/07/14 18:11:54  cheshire
105Fix stricter compiler warnings
106
107Revision 1.8  2003/07/02 21:19:59  cheshire
108<rdar://problem/3313413> Update copyright notices, etc., in source code comments
109
110Revision 1.7  2003/03/20 21:10:31  cheshire
111Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
112
113Revision 1.6  2003/03/13 03:46:21  cheshire
114Fixes to make the code build on Linux
115
116Revision 1.5  2003/02/07 03:02:02  cheshire
117Submitted by: Mitsutaka Watanabe
118The code saying "index += 1;" was effectively making up random interface index values.
119The right way to find the correct interface index is if_nametoindex();
120
121Revision 1.4  2002/12/23 22:13:31  jgraessl
122
123Reviewed by: Stuart Cheshire
124Initial IPv6 support for mDNSResponder.
125
126Revision 1.3  2002/09/21 20:44:53  zarzycki
127Added APSL info
128
129Revision 1.2  2002/09/19 04:20:44  cheshire
130Remove high-ascii characters that confuse some systems
131
132Revision 1.1  2002/09/17 06:24:34  cheshire
133First 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 */
197void 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*/
212struct 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 */
326static 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 */
340struct ifi_info *
341select_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 */
474struct 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
498again:
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
631gotError:
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
641struct 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
861gotError:
862    if (ifihead != NULL) {
863        free_ifi_info(ifihead);
864        ifihead = NULL;
865    }
866
867done:
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 */
884void
885free_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
904ssize_t
905recvfrom_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
970struct 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
1073int 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