Home | History | Annotate | Download | only in mdnsd
      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