Home | History | Annotate | Line # | Download | only in mDNSPosix
mDNSUNP.c revision 1.1
      1  1.1  tsarna /* -*- Mode: C; tab-width: 4 -*-
      2  1.1  tsarna  *
      3  1.1  tsarna  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
      4  1.1  tsarna  *
      5  1.1  tsarna  * Licensed under the Apache License, Version 2.0 (the "License");
      6  1.1  tsarna  * you may not use this file except in compliance with the License.
      7  1.1  tsarna  * You may obtain a copy of the License at
      8  1.1  tsarna  *
      9  1.1  tsarna  *     http://www.apache.org/licenses/LICENSE-2.0
     10  1.1  tsarna  *
     11  1.1  tsarna  * Unless required by applicable law or agreed to in writing, software
     12  1.1  tsarna  * distributed under the License is distributed on an "AS IS" BASIS,
     13  1.1  tsarna  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  1.1  tsarna  * See the License for the specific language governing permissions and
     15  1.1  tsarna  * limitations under the License.
     16  1.1  tsarna 
     17  1.1  tsarna     Change History (most recent first):
     18  1.1  tsarna 
     19  1.1  tsarna Log: mDNSUNP.c,v $
     20  1.1  tsarna Revision 1.40  2009/01/13 05:31:34  mkrochma
     21  1.1  tsarna <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
     22  1.1  tsarna 
     23  1.1  tsarna Revision 1.39  2009/01/11 03:20:06  mkrochma
     24  1.1  tsarna <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
     25  1.1  tsarna 
     26  1.1  tsarna Revision 1.38  2009/01/10 22:54:42  mkrochma
     27  1.1  tsarna <rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
     28  1.1  tsarna 
     29  1.1  tsarna Revision 1.37  2008/10/23 22:33:24  cheshire
     30  1.1  tsarna Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
     31  1.1  tsarna 
     32  1.1  tsarna Revision 1.36  2008/04/21 18:21:22  mkrochma
     33  1.1  tsarna <rdar://problem/5877307> Need to free ifi_netmask
     34  1.1  tsarna Submitted by Igor Seleznev
     35  1.1  tsarna 
     36  1.1  tsarna Revision 1.35  2007/11/15 21:36:19  cheshire
     37  1.1  tsarna <rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
     38  1.1  tsarna 
     39  1.1  tsarna Revision 1.34  2006/08/14 23:24:47  cheshire
     40  1.1  tsarna Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
     41  1.1  tsarna 
     42  1.1  tsarna Revision 1.33  2006/03/13 23:14:21  cheshire
     43  1.1  tsarna <rdar://problem/4427969> Compile problems on FreeBSD
     44  1.1  tsarna Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
     45  1.1  tsarna 
     46  1.1  tsarna Revision 1.32  2005/12/21 02:56:43  cheshire
     47  1.1  tsarna <rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
     48  1.1  tsarna 
     49  1.1  tsarna Revision 1.31  2005/12/21 02:46:05  cheshire
     50  1.1  tsarna <rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
     51  1.1  tsarna 
     52  1.1  tsarna Revision 1.30  2005/11/29 20:03:02  mkrochma
     53  1.1  tsarna Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
     54  1.1  tsarna 
     55  1.1  tsarna Revision 1.29  2005/11/12 02:23:10  cheshire
     56  1.1  tsarna <rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
     57  1.1  tsarna 
     58  1.1  tsarna Revision 1.28  2005/10/31 22:09:45  cheshire
     59  1.1  tsarna Buffer "char addr6[33]" was seven bytes too small
     60  1.1  tsarna 
     61  1.1  tsarna Revision 1.27  2005/06/29 15:54:21  cheshire
     62  1.1  tsarna <rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
     63  1.1  tsarna Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
     64  1.1  tsarna 
     65  1.1  tsarna Revision 1.26  2005/04/08 21:43:59  ksekar
     66  1.1  tsarna <rdar://problem/4083426>  mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
     67  1.1  tsarna Submitted by Andrew de Quincey
     68  1.1  tsarna 
     69  1.1  tsarna Revision 1.25  2005/04/08 21:37:57  ksekar
     70  1.1  tsarna <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
     71  1.1  tsarna 
     72  1.1  tsarna Revision 1.24  2005/04/08 21:30:16  ksekar
     73  1.1  tsarna <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
     74  1.1  tsarna Patch submitted by Bernd Kuhls
     75  1.1  tsarna 
     76  1.1  tsarna Revision 1.23  2004/12/01 04:25:05  cheshire
     77  1.1  tsarna <rdar://problem/3872803> Darwin patches for Solaris and Suse
     78  1.1  tsarna Provide daemon() for platforms that don't have it
     79  1.1  tsarna 
     80  1.1  tsarna Revision 1.22  2004/11/30 22:37:01  cheshire
     81  1.1  tsarna Update copyright dates and add "Mode: C; tab-width: 4" headers
     82  1.1  tsarna 
     83  1.1  tsarna Revision 1.21  2004/11/08 22:13:59  rpantos
     84  1.1  tsarna Create sockf6 lazily when v6 interface found.
     85  1.1  tsarna 
     86  1.1  tsarna Revision 1.20  2004/10/16 00:17:01  cheshire
     87  1.1  tsarna <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
     88  1.1  tsarna 
     89  1.1  tsarna Revision 1.19  2004/07/20 01:47:36  rpantos
     90  1.1  tsarna NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
     91  1.1  tsarna 
     92  1.1  tsarna Revision 1.18  2004/07/08 21:30:21  rpantos
     93  1.1  tsarna 
     94  1.1  tsarna Revision 1.17  2004/06/25 00:26:27  rpantos
     95  1.1  tsarna Changes to fix the Posix build on Solaris.
     96  1.1  tsarna 
     97  1.1  tsarna Revision 1.16  2004/03/20 05:37:09  cheshire
     98  1.1  tsarna Fix contributed by Terry Lambert & Alfred Perlstein:
     99  1.1  tsarna Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
    100  1.1  tsarna 
    101  1.1  tsarna Revision 1.15  2004/02/14 01:09:45  rpantos
    102  1.1  tsarna Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
    103  1.1  tsarna 
    104  1.1  tsarna Revision 1.14  2003/12/11 18:53:40  cheshire
    105  1.1  tsarna Fix compiler warning reported by Paul Guyot
    106  1.1  tsarna 
    107  1.1  tsarna Revision 1.13  2003/12/08 20:47:02  rpantos
    108  1.1  tsarna Add support for mDNSResponder on Linux.
    109  1.1  tsarna 
    110  1.1  tsarna Revision 1.12  2003/09/02 20:47:13  cheshire
    111  1.1  tsarna Fix signed/unsigned warning
    112  1.1  tsarna 
    113  1.1  tsarna Revision 1.11  2003/08/12 19:56:26  cheshire
    114  1.1  tsarna Update to APSL 2.0
    115  1.1  tsarna 
    116  1.1  tsarna Revision 1.10  2003/08/06 18:20:51  cheshire
    117  1.1  tsarna Makefile cleanup
    118  1.1  tsarna 
    119  1.1  tsarna Revision 1.9  2003/07/14 18:11:54  cheshire
    120  1.1  tsarna Fix stricter compiler warnings
    121  1.1  tsarna 
    122  1.1  tsarna Revision 1.8  2003/07/02 21:19:59  cheshire
    123  1.1  tsarna <rdar://problem/3313413> Update copyright notices, etc., in source code comments
    124  1.1  tsarna 
    125  1.1  tsarna Revision 1.7  2003/03/20 21:10:31  cheshire
    126  1.1  tsarna Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
    127  1.1  tsarna 
    128  1.1  tsarna Revision 1.6  2003/03/13 03:46:21  cheshire
    129  1.1  tsarna Fixes to make the code build on Linux
    130  1.1  tsarna 
    131  1.1  tsarna Revision 1.5  2003/02/07 03:02:02  cheshire
    132  1.1  tsarna Submitted by: Mitsutaka Watanabe
    133  1.1  tsarna The code saying "index += 1;" was effectively making up random interface index values.
    134  1.1  tsarna The right way to find the correct interface index is if_nametoindex();
    135  1.1  tsarna 
    136  1.1  tsarna Revision 1.4  2002/12/23 22:13:31  jgraessl
    137  1.1  tsarna 
    138  1.1  tsarna Reviewed by: Stuart Cheshire
    139  1.1  tsarna Initial IPv6 support for mDNSResponder.
    140  1.1  tsarna 
    141  1.1  tsarna Revision 1.3  2002/09/21 20:44:53  zarzycki
    142  1.1  tsarna Added APSL info
    143  1.1  tsarna 
    144  1.1  tsarna Revision 1.2  2002/09/19 04:20:44  cheshire
    145  1.1  tsarna Remove high-ascii characters that confuse some systems
    146  1.1  tsarna 
    147  1.1  tsarna Revision 1.1  2002/09/17 06:24:34  cheshire
    148  1.1  tsarna First checkin
    149  1.1  tsarna 
    150  1.1  tsarna */
    151  1.1  tsarna 
    152  1.1  tsarna #include "mDNSUNP.h"
    153  1.1  tsarna 
    154  1.1  tsarna #include <errno.h>
    155  1.1  tsarna #include <assert.h>
    156  1.1  tsarna #include <string.h>
    157  1.1  tsarna #include <stdlib.h>
    158  1.1  tsarna #include <sys/uio.h>
    159  1.1  tsarna #include <sys/ioctl.h>
    160  1.1  tsarna #include <signal.h>
    161  1.1  tsarna #include <unistd.h>
    162  1.1  tsarna #include <stdio.h>
    163  1.1  tsarna 
    164  1.1  tsarna /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
    165  1.1  tsarna    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
    166  1.1  tsarna    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
    167  1.1  tsarna    should be set to the name of the header to include to get the ALIGN(P) macro.
    168  1.1  tsarna */
    169  1.1  tsarna #ifdef NEED_ALIGN_MACRO
    170  1.1  tsarna #include NEED_ALIGN_MACRO
    171  1.1  tsarna #endif
    172  1.1  tsarna 
    173  1.1  tsarna /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
    174  1.1  tsarna    other platforms don't even have that include file.  So,
    175  1.1  tsarna    if we haven't yet got a definition, let's try to find
    176  1.1  tsarna    <sys/sockio.h>.
    177  1.1  tsarna */
    178  1.1  tsarna 
    179  1.1  tsarna #ifndef SIOCGIFCONF
    180  1.1  tsarna     #include <sys/sockio.h>
    181  1.1  tsarna #endif
    182  1.1  tsarna 
    183  1.1  tsarna /* sockaddr_dl is only referenced if we're using IP_RECVIF,
    184  1.1  tsarna    so only include the header in that case.
    185  1.1  tsarna */
    186  1.1  tsarna 
    187  1.1  tsarna #ifdef  IP_RECVIF
    188  1.1  tsarna     #include <net/if_dl.h>
    189  1.1  tsarna #endif
    190  1.1  tsarna 
    191  1.1  tsarna #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
    192  1.1  tsarna #include <net/if_var.h>
    193  1.1  tsarna #include <netinet/in_var.h>
    194  1.1  tsarna // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
    195  1.1  tsarna #endif
    196  1.1  tsarna 
    197  1.1  tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
    198  1.1  tsarna #include <netdb.h>
    199  1.1  tsarna #include <arpa/inet.h>
    200  1.1  tsarna 
    201  1.1  tsarna /* Converts a prefix length to IPv6 network mask */
    202  1.1  tsarna void plen_to_mask(int plen, char *addr) {
    203  1.1  tsarna 	int i;
    204  1.1  tsarna 	int colons=7; /* Number of colons in IPv6 address */
    205  1.1  tsarna 	int bits_in_block=16; /* Bits per IPv6 block */
    206  1.1  tsarna 	for(i=0;i<=colons;i++) {
    207  1.1  tsarna 		int block, ones=0xffff, ones_in_block;
    208  1.1  tsarna 		if(plen>bits_in_block) ones_in_block=bits_in_block;
    209  1.1  tsarna 		else                   ones_in_block=plen;
    210  1.1  tsarna 		block = ones & (ones << (bits_in_block-ones_in_block));
    211  1.1  tsarna 		i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
    212  1.1  tsarna 		plen -= ones_in_block;
    213  1.1  tsarna 		}
    214  1.1  tsarna 	}
    215  1.1  tsarna 
    216  1.1  tsarna /* Gets IPv6 interface information from the /proc filesystem in linux*/
    217  1.1  tsarna struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
    218  1.1  tsarna 	{
    219  1.1  tsarna 	struct ifi_info *ifi, *ifihead, **ifipnext;
    220  1.1  tsarna 	FILE *fp;
    221  1.1  tsarna 	char addr[8][5];
    222  1.1  tsarna 	int flags, myflags, index, plen, scope;
    223  1.1  tsarna 	char ifname[9], lastname[IFNAMSIZ];
    224  1.1  tsarna 	char addr6[32+7+1]; /* don't forget the seven ':' */
    225  1.1  tsarna 	struct addrinfo hints, *res0;
    226  1.1  tsarna 	struct sockaddr_in6 *sin6;
    227  1.1  tsarna 	struct in6_addr *addrptr;
    228  1.1  tsarna 	int err;
    229  1.1  tsarna 
    230  1.1  tsarna 	res0=NULL;
    231  1.1  tsarna 	ifihead = NULL;
    232  1.1  tsarna 	ifipnext = &ifihead;
    233  1.1  tsarna 	lastname[0] = 0;
    234  1.1  tsarna 
    235  1.1  tsarna 	if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
    236  1.1  tsarna 		while (fscanf(fp,
    237  1.1  tsarna 					  "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
    238  1.1  tsarna 					  addr[0],addr[1],addr[2],addr[3],
    239  1.1  tsarna 					  addr[4],addr[5],addr[6],addr[7],
    240  1.1  tsarna 					  &index, &plen, &scope, &flags, ifname) != EOF) {
    241  1.1  tsarna 
    242  1.1  tsarna 			myflags = 0;
    243  1.1  tsarna 			if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
    244  1.1  tsarna 				if (doaliases == 0)
    245  1.1  tsarna 					continue;   /* already processed this interface */
    246  1.1  tsarna 				myflags = IFI_ALIAS;
    247  1.1  tsarna 				}
    248  1.1  tsarna 			memcpy(lastname, ifname, IFNAMSIZ);
    249  1.1  tsarna 			ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
    250  1.1  tsarna 			if (ifi == NULL) {
    251  1.1  tsarna 				goto gotError;
    252  1.1  tsarna 				}
    253  1.1  tsarna 
    254  1.1  tsarna 			*ifipnext = ifi;            /* prev points to this new one */
    255  1.1  tsarna 			ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
    256  1.1  tsarna 
    257  1.1  tsarna 			sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
    258  1.1  tsarna 					addr[0],addr[1],addr[2],addr[3],
    259  1.1  tsarna 					addr[4],addr[5],addr[6],addr[7]);
    260  1.1  tsarna 
    261  1.1  tsarna 			/* Add address of the interface */
    262  1.1  tsarna 			memset(&hints, 0, sizeof(hints));
    263  1.1  tsarna 			hints.ai_family = AF_INET6;
    264  1.1  tsarna 			hints.ai_flags = AI_NUMERICHOST;
    265  1.1  tsarna 			err = getaddrinfo(addr6, NULL, &hints, &res0);
    266  1.1  tsarna 			if (err) {
    267  1.1  tsarna 				goto gotError;
    268  1.1  tsarna 				}
    269  1.1  tsarna 			ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
    270  1.1  tsarna 			if (ifi->ifi_addr == NULL) {
    271  1.1  tsarna 				goto gotError;
    272  1.1  tsarna 				}
    273  1.1  tsarna 			memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
    274  1.1  tsarna 
    275  1.1  tsarna 			/* Add netmask of the interface */
    276  1.1  tsarna 			char ipv6addr[INET6_ADDRSTRLEN];
    277  1.1  tsarna 			plen_to_mask(plen, ipv6addr);
    278  1.1  tsarna 			ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
    279  1.1  tsarna 			if (ifi->ifi_addr == NULL) {
    280  1.1  tsarna 				goto gotError;
    281  1.1  tsarna 				}
    282  1.1  tsarna 			sin6=calloc(1, sizeof(struct sockaddr_in6));
    283  1.1  tsarna 			addrptr=calloc(1, sizeof(struct in6_addr));
    284  1.1  tsarna 			inet_pton(family, ipv6addr, addrptr);
    285  1.1  tsarna 			sin6->sin6_family=family;
    286  1.1  tsarna 			sin6->sin6_addr=*addrptr;
    287  1.1  tsarna 			sin6->sin6_scope_id=scope;
    288  1.1  tsarna 			memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
    289  1.1  tsarna 			free(sin6);
    290  1.1  tsarna 
    291  1.1  tsarna 
    292  1.1  tsarna 			/* Add interface name */
    293  1.1  tsarna 			memcpy(ifi->ifi_name, ifname, IFI_NAME);
    294  1.1  tsarna 
    295  1.1  tsarna 			/* Add interface index */
    296  1.1  tsarna 			ifi->ifi_index = index;
    297  1.1  tsarna 
    298  1.1  tsarna 			/* If interface is in /proc then it is up*/
    299  1.1  tsarna 			ifi->ifi_flags = IFF_UP;
    300  1.1  tsarna 
    301  1.1  tsarna 			freeaddrinfo(res0);
    302  1.1  tsarna 			res0=NULL;
    303  1.1  tsarna 			}
    304  1.1  tsarna 		}
    305  1.1  tsarna 	goto done;
    306  1.1  tsarna 
    307  1.1  tsarna 	gotError:
    308  1.1  tsarna 	if (ifihead != NULL) {
    309  1.1  tsarna 		free_ifi_info(ifihead);
    310  1.1  tsarna 		ifihead = NULL;
    311  1.1  tsarna 		}
    312  1.1  tsarna 	if (res0 != NULL) {
    313  1.1  tsarna 		freeaddrinfo(res0);
    314  1.1  tsarna 		res0=NULL;
    315  1.1  tsarna 		}
    316  1.1  tsarna 	done:
    317  1.1  tsarna 	return(ifihead);    /* pointer to first structure in linked list */
    318  1.1  tsarna 	}
    319  1.1  tsarna #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
    320  1.1  tsarna 
    321  1.1  tsarna struct ifi_info *get_ifi_info(int family, int doaliases)
    322  1.1  tsarna {
    323  1.1  tsarna     int                 junk;
    324  1.1  tsarna     struct ifi_info     *ifi, *ifihead, **ifipnext;
    325  1.1  tsarna     int                 sockfd, sockf6, len, lastlen, flags, myflags;
    326  1.1  tsarna #ifdef NOT_HAVE_IF_NAMETOINDEX
    327  1.1  tsarna     int                 index = 200;
    328  1.1  tsarna #endif
    329  1.1  tsarna     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
    330  1.1  tsarna     struct ifconf       ifc;
    331  1.1  tsarna     struct ifreq        *ifr, ifrcopy;
    332  1.1  tsarna     struct sockaddr_in  *sinptr;
    333  1.1  tsarna 
    334  1.1  tsarna #if defined(AF_INET6) && HAVE_IPV6
    335  1.1  tsarna     struct sockaddr_in6 *sinptr6;
    336  1.1  tsarna #endif
    337  1.1  tsarna 
    338  1.1  tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
    339  1.1  tsarna  if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
    340  1.1  tsarna #endif
    341  1.1  tsarna 
    342  1.1  tsarna 	sockfd = -1;
    343  1.1  tsarna     sockf6 = -1;
    344  1.1  tsarna     buf = NULL;
    345  1.1  tsarna     ifihead = NULL;
    346  1.1  tsarna 
    347  1.1  tsarna     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    348  1.1  tsarna     if (sockfd < 0) {
    349  1.1  tsarna         goto gotError;
    350  1.1  tsarna     }
    351  1.1  tsarna 
    352  1.1  tsarna     lastlen = 0;
    353  1.1  tsarna     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
    354  1.1  tsarna     for ( ; ; ) {
    355  1.1  tsarna         buf = (char*)malloc(len);
    356  1.1  tsarna         if (buf == NULL) {
    357  1.1  tsarna             goto gotError;
    358  1.1  tsarna         }
    359  1.1  tsarna         ifc.ifc_len = len;
    360  1.1  tsarna         ifc.ifc_buf = buf;
    361  1.1  tsarna         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
    362  1.1  tsarna             if (errno != EINVAL || lastlen != 0) {
    363  1.1  tsarna                 goto gotError;
    364  1.1  tsarna             }
    365  1.1  tsarna         } else {
    366  1.1  tsarna             if (ifc.ifc_len == lastlen)
    367  1.1  tsarna                 break;      /* success, len has not changed */
    368  1.1  tsarna             lastlen = ifc.ifc_len;
    369  1.1  tsarna         }
    370  1.1  tsarna         len += 10 * sizeof(struct ifreq);   /* increment */
    371  1.1  tsarna         free(buf);
    372  1.1  tsarna     }
    373  1.1  tsarna     ifihead = NULL;
    374  1.1  tsarna     ifipnext = &ifihead;
    375  1.1  tsarna     lastname[0] = 0;
    376  1.1  tsarna /* end get_ifi_info1 */
    377  1.1  tsarna 
    378  1.1  tsarna /* include get_ifi_info2 */
    379  1.1  tsarna     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
    380  1.1  tsarna         ifr = (struct ifreq *) ptr;
    381  1.1  tsarna 
    382  1.1  tsarna         /* Advance to next one in buffer */
    383  1.1  tsarna         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
    384  1.1  tsarna             ptr += sizeof(struct ifreq);
    385  1.1  tsarna         else
    386  1.1  tsarna             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
    387  1.1  tsarna 
    388  1.1  tsarna //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
    389  1.1  tsarna 
    390  1.1  tsarna         if (ifr->ifr_addr.sa_family != family)
    391  1.1  tsarna             continue;   /* ignore if not desired address family */
    392  1.1  tsarna 
    393  1.1  tsarna         myflags = 0;
    394  1.1  tsarna         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
    395  1.1  tsarna             *cptr = 0;      /* replace colon will null */
    396  1.1  tsarna         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
    397  1.1  tsarna             if (doaliases == 0)
    398  1.1  tsarna                 continue;   /* already processed this interface */
    399  1.1  tsarna             myflags = IFI_ALIAS;
    400  1.1  tsarna         }
    401  1.1  tsarna         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
    402  1.1  tsarna 
    403  1.1  tsarna         ifrcopy = *ifr;
    404  1.1  tsarna         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
    405  1.1  tsarna             goto gotError;
    406  1.1  tsarna         }
    407  1.1  tsarna 
    408  1.1  tsarna         flags = ifrcopy.ifr_flags;
    409  1.1  tsarna         if ((flags & IFF_UP) == 0)
    410  1.1  tsarna             continue;   /* ignore if interface not up */
    411  1.1  tsarna 
    412  1.1  tsarna         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
    413  1.1  tsarna         if (ifi == NULL) {
    414  1.1  tsarna             goto gotError;
    415  1.1  tsarna         }
    416  1.1  tsarna         *ifipnext = ifi;            /* prev points to this new one */
    417  1.1  tsarna         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
    418  1.1  tsarna 
    419  1.1  tsarna         ifi->ifi_flags = flags;     /* IFF_xxx values */
    420  1.1  tsarna         ifi->ifi_myflags = myflags; /* IFI_xxx values */
    421  1.1  tsarna #ifndef NOT_HAVE_IF_NAMETOINDEX
    422  1.1  tsarna         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
    423  1.1  tsarna #else
    424  1.1  tsarna         ifrcopy = *ifr;
    425  1.1  tsarna #ifdef SIOCGIFINDEX
    426  1.1  tsarna 		if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
    427  1.1  tsarna             ifi->ifi_index = ifrcopy.ifr_index;
    428  1.1  tsarna         else
    429  1.1  tsarna #endif
    430  1.1  tsarna             ifi->ifi_index = index++;	/* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
    431  1.1  tsarna #endif
    432  1.1  tsarna         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
    433  1.1  tsarna         ifi->ifi_name[IFI_NAME-1] = '\0';
    434  1.1  tsarna /* end get_ifi_info2 */
    435  1.1  tsarna /* include get_ifi_info3 */
    436  1.1  tsarna         switch (ifr->ifr_addr.sa_family) {
    437  1.1  tsarna         case AF_INET:
    438  1.1  tsarna             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
    439  1.1  tsarna             if (ifi->ifi_addr == NULL) {
    440  1.1  tsarna                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
    441  1.1  tsarna                 if (ifi->ifi_addr == NULL) {
    442  1.1  tsarna                     goto gotError;
    443  1.1  tsarna                 }
    444  1.1  tsarna                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
    445  1.1  tsarna 
    446  1.1  tsarna #ifdef  SIOCGIFNETMASK
    447  1.1  tsarna 				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
    448  1.1  tsarna 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
    449  1.1  tsarna 				if (ifi->ifi_netmask == NULL) goto gotError;
    450  1.1  tsarna 				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
    451  1.1  tsarna 				/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
    452  1.1  tsarna #ifndef NOT_HAVE_SA_LEN
    453  1.1  tsarna 				sinptr->sin_len    = sizeof(struct sockaddr_in);
    454  1.1  tsarna #endif
    455  1.1  tsarna 				sinptr->sin_family = AF_INET;
    456  1.1  tsarna 				memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
    457  1.1  tsarna #endif
    458  1.1  tsarna 
    459  1.1  tsarna #ifdef  SIOCGIFBRDADDR
    460  1.1  tsarna                 if (flags & IFF_BROADCAST) {
    461  1.1  tsarna                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
    462  1.1  tsarna                         goto gotError;
    463  1.1  tsarna                     }
    464  1.1  tsarna                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
    465  1.1  tsarna 					/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
    466  1.1  tsarna #ifndef NOT_HAVE_SA_LEN
    467  1.1  tsarna 					sinptr->sin_len    = sizeof( struct sockaddr_in );
    468  1.1  tsarna #endif
    469  1.1  tsarna 					sinptr->sin_family = AF_INET;
    470  1.1  tsarna                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
    471  1.1  tsarna                     if (ifi->ifi_brdaddr == NULL) {
    472  1.1  tsarna                         goto gotError;
    473  1.1  tsarna                     }
    474  1.1  tsarna                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
    475  1.1  tsarna                 }
    476  1.1  tsarna #endif
    477  1.1  tsarna 
    478  1.1  tsarna #ifdef  SIOCGIFDSTADDR
    479  1.1  tsarna                 if (flags & IFF_POINTOPOINT) {
    480  1.1  tsarna                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
    481  1.1  tsarna                         goto gotError;
    482  1.1  tsarna                     }
    483  1.1  tsarna                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
    484  1.1  tsarna                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
    485  1.1  tsarna #ifndef NOT_HAVE_SA_LEN
    486  1.1  tsarna 					sinptr->sin_len    = sizeof( struct sockaddr_in );
    487  1.1  tsarna #endif
    488  1.1  tsarna 					sinptr->sin_family = AF_INET;
    489  1.1  tsarna                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
    490  1.1  tsarna                     if (ifi->ifi_dstaddr == NULL) {
    491  1.1  tsarna                         goto gotError;
    492  1.1  tsarna                     }
    493  1.1  tsarna                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
    494  1.1  tsarna                 }
    495  1.1  tsarna #endif
    496  1.1  tsarna             }
    497  1.1  tsarna             break;
    498  1.1  tsarna 
    499  1.1  tsarna #if defined(AF_INET6) && HAVE_IPV6
    500  1.1  tsarna         case AF_INET6:
    501  1.1  tsarna             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
    502  1.1  tsarna             if (ifi->ifi_addr == NULL) {
    503  1.1  tsarna                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
    504  1.1  tsarna                 if (ifi->ifi_addr == NULL) {
    505  1.1  tsarna                     goto gotError;
    506  1.1  tsarna                 }
    507  1.1  tsarna 
    508  1.1  tsarna                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
    509  1.1  tsarna                 /* We need to strip that out */
    510  1.1  tsarna                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
    511  1.1  tsarna                 	sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
    512  1.1  tsarna                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
    513  1.1  tsarna 
    514  1.1  tsarna #ifdef  SIOCGIFNETMASK_IN6
    515  1.1  tsarna 				{
    516  1.1  tsarna 				struct in6_ifreq ifr6;
    517  1.1  tsarna 				if (sockf6 == -1)
    518  1.1  tsarna 					sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
    519  1.1  tsarna 				memset(&ifr6, 0, sizeof(ifr6));
    520  1.1  tsarna 				memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
    521  1.1  tsarna 				memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
    522  1.1  tsarna 				if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
    523  1.1  tsarna 				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
    524  1.1  tsarna 				if (ifi->ifi_netmask == NULL) goto gotError;
    525  1.1  tsarna 				sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
    526  1.1  tsarna 				memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
    527  1.1  tsarna 				}
    528  1.1  tsarna #endif
    529  1.1  tsarna             }
    530  1.1  tsarna             break;
    531  1.1  tsarna #endif
    532  1.1  tsarna 
    533  1.1  tsarna         default:
    534  1.1  tsarna             break;
    535  1.1  tsarna         }
    536  1.1  tsarna     }
    537  1.1  tsarna     goto done;
    538  1.1  tsarna 
    539  1.1  tsarna gotError:
    540  1.1  tsarna     if (ifihead != NULL) {
    541  1.1  tsarna         free_ifi_info(ifihead);
    542  1.1  tsarna         ifihead = NULL;
    543  1.1  tsarna     }
    544  1.1  tsarna 
    545  1.1  tsarna done:
    546  1.1  tsarna     if (buf != NULL) {
    547  1.1  tsarna         free(buf);
    548  1.1  tsarna     }
    549  1.1  tsarna     if (sockfd != -1) {
    550  1.1  tsarna         junk = close(sockfd);
    551  1.1  tsarna         assert(junk == 0);
    552  1.1  tsarna     }
    553  1.1  tsarna     if (sockf6 != -1) {
    554  1.1  tsarna         junk = close(sockf6);
    555  1.1  tsarna         assert(junk == 0);
    556  1.1  tsarna     }
    557  1.1  tsarna     return(ifihead);    /* pointer to first structure in linked list */
    558  1.1  tsarna }
    559  1.1  tsarna /* end get_ifi_info3 */
    560  1.1  tsarna 
    561  1.1  tsarna /* include free_ifi_info */
    562  1.1  tsarna void
    563  1.1  tsarna free_ifi_info(struct ifi_info *ifihead)
    564  1.1  tsarna {
    565  1.1  tsarna     struct ifi_info *ifi, *ifinext;
    566  1.1  tsarna 
    567  1.1  tsarna     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
    568  1.1  tsarna         if (ifi->ifi_addr != NULL)
    569  1.1  tsarna             free(ifi->ifi_addr);
    570  1.1  tsarna         if (ifi->ifi_netmask != NULL)
    571  1.1  tsarna             free(ifi->ifi_netmask);
    572  1.1  tsarna         if (ifi->ifi_brdaddr != NULL)
    573  1.1  tsarna             free(ifi->ifi_brdaddr);
    574  1.1  tsarna         if (ifi->ifi_dstaddr != NULL)
    575  1.1  tsarna             free(ifi->ifi_dstaddr);
    576  1.1  tsarna         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
    577  1.1  tsarna         free(ifi);                  /* the ifi_info{} itself */
    578  1.1  tsarna     }
    579  1.1  tsarna }
    580  1.1  tsarna /* end free_ifi_info */
    581  1.1  tsarna 
    582  1.1  tsarna ssize_t
    583  1.1  tsarna recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
    584  1.1  tsarna                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
    585  1.1  tsarna {
    586  1.1  tsarna     struct msghdr   msg;
    587  1.1  tsarna     struct iovec    iov[1];
    588  1.1  tsarna     ssize_t         n;
    589  1.1  tsarna 
    590  1.1  tsarna #ifdef CMSG_FIRSTHDR
    591  1.1  tsarna     struct cmsghdr  *cmptr;
    592  1.1  tsarna     union {
    593  1.1  tsarna       struct cmsghdr    cm;
    594  1.1  tsarna       char              control[1024];
    595  1.1  tsarna     } control_un;
    596  1.1  tsarna 
    597  1.1  tsarna 	*ttl = 255;			// If kernel fails to provide TTL data then assume the TTL was 255 as it should be
    598  1.1  tsarna 
    599  1.1  tsarna     msg.msg_control = control_un.control;
    600  1.1  tsarna     msg.msg_controllen = sizeof(control_un.control);
    601  1.1  tsarna     msg.msg_flags = 0;
    602  1.1  tsarna #else
    603  1.1  tsarna     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
    604  1.1  tsarna #endif /* CMSG_FIRSTHDR */
    605  1.1  tsarna 
    606  1.1  tsarna     msg.msg_name = (char *) sa;
    607  1.1  tsarna     msg.msg_namelen = *salenptr;
    608  1.1  tsarna     iov[0].iov_base = (char *)ptr;
    609  1.1  tsarna     iov[0].iov_len = nbytes;
    610  1.1  tsarna     msg.msg_iov = iov;
    611  1.1  tsarna     msg.msg_iovlen = 1;
    612  1.1  tsarna 
    613  1.1  tsarna     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
    614  1.1  tsarna         return(n);
    615  1.1  tsarna 
    616  1.1  tsarna     *salenptr = msg.msg_namelen;    /* pass back results */
    617  1.1  tsarna     if (pktp) {
    618  1.1  tsarna         /* 0.0.0.0, i/f = -1 */
    619  1.1  tsarna         /* We set the interface to -1 so that the caller can
    620  1.1  tsarna            tell whether we returned a meaningful value or
    621  1.1  tsarna            just some default.  Previously this code just
    622  1.1  tsarna            set the value to 0, but I'm concerned that 0
    623  1.1  tsarna            might be a valid interface value.
    624  1.1  tsarna         */
    625  1.1  tsarna         memset(pktp, 0, sizeof(struct my_in_pktinfo));
    626  1.1  tsarna         pktp->ipi_ifindex = -1;
    627  1.1  tsarna     }
    628  1.1  tsarna /* end recvfrom_flags1 */
    629  1.1  tsarna 
    630  1.1  tsarna /* include recvfrom_flags2 */
    631  1.1  tsarna #ifndef CMSG_FIRSTHDR
    632  1.1  tsarna 	#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
    633  1.1  tsarna     *flagsp = 0;                    /* pass back results */
    634  1.1  tsarna     return(n);
    635  1.1  tsarna #else
    636  1.1  tsarna 
    637  1.1  tsarna     *flagsp = msg.msg_flags;        /* pass back results */
    638  1.1  tsarna     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
    639  1.1  tsarna         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
    640  1.1  tsarna         return(n);
    641  1.1  tsarna 
    642  1.1  tsarna     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
    643  1.1  tsarna          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
    644  1.1  tsarna 
    645  1.1  tsarna #ifdef  IP_PKTINFO
    646  1.1  tsarna #if in_pktinfo_definition_is_missing
    647  1.1  tsarna struct in_pktinfo
    648  1.1  tsarna {
    649  1.1  tsarna         int             ipi_ifindex;
    650  1.1  tsarna         struct in_addr  ipi_spec_dst;
    651  1.1  tsarna         struct in_addr  ipi_addr;
    652  1.1  tsarna };
    653  1.1  tsarna #endif
    654  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    655  1.1  tsarna             cmptr->cmsg_type == IP_PKTINFO) {
    656  1.1  tsarna             struct in_pktinfo *tmp;
    657  1.1  tsarna             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    658  1.1  tsarna 
    659  1.1  tsarna             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
    660  1.1  tsarna             sin->sin_family = AF_INET;
    661  1.1  tsarna             sin->sin_addr = tmp->ipi_addr;
    662  1.1  tsarna             sin->sin_port = 0;
    663  1.1  tsarna             pktp->ipi_ifindex = tmp->ipi_ifindex;
    664  1.1  tsarna             continue;
    665  1.1  tsarna         }
    666  1.1  tsarna #endif
    667  1.1  tsarna 
    668  1.1  tsarna #ifdef  IP_RECVDSTADDR
    669  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    670  1.1  tsarna             cmptr->cmsg_type == IP_RECVDSTADDR) {
    671  1.1  tsarna             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    672  1.1  tsarna 
    673  1.1  tsarna             sin->sin_family = AF_INET;
    674  1.1  tsarna             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
    675  1.1  tsarna             sin->sin_port = 0;
    676  1.1  tsarna             continue;
    677  1.1  tsarna         }
    678  1.1  tsarna #endif
    679  1.1  tsarna 
    680  1.1  tsarna #ifdef  IP_RECVIF
    681  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    682  1.1  tsarna             cmptr->cmsg_type == IP_RECVIF) {
    683  1.1  tsarna             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
    684  1.1  tsarna #ifndef HAVE_BROKEN_RECVIF_NAME
    685  1.1  tsarna             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
    686  1.1  tsarna             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
    687  1.1  tsarna #endif
    688  1.1  tsarna             pktp->ipi_ifindex = sdl->sdl_index;
    689  1.1  tsarna #ifdef HAVE_BROKEN_RECVIF_NAME
    690  1.1  tsarna 			if (sdl->sdl_index == 0) {
    691  1.1  tsarna 				pktp->ipi_ifindex = *(uint_t*)sdl;
    692  1.1  tsarna 			}
    693  1.1  tsarna #endif
    694  1.1  tsarna             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
    695  1.1  tsarna             // null terminated because of memset above
    696  1.1  tsarna             continue;
    697  1.1  tsarna         }
    698  1.1  tsarna #endif
    699  1.1  tsarna 
    700  1.1  tsarna #ifdef  IP_RECVTTL
    701  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    702  1.1  tsarna             cmptr->cmsg_type == IP_RECVTTL) {
    703  1.1  tsarna 			*ttl = *(u_char*)CMSG_DATA(cmptr);
    704  1.1  tsarna             continue;
    705  1.1  tsarna         }
    706  1.1  tsarna         else if (cmptr->cmsg_level == IPPROTO_IP &&
    707  1.1  tsarna             cmptr->cmsg_type == IP_TTL) {		// some implementations seem to send IP_TTL instead of IP_RECVTTL
    708  1.1  tsarna 			*ttl = *(int*)CMSG_DATA(cmptr);
    709  1.1  tsarna             continue;
    710  1.1  tsarna         }
    711  1.1  tsarna #endif
    712  1.1  tsarna 
    713  1.1  tsarna #if defined(IPV6_PKTINFO) && HAVE_IPV6
    714  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    715  1.1  tsarna             cmptr->cmsg_type == IPV6_PKTINFO) {
    716  1.1  tsarna             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
    717  1.1  tsarna 			struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
    718  1.1  tsarna 
    719  1.1  tsarna             sin6->sin6_family   = AF_INET6;
    720  1.1  tsarna #ifndef NOT_HAVE_SA_LEN
    721  1.1  tsarna             sin6->sin6_len      = sizeof(*sin6);
    722  1.1  tsarna #endif
    723  1.1  tsarna             sin6->sin6_addr     = ip6_info->ipi6_addr;
    724  1.1  tsarna             sin6->sin6_flowinfo = 0;
    725  1.1  tsarna             sin6->sin6_scope_id = 0;
    726  1.1  tsarna             sin6->sin6_port     = 0;
    727  1.1  tsarna 			pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
    728  1.1  tsarna             continue;
    729  1.1  tsarna         }
    730  1.1  tsarna #endif
    731  1.1  tsarna 
    732  1.1  tsarna #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
    733  1.1  tsarna         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    734  1.1  tsarna             cmptr->cmsg_type == IPV6_HOPLIMIT) {
    735  1.1  tsarna 			*ttl = *(int*)CMSG_DATA(cmptr);
    736  1.1  tsarna             continue;
    737  1.1  tsarna         }
    738  1.1  tsarna #endif
    739  1.1  tsarna         assert(0);  // unknown ancillary data
    740  1.1  tsarna     }
    741  1.1  tsarna     return(n);
    742  1.1  tsarna #endif /* CMSG_FIRSTHDR */
    743  1.1  tsarna }
    744  1.1  tsarna 
    745  1.1  tsarna // **********************************************************************************************
    746  1.1  tsarna 
    747  1.1  tsarna // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
    748  1.1  tsarna // Returns 0 on success, -1 on failure.
    749  1.1  tsarna 
    750  1.1  tsarna #ifdef NOT_HAVE_DAEMON
    751  1.1  tsarna #include <fcntl.h>
    752  1.1  tsarna #include <sys/stat.h>
    753  1.1  tsarna #include <sys/signal.h>
    754  1.1  tsarna 
    755  1.1  tsarna int daemon(int nochdir, int noclose)
    756  1.1  tsarna     {
    757  1.1  tsarna 	switch (fork())
    758  1.1  tsarna 		{
    759  1.1  tsarna 		case -1: return (-1);	// Fork failed
    760  1.1  tsarna 		case 0:  break;			// Child -- continue
    761  1.1  tsarna 		default: _exit(0);		// Parent -- exit
    762  1.1  tsarna 		}
    763  1.1  tsarna 
    764  1.1  tsarna 	if (setsid() == -1) return(-1);
    765  1.1  tsarna 
    766  1.1  tsarna 	signal(SIGHUP, SIG_IGN);
    767  1.1  tsarna 
    768  1.1  tsarna 	switch (fork())				// Fork again, primarily for reasons of Unix trivia
    769  1.1  tsarna 		{
    770  1.1  tsarna 		case -1: return (-1);	// Fork failed
    771  1.1  tsarna 		case 0:  break;			// Child -- continue
    772  1.1  tsarna 		default: _exit(0);		// Parent -- exit
    773  1.1  tsarna 		}
    774  1.1  tsarna 
    775  1.1  tsarna 	if (!nochdir) (void)chdir("/");
    776  1.1  tsarna 	umask(0);
    777  1.1  tsarna 
    778  1.1  tsarna 	if (!noclose)
    779  1.1  tsarna 		{
    780  1.1  tsarna 		int fd = open("/dev/null", O_RDWR, 0);
    781  1.1  tsarna 		if (fd != -1)
    782  1.1  tsarna 			{
    783  1.1  tsarna 			// Avoid unnecessarily duplicating a file descriptor to itself
    784  1.1  tsarna 			if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
    785  1.1  tsarna 			if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
    786  1.1  tsarna 			if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
    787  1.1  tsarna 			if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
    788  1.1  tsarna 				(void)close (fd);
    789  1.1  tsarna 			}
    790  1.1  tsarna 		}
    791  1.1  tsarna 	return (0);
    792  1.1  tsarna     }
    793  1.1  tsarna #endif /* NOT_HAVE_DAEMON */
    794