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 #if defined(__FreeBSD__) || defined(__DragonFly__)
59 #include <net/if_var.h>
60 #endif
61 #include <netinet/in_var.h>
62 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
63 #endif
64 
65 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
66 #include <netdb.h>
67 #include <arpa/inet.h>
68 
69 /* Converts a prefix length to IPv6 network mask */
plen_to_mask(int plen,char * addr)70 void plen_to_mask(int plen, char *addr) {
71     int i;
72     int colons=7; /* Number of colons in IPv6 address */
73     int bits_in_block=16; /* Bits per IPv6 block */
74     for(i=0; i<=colons; i++) {
75         int block, ones=0xffff, ones_in_block;
76         if (plen>bits_in_block) ones_in_block=bits_in_block;
77         else ones_in_block=plen;
78         block = ones & (ones << (bits_in_block-ones_in_block));
79         i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
80         plen -= ones_in_block;
81     }
82 }
83 
84 /* Gets IPv6 interface information from the /proc filesystem in linux*/
get_ifi_info_linuxv6(int family,int doaliases)85 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
86 {
87     struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
88     FILE *fp = NULL;
89     char addr[8][5];
90     int flags, myflags, index, plen, scope;
91     char ifname[9], lastname[IFNAMSIZ];
92     char addr6[32+7+1]; /* don't forget the seven ':' */
93     struct addrinfo hints, *res0;
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             memcpy(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_netmask == NULL) {
154                 goto gotError;
155             }
156 
157             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family;
158             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
159             inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
160 
161             /* Add interface name */
162             memcpy(ifi->ifi_name, ifname, IFI_NAME);
163 
164             /* Add interface index */
165             ifi->ifi_index = index;
166 
167             /* Add interface flags*/
168             memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
169             if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
170                 if (errno == EADDRNOTAVAIL) {
171                     /*
172                      * If the main interface is configured with no IP address but
173                      * an alias interface exists with an IP address, you get
174                      * EADDRNOTAVAIL for the main interface
175                      */
176                     free(ifi->ifi_addr);
177                     free(ifi->ifi_netmask);
178                     free(ifi);
179                     ifipnext  = ifiptr;
180                     *ifipnext = ifipold;
181                     continue;
182                 } else {
183                     goto gotError;
184                 }
185             }
186             ifi->ifi_flags = ifr.ifr_flags;
187             freeaddrinfo(res0);
188             res0=NULL;
189         }
190     }
191     goto done;
192 
193 gotError:
194     if (ifihead != NULL) {
195         free_ifi_info(ifihead);
196         ifihead = NULL;
197     }
198     if (res0 != NULL) {
199         freeaddrinfo(res0);
200         res0=NULL;
201     }
202 done:
203     if (sockfd != -1) {
204         int rv;
205         rv = close(sockfd);
206         assert(rv == 0);
207     }
208     if (fp != NULL) {
209         fclose(fp);
210     }
211     return(ifihead);    /* pointer to first structure in linked list */
212 }
213 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
214 
get_ifi_info(int family,int doaliases)215 struct ifi_info *get_ifi_info(int family, int doaliases)
216 {
217     int junk;
218     struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
219     int sockfd, sockf6, len, lastlen, flags, myflags;
220 #ifdef NOT_HAVE_IF_NAMETOINDEX
221     int index = 200;
222 #endif
223     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
224     struct ifconf ifc;
225     struct ifreq        *ifr, ifrcopy;
226     struct sockaddr_in  *sinptr;
227 
228 #if defined(AF_INET6) && HAVE_IPV6
229     struct sockaddr_in6 *sinptr6;
230 #endif
231 
232 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
233     if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
234 #endif
235 
236     sockfd = -1;
237     sockf6 = -1;
238     buf = NULL;
239     ifihead = NULL;
240 
241     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
242     if (sockfd < 0) {
243         goto gotError;
244     }
245 
246     lastlen = 0;
247     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
248     for ( ; ; ) {
249         buf = (char*)malloc(len);
250         if (buf == NULL) {
251             goto gotError;
252         }
253         ifc.ifc_len = len;
254         ifc.ifc_buf = buf;
255         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
256             if (errno != EINVAL || lastlen != 0) {
257                 goto gotError;
258             }
259         } else {
260             if (ifc.ifc_len == lastlen)
261                 break;      /* success, len has not changed */
262             lastlen = ifc.ifc_len;
263         }
264         len += 10 * sizeof(struct ifreq);   /* increment */
265         free(buf);
266     }
267     ifihead = NULL;
268     ifipnext = &ifihead;
269     lastname[0] = 0;
270 /* end get_ifi_info1 */
271 
272 /* include get_ifi_info2 */
273     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
274         ifr = (struct ifreq *) ptr;
275 
276         /* Advance to next one in buffer */
277         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
278             ptr += sizeof(struct ifreq);
279         else
280             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
281 
282 //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
283 
284         if (ifr->ifr_addr.sa_family != family)
285             continue;   /* ignore if not desired address family */
286 
287         myflags = 0;
288         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
289             *cptr = 0;      /* replace colon will null */
290         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
291             if (doaliases == 0)
292                 continue;   /* already processed this interface */
293             myflags = IFI_ALIAS;
294         }
295         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
296 
297         ifrcopy = *ifr;
298         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
299             goto gotError;
300         }
301 
302         flags = ifrcopy.ifr_flags;
303         if ((flags & IFF_UP) == 0)
304             continue;   /* ignore if interface not up */
305 
306 
307 #ifdef notdef
308 	/*
309 	 * Include the loopback so that we return at least one
310 	 * address, so that mdnsd does not exit before we get
311 	 * a dhcp address
312 	 */
313 	if ((flags & IFF_LOOPBACK))
314 	    continue;	/* ignore loopback interfaces */
315 #endif
316 
317 	/* Skip addresses we can't use */
318 #ifdef SIOCGIFAFLAG_IN
319 	if (ifr->ifr_addr.sa_family == AF_INET) {
320 		ifrcopy = *ifr;
321 		if (ioctl(sockfd, SIOCGIFAFLAG_IN, &ifrcopy) < 0)
322 			goto gotError;
323 		if (ifrcopy.ifr_addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
324 			continue;
325 	}
326 #endif
327 #ifdef SIOCGIFAFLAG_IN6
328         if (ifr->ifr_addr.sa_family == AF_INET6) {
329 		struct in6_ifreq ifr6;
330 
331 		if (sockf6 == -1)
332 			sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
333 		memset(&ifr6, 0, sizeof(ifr6));
334 		memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name));
335 		memcpy(&ifr6.ifr_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_addr));
336 		if (ioctl(sockf6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
337 			goto gotError;
338 		if (ifr6.ifr_ifru.ifru_flags6 &
339 		    (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
340 			continue;
341 	}
342 #endif
343 
344         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
345         if (ifi == NULL) {
346             goto gotError;
347         }
348         ifipold   = *ifipnext;       /* need this later */
349         ifiptr    = ifipnext;
350         *ifipnext = ifi;             /* prev points to this new one */
351         ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
352 
353         ifi->ifi_flags = flags;     /* IFF_xxx values */
354         ifi->ifi_myflags = myflags; /* IFI_xxx values */
355 #ifndef NOT_HAVE_IF_NAMETOINDEX
356         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
357 #else
358         ifrcopy = *ifr;
359 #ifdef SIOCGIFINDEX
360         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
361             ifi->ifi_index = ifrcopy.ifr_index;
362         else
363 #endif
364         ifi->ifi_index = index++;       /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
365 #endif
366         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
367         ifi->ifi_name[IFI_NAME-1] = '\0';
368 /* end get_ifi_info2 */
369 /* include get_ifi_info3 */
370         switch (ifr->ifr_addr.sa_family) {
371         case AF_INET:
372             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
373             if (ifi->ifi_addr == NULL) {
374                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
375                 if (ifi->ifi_addr == NULL) {
376                     goto gotError;
377                 }
378                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
379 
380 #ifdef  SIOCGIFNETMASK
381                 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
382                     if (errno == EADDRNOTAVAIL) {
383                         /*
384                          * If the main interface is configured with no IP address but
385                          * an alias interface exists with an IP address, you get
386                          * EADDRNOTAVAIL for the main interface
387                          */
388                         free(ifi->ifi_addr);
389                         free(ifi);
390                         ifipnext  = ifiptr;
391                         *ifipnext = ifipold;
392                         continue;
393                     } else {
394                         goto gotError;
395                     }
396                 }
397 
398                 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
399                 if (ifi->ifi_netmask == NULL) goto gotError;
400                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
401                 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
402 #ifndef NOT_HAVE_SA_LEN
403                 sinptr->sin_len    = sizeof(struct sockaddr_in);
404 #endif
405                 sinptr->sin_family = AF_INET;
406                 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
407 #endif
408 
409 #ifdef  SIOCGIFBRDADDR
410                 if (flags & IFF_BROADCAST) {
411                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
412                         goto gotError;
413                     }
414                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
415                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
416 #ifndef NOT_HAVE_SA_LEN
417                     sinptr->sin_len    = sizeof( struct sockaddr_in );
418 #endif
419                     sinptr->sin_family = AF_INET;
420                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
421                     if (ifi->ifi_brdaddr == NULL) {
422                         goto gotError;
423                     }
424                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
425                 }
426 #endif
427 
428 #ifdef  SIOCGIFDSTADDR
429                 if (flags & IFF_POINTOPOINT) {
430                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
431                         goto gotError;
432                     }
433                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
434                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
435 #ifndef NOT_HAVE_SA_LEN
436                     sinptr->sin_len    = sizeof( struct sockaddr_in );
437 #endif
438                     sinptr->sin_family = AF_INET;
439                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
440                     if (ifi->ifi_dstaddr == NULL) {
441                         goto gotError;
442                     }
443                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
444                 }
445 #endif
446             }
447             break;
448 
449 #if defined(AF_INET6) && HAVE_IPV6
450         case AF_INET6:
451             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
452             if (ifi->ifi_addr == NULL) {
453                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
454                 if (ifi->ifi_addr == NULL) {
455                     goto gotError;
456                 }
457 
458                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
459                 /* We need to strip that out */
460                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
461                     sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
462                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
463 
464 #ifdef  SIOCGIFNETMASK_IN6
465                 {
466                     struct in6_ifreq ifr6;
467                     if (sockf6 == -1)
468                         sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
469                     memset(&ifr6, 0, sizeof(ifr6));
470                     memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
471                     memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
472                     if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
473                         if (errno == EADDRNOTAVAIL) {
474                             /*
475                              * If the main interface is configured with no IP address but
476                              * an alias interface exists with an IP address, you get
477                              * EADDRNOTAVAIL for the main interface
478                              */
479                             free(ifi->ifi_addr);
480                             free(ifi);
481                             ifipnext  = ifiptr;
482                             *ifipnext = ifipold;
483                             continue;
484                         } else {
485                             goto gotError;
486                         }
487                     }
488                     ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
489                     if (ifi->ifi_netmask == NULL) goto gotError;
490                     sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
491                     memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
492                 }
493 #endif
494             }
495             break;
496 #endif
497 
498         default:
499             break;
500         }
501     }
502     goto done;
503 
504 gotError:
505     if (ifihead != NULL) {
506         free_ifi_info(ifihead);
507         ifihead = NULL;
508     }
509 
510 done:
511     if (buf != NULL) {
512         free(buf);
513     }
514     if (sockfd != -1) {
515         junk = close(sockfd);
516         assert(junk == 0);
517     }
518     if (sockf6 != -1) {
519         junk = close(sockf6);
520         assert(junk == 0);
521     }
522     return(ifihead);    /* pointer to first structure in linked list */
523 }
524 /* end get_ifi_info3 */
525 
526 /* include free_ifi_info */
527 void
free_ifi_info(struct ifi_info * ifihead)528 free_ifi_info(struct ifi_info *ifihead)
529 {
530     struct ifi_info *ifi, *ifinext;
531 
532     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
533         if (ifi->ifi_addr != NULL)
534             free(ifi->ifi_addr);
535         if (ifi->ifi_netmask != NULL)
536             free(ifi->ifi_netmask);
537         if (ifi->ifi_brdaddr != NULL)
538             free(ifi->ifi_brdaddr);
539         if (ifi->ifi_dstaddr != NULL)
540             free(ifi->ifi_dstaddr);
541         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
542         free(ifi);                  /* the ifi_info{} itself */
543     }
544 }
545 /* end free_ifi_info */
546 
547 ssize_t
recvfrom_flags(int fd,void * ptr,size_t nbytes,int * flagsp,struct sockaddr * sa,socklen_t * salenptr,struct my_in_pktinfo * pktp,u_char * ttl)548 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
549                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
550 {
551     struct msghdr msg;
552     struct iovec iov[1];
553     ssize_t n;
554 
555 #ifdef CMSG_FIRSTHDR
556     struct cmsghdr  *cmptr;
557     union {
558         struct cmsghdr cm;
559         char control[1024];
560     } control_un;
561 
562     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
563 
564     msg.msg_control = control_un.control;
565     msg.msg_controllen = sizeof(control_un.control);
566     msg.msg_flags = 0;
567 #else
568     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
569 #endif /* CMSG_FIRSTHDR */
570 
571     msg.msg_name = (char *) sa;
572     msg.msg_namelen = *salenptr;
573     iov[0].iov_base = (char *)ptr;
574     iov[0].iov_len = nbytes;
575     msg.msg_iov = iov;
576     msg.msg_iovlen = 1;
577 
578     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
579         return(n);
580 
581     *salenptr = msg.msg_namelen;    /* pass back results */
582     if (pktp) {
583         /* 0.0.0.0, i/f = -1 */
584         /* We set the interface to -1 so that the caller can
585            tell whether we returned a meaningful value or
586            just some default.  Previously this code just
587            set the value to 0, but I'm concerned that 0
588            might be a valid interface value.
589          */
590         memset(pktp, 0, sizeof(struct my_in_pktinfo));
591         pktp->ipi_ifindex = -1;
592     }
593 /* end recvfrom_flags1 */
594 
595 /* include recvfrom_flags2 */
596 #ifndef CMSG_FIRSTHDR
597     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
598     *flagsp = 0;                    /* pass back results */
599     return(n);
600 #else
601 
602     *flagsp = msg.msg_flags;        /* pass back results */
603     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
604         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
605         return(n);
606 
607     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
608          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
609 
610 #ifdef  IP_PKTINFO
611 #if in_pktinfo_definition_is_missing
612         struct in_pktinfo
613         {
614             int ipi_ifindex;
615             struct in_addr ipi_spec_dst;
616             struct in_addr ipi_addr;
617         };
618 #endif
619         if (cmptr->cmsg_level == IPPROTO_IP &&
620             cmptr->cmsg_type == IP_PKTINFO) {
621             struct in_pktinfo *tmp;
622             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
623 
624             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
625             sin->sin_family = AF_INET;
626             sin->sin_addr = tmp->ipi_addr;
627             sin->sin_port = 0;
628             pktp->ipi_ifindex = tmp->ipi_ifindex;
629             continue;
630         }
631 #endif
632 
633 #ifdef  IP_RECVDSTADDR
634         if (cmptr->cmsg_level == IPPROTO_IP &&
635             cmptr->cmsg_type == IP_RECVDSTADDR) {
636             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
637 
638             sin->sin_family = AF_INET;
639             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
640             sin->sin_port = 0;
641             continue;
642         }
643 #endif
644 
645 #ifdef  IP_RECVIF
646         if (cmptr->cmsg_level == IPPROTO_IP &&
647             cmptr->cmsg_type == IP_RECVIF) {
648             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
649 #ifndef HAVE_BROKEN_RECVIF_NAME
650             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
651             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
652 #endif
653             pktp->ipi_ifindex = sdl->sdl_index;
654 #ifdef HAVE_BROKEN_RECVIF_NAME
655             if (sdl->sdl_index == 0) {
656                 pktp->ipi_ifindex = *(uint_t*)sdl;
657             }
658 #endif
659             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
660             // null terminated because of memset above
661             continue;
662         }
663 #endif
664 
665 #ifdef  IP_RECVTTL
666         if (cmptr->cmsg_level == IPPROTO_IP &&
667             cmptr->cmsg_type == IP_RECVTTL) {
668             *ttl = *(u_char*)CMSG_DATA(cmptr);
669             continue;
670         }
671         else if (cmptr->cmsg_level == IPPROTO_IP &&
672                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
673             *ttl = *(int*)CMSG_DATA(cmptr);
674             continue;
675         }
676 #endif
677 
678 #if defined(IPV6_PKTINFO) && HAVE_IPV6
679         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
680             cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
681             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
682             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
683 
684             sin6->sin6_family   = AF_INET6;
685 #ifndef NOT_HAVE_SA_LEN
686             sin6->sin6_len      = sizeof(*sin6);
687 #endif
688             sin6->sin6_addr     = ip6_info->ipi6_addr;
689             sin6->sin6_flowinfo = 0;
690             sin6->sin6_scope_id = 0;
691             sin6->sin6_port     = 0;
692             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
693             continue;
694         }
695 #endif
696 
697 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
698         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
699             cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
700             *ttl = *(int*)CMSG_DATA(cmptr);
701             continue;
702         }
703 #endif
704         assert(0);  // unknown ancillary data
705     }
706     return(n);
707 #endif /* CMSG_FIRSTHDR */
708 }
709 
710 // **********************************************************************************************
711 
712 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
713 // Returns 0 on success, -1 on failure.
714 
715 #ifdef NOT_HAVE_DAEMON
716 #include <fcntl.h>
717 #include <sys/stat.h>
718 #include <sys/signal.h>
719 
daemon(int nochdir,int noclose)720 int daemon(int nochdir, int noclose)
721 {
722     switch (fork())
723     {
724     case -1: return (-1);       // Fork failed
725     case 0:  break;             // Child -- continue
726     default: _exit(0);          // Parent -- exit
727     }
728 
729     if (setsid() == -1) return(-1);
730 
731     signal(SIGHUP, SIG_IGN);
732 
733     switch (fork())             // Fork again, primarily for reasons of Unix trivia
734     {
735     case -1: return (-1);       // Fork failed
736     case 0:  break;             // Child -- continue
737     default: _exit(0);          // Parent -- exit
738     }
739 
740     if (!nochdir) (void)chdir("/");
741     umask(0);
742 
743     if (!noclose)
744     {
745         int fd = open("/dev/null", O_RDWR, 0);
746         if (fd != -1)
747         {
748             // Avoid unnecessarily duplicating a file descriptor to itself
749             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
750             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
751             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
752             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
753                 (void)close (fd);
754         }
755     }
756     return (0);
757 }
758 #endif /* NOT_HAVE_DAEMON */
759