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