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 !HAVE_SOLARIS
59 #include <net/if_var.h>
60 #else
61 #include <alloca.h>
62 #endif /* !HAVE_SOLARIS */
63 #include <netinet/in_var.h>
64 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
65 #endif
66 
67 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
68 #include <netdb.h>
69 #include <arpa/inet.h>
70 
71 /* Converts a prefix length to IPv6 network mask */
72 void plen_to_mask(int plen, char *addr) {
73     int i;
74     int colons=7; /* Number of colons in IPv6 address */
75     int bits_in_block=16; /* Bits per IPv6 block */
76     for(i=0; i<=colons; i++) {
77         int block, ones=0xffff, ones_in_block;
78         if (plen>bits_in_block) ones_in_block=bits_in_block;
79         else ones_in_block=plen;
80         block = ones & (ones << (bits_in_block-ones_in_block));
81         i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
82         plen -= ones_in_block;
83     }
84 }
85 
86 /* Gets IPv6 interface information from the /proc filesystem in linux*/
87 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
88 {
89     struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
90     FILE *fp = NULL;
91     char addr[8][5];
92     int flags, myflags, index, plen, scope;
93     char ifname[9], lastname[IFNAMSIZ];
94     char addr6[32+7+1]; /* don't forget the seven ':' */
95     struct addrinfo hints, *res0;
96     int err;
97     int sockfd = -1;
98     struct ifreq ifr;
99 
100     res0=NULL;
101     ifihead = NULL;
102     ifipnext = &ifihead;
103     lastname[0] = 0;
104 
105     if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
106         sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
107         if (sockfd < 0) {
108             goto gotError;
109         }
110         while (fscanf(fp,
111                       "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
112                       addr[0],addr[1],addr[2],addr[3],
113                       addr[4],addr[5],addr[6],addr[7],
114                       &index, &plen, &scope, &flags, ifname) != EOF) {
115 
116             myflags = 0;
117             if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
118                 if (doaliases == 0)
119                     continue;   /* already processed this interface */
120                 myflags = IFI_ALIAS;
121             }
122             memcpy(lastname, ifname, IFNAMSIZ);
123             ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
124             if (ifi == NULL) {
125                 goto gotError;
126             }
127 
128             ifipold   = *ifipnext;       /* need this later */
129             ifiptr    = ifipnext;
130             *ifipnext = ifi;            /* prev points to this new one */
131             ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
132 
133             sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
134                     addr[0],addr[1],addr[2],addr[3],
135                     addr[4],addr[5],addr[6],addr[7]);
136 
137             /* Add address of the interface */
138             memset(&hints, 0, sizeof(hints));
139             hints.ai_family = AF_INET6;
140             hints.ai_flags = AI_NUMERICHOST;
141             err = getaddrinfo(addr6, NULL, &hints, &res0);
142             if (err) {
143                 goto gotError;
144             }
145             ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
146             if (ifi->ifi_addr == NULL) {
147                 goto gotError;
148             }
149             memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
150 
151             /* Add netmask of the interface */
152             char ipv6addr[INET6_ADDRSTRLEN];
153             plen_to_mask(plen, ipv6addr);
154             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
155             if (ifi->ifi_netmask == NULL) {
156                 goto gotError;
157             }
158 
159             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family;
160             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
161             inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
162 
163             /* Add interface name */
164             memcpy(ifi->ifi_name, ifname, IFI_NAME);
165 
166             /* Add interface index */
167             ifi->ifi_index = index;
168 
169             /* Add interface flags*/
170             memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
171             if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
172                 if (errno == EADDRNOTAVAIL) {
173                     /*
174                      * If the main interface is configured with no IP address but
175                      * an alias interface exists with an IP address, you get
176                      * EADDRNOTAVAIL for the main interface
177                      */
178                     free(ifi->ifi_addr);
179                     free(ifi->ifi_netmask);
180                     free(ifi);
181                     ifipnext  = ifiptr;
182                     *ifipnext = ifipold;
183                     continue;
184                 } else {
185                     goto gotError;
186                 }
187             }
188             ifi->ifi_flags = ifr.ifr_flags;
189             freeaddrinfo(res0);
190             res0=NULL;
191         }
192     }
193     goto done;
194 
195 gotError:
196     if (ifihead != NULL) {
197         free_ifi_info(ifihead);
198         ifihead = NULL;
199     }
200     if (res0 != NULL) {
201         freeaddrinfo(res0);
202         res0=NULL;
203     }
204 done:
205     if (sockfd != -1) {
206         assert(close(sockfd) == 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 
215 #if HAVE_SOLARIS
216 
217 /*
218  * Converts prefix length to network mask. Assumes
219  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
220  * Unlike plen_to_mask returns netmask in binary form and not
221  * in text form.
222  */
223 static void plen_to_netmask(int prefix, unsigned char *addr) {
224     for (; prefix > 8; prefix -= 8)
225         *addr++ = 0xff;
226     for (; prefix > 0; prefix--)
227         *addr = (*addr >> 1) | 0x80;
228 }
229 
230 /*
231  * This function goes through all the IP interfaces associated with a
232  * physical interface and finds the best matched one for use by mDNS.
233  * Returns NULL when none of the IP interfaces associated with a physical
234  * interface are usable. Otherwise returns the best matched interface
235  * information and a pointer to the best matched lifreq.
236  */
237 struct ifi_info *
238 select_src_ifi_info_solaris(int sockfd, int numifs,
239         struct lifreq *lifrlist, const char *curifname,
240         struct lifreq **best_lifr)
241 {
242     struct lifreq *lifr;
243     struct lifreq lifrcopy;
244     struct ifi_info *ifi;
245     char *chptr;
246     char cmpifname[LIFNAMSIZ];
247     int i;
248     uint64_t best_lifrflags = 0;
249     uint64_t ifflags;
250 
251     *best_lifr = NULL;
252 
253     /*
254      * Check all logical interfaces associated with the physical
255      * interface and figure out which one works best for us.
256      */
257     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
258 
259         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
260             continue; /* skip interface */
261 
262         /* Strip logical interface number before checking ifname */
263         if ((chptr = strchr(cmpifname, ':')) != NULL)
264             *chptr = '\0';
265 
266         /*
267          * Check ifname to see if the logical interface is associated
268          * with the physical interface we are interested in.
269          */
270         if (strcmp(cmpifname, curifname) != 0)
271             continue;
272 
273         lifrcopy = *lifr;
274         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
275             /* interface removed */
276             if (errno == ENXIO)
277                 continue;
278             return(NULL);
279         }
280         ifflags = lifrcopy.lifr_flags;
281 
282         /* ignore address if not up */
283         if ((ifflags & IFF_UP) == 0)
284             continue;
285         /*
286          * Avoid address if any of the following flags are set:
287          *  IFF_NOXMIT: no packets transmitted over interface
288          *  IFF_NOLOCAL: no address
289          *  IFF_PRIVATE: is not advertised
290          */
291         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
292             continue;
293 
294        /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
295         if (lifr->lifr_addr.ss_family == AF_INET) {
296                struct sockaddr_in *sinptr;
297 
298                sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
299                if (sinptr->sin_addr.s_addr == INADDR_ANY)
300                        continue;
301        }
302 
303         if (*best_lifr != NULL) {
304             /*
305              * Check if we found a better interface by checking
306              * the flags. If flags are identical we prefer
307              * the new found interface.
308              */
309             uint64_t diff_flags = best_lifrflags ^ ifflags;
310 
311             /* If interface has a different set of flags */
312             if (diff_flags != 0) {
313                 /* Check flags in increasing order of ones we prefer */
314 
315                 /* Address temporary? */
316                 if ((diff_flags & IFF_TEMPORARY) &&
317                     (ifflags & IFF_TEMPORARY))
318                     continue;
319                 /* Deprecated address? */
320                 if ((diff_flags & IFF_DEPRECATED) &&
321                     (ifflags & IFF_DEPRECATED))
322                     continue;
323                 /* Last best-matched interface address has preferred? */
324                 if ((diff_flags & IFF_PREFERRED) &&
325                     ((ifflags & IFF_PREFERRED) == 0))
326                     continue;
327             }
328         }
329 
330         /* Set best match interface & flags */
331         *best_lifr = lifr;
332         best_lifrflags = ifflags;
333     }
334 
335     if (*best_lifr == NULL)
336         return(NULL);
337 
338     /* Found a match: return the interface information */
339     ifi = calloc(1, sizeof(struct ifi_info));
340     if (ifi == NULL)
341         return(NULL);
342 
343     ifi->ifi_flags = best_lifrflags;
344     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
345     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
346         free(ifi);
347         return(NULL);
348     }
349     return(ifi);
350 }
351 
352 /*
353  * Returns a list of IP interface information on Solaris. The function
354  * returns all IP interfaces on the system with IPv4 address assigned
355  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
356  * when AF_INET6 is passed.
357  */
358 struct ifi_info *get_ifi_info_solaris(int family)
359 {
360     struct ifi_info     *ifi, *ifihead, **ifipnext;
361     int   sockfd;
362     int  len;
363     char  *buf;
364     char *cptr;
365     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
366     struct sockaddr_in *sinptr;
367     struct lifnum lifn;
368     struct lifconf lifc;
369     struct lifreq *lifrp, *best_lifr;
370     struct lifreq lifrcopy;
371     int numifs, nlifr, n;
372 #if defined(AF_INET6) && HAVE_IPV6
373     struct sockaddr_in6 *sinptr6;
374 #endif
375 
376     ifihead = NULL;
377 
378     sockfd = socket(family, SOCK_DGRAM, 0);
379     if (sockfd < 0)
380         goto gotError;
381 
382 again:
383     lifn.lifn_family = family;
384     lifn.lifn_flags = 0;
385     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
386         goto gotError;
387     /*
388      * Pad interface count to detect & retrieve any
389      * additional interfaces between IFNUM & IFCONF calls.
390      */
391     lifn.lifn_count += 4;
392     numifs = lifn.lifn_count;
393     len = numifs * sizeof (struct lifreq);
394     buf = alloca(len);
395 
396     lifc.lifc_family = family;
397     lifc.lifc_len = len;
398     lifc.lifc_buf = buf;
399     lifc.lifc_flags = 0;
400 
401     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
402         goto gotError;
403 
404     nlifr = lifc.lifc_len / sizeof(struct lifreq);
405     if (nlifr >= numifs)
406         goto again;
407 
408     lifrp = lifc.lifc_req;
409     ifipnext = &ifihead;
410 
411     for (n = nlifr; n > 0; n--, lifrp++) {
412 
413         if (lifrp->lifr_addr.ss_family != family)
414             continue;
415 
416         /*
417          * See if we have already processed the interface
418          * by checking the interface names.
419          */
420         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
421             goto gotError;
422         if ((cptr = strchr(ifname, ':')) != NULL)
423             *cptr = '\0';
424 
425         /*
426          * If any of the interfaces found so far share the physical
427          * interface name then we have already processed the interface.
428          */
429         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
430 
431             /* Retrieve physical interface name */
432             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
433 
434             /* Strip logical interface number before checking ifname */
435             if ((cptr = strchr(cmpifname, ':')) != NULL)
436                 *cptr = '\0';
437 
438             if (strcmp(cmpifname, ifname) == 0)
439                 break;
440         }
441         if (ifi != NULL)
442             continue; /* already processed */
443 
444         /*
445          * New interface, find the one with the preferred source
446          * address for our use in Multicast DNS.
447          */
448         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
449             lifc.lifc_req, ifname, &best_lifr)) == NULL)
450             continue;
451 
452         assert(best_lifr != NULL);
453         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
454                (best_lifr->lifr_addr.ss_family == AF_INET));
455 
456         switch (best_lifr->lifr_addr.ss_family) {
457 
458 #if defined(AF_INET6) && HAVE_IPV6
459         case AF_INET6:
460             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
461             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
462             if (ifi->ifi_addr == NULL)
463                 goto gotError;
464             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
465 
466             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
467             if (ifi->ifi_netmask == NULL)
468                 goto gotError;
469             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
470             sinptr6->sin6_family = AF_INET6;
471             plen_to_netmask(best_lifr->lifr_addrlen,
472                     (unsigned char *) &(sinptr6->sin6_addr));
473             break;
474 #endif
475 
476         case AF_INET:
477             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
478             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
479             if (ifi->ifi_addr == NULL)
480                 goto gotError;
481 
482             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
483 
484             lifrcopy = *best_lifr;
485             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
486                 /* interface removed */
487                 if (errno == ENXIO) {
488                     free(ifi->ifi_addr);
489                     free(ifi);
490                     continue;
491                 }
492                 goto gotError;
493             }
494 
495             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
496             if (ifi->ifi_netmask == NULL)
497                 goto gotError;
498             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
499             sinptr->sin_family = AF_INET;
500             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
501             break;
502 
503         default:
504             /* never reached */
505             break;
506         }
507 
508         *ifipnext = ifi;            /* prev points to this new one */
509         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
510     }
511 
512     (void) close(sockfd);
513     return(ifihead);    /* pointer to first structure in linked list */
514 
515 gotError:
516     if (sockfd != -1)
517         (void) close(sockfd);
518     if (ifihead != NULL)
519         free_ifi_info(ifihead);
520     return(NULL);
521 }
522 
523 #endif /* HAVE_SOLARIS */
524 
525 struct ifi_info *get_ifi_info(int family, int doaliases)
526 {
527     int junk;
528     struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
529     int sockfd, sockf6, len, lastlen, flags, myflags;
530 #ifdef NOT_HAVE_IF_NAMETOINDEX
531     int index = 200;
532 #endif
533     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
534     struct ifconf ifc;
535     struct ifreq        *ifr, ifrcopy;
536     struct sockaddr_in  *sinptr;
537 
538 #if defined(AF_INET6) && HAVE_IPV6
539     struct sockaddr_in6 *sinptr6;
540 #endif
541 
542 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
543     if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
544 #elif HAVE_SOLARIS
545     return get_ifi_info_solaris(family);
546 #endif
547 
548     sockfd = -1;
549     sockf6 = -1;
550     buf = NULL;
551     ifihead = NULL;
552 
553     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
554     if (sockfd < 0) {
555         goto gotError;
556     }
557 
558     lastlen = 0;
559     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
560     for ( ; ; ) {
561         buf = (char*)malloc(len);
562         if (buf == NULL) {
563             goto gotError;
564         }
565         ifc.ifc_len = len;
566         ifc.ifc_buf = buf;
567         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
568             if (errno != EINVAL || lastlen != 0) {
569                 goto gotError;
570             }
571         } else {
572             if (ifc.ifc_len == lastlen)
573                 break;      /* success, len has not changed */
574             lastlen = ifc.ifc_len;
575         }
576         len += 10 * sizeof(struct ifreq);   /* increment */
577         free(buf);
578     }
579     ifihead = NULL;
580     ifipnext = &ifihead;
581     lastname[0] = 0;
582 /* end get_ifi_info1 */
583 
584 /* include get_ifi_info2 */
585     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
586         ifr = (struct ifreq *) ptr;
587 
588         /* Advance to next one in buffer */
589         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
590             ptr += sizeof(struct ifreq);
591         else
592             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
593 
594 //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
595 
596         if (ifr->ifr_addr.sa_family != family)
597             continue;   /* ignore if not desired address family */
598 
599         myflags = 0;
600         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
601             *cptr = 0;      /* replace colon will null */
602         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
603             if (doaliases == 0)
604                 continue;   /* already processed this interface */
605             myflags = IFI_ALIAS;
606         }
607         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
608 
609         ifrcopy = *ifr;
610         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
611             goto gotError;
612         }
613 
614         flags = ifrcopy.ifr_flags;
615         if ((flags & IFF_UP) == 0)
616             continue;   /* ignore if interface not up */
617 
618         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
619         if (ifi == NULL) {
620             goto gotError;
621         }
622         ifipold   = *ifipnext;       /* need this later */
623         ifiptr    = ifipnext;
624         *ifipnext = ifi;             /* prev points to this new one */
625         ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
626 
627         ifi->ifi_flags = flags;     /* IFF_xxx values */
628         ifi->ifi_myflags = myflags; /* IFI_xxx values */
629 #ifndef NOT_HAVE_IF_NAMETOINDEX
630         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
631 #else
632         ifrcopy = *ifr;
633 #ifdef SIOCGIFINDEX
634         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
635             ifi->ifi_index = ifrcopy.ifr_index;
636         else
637 #endif
638         ifi->ifi_index = index++;       /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
639 #endif
640         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
641         ifi->ifi_name[IFI_NAME-1] = '\0';
642 /* end get_ifi_info2 */
643 /* include get_ifi_info3 */
644         switch (ifr->ifr_addr.sa_family) {
645         case AF_INET:
646             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
647             if (ifi->ifi_addr == NULL) {
648                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
649                 if (ifi->ifi_addr == NULL) {
650                     goto gotError;
651                 }
652                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
653 
654 #ifdef  SIOCGIFNETMASK
655                 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
656                     if (errno == EADDRNOTAVAIL) {
657                         /*
658                          * If the main interface is configured with no IP address but
659                          * an alias interface exists with an IP address, you get
660                          * EADDRNOTAVAIL for the main interface
661                          */
662                         free(ifi->ifi_addr);
663                         free(ifi);
664                         ifipnext  = ifiptr;
665                         *ifipnext = ifipold;
666                         continue;
667                     } else {
668                         goto gotError;
669                     }
670                 }
671 
672                 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
673                 if (ifi->ifi_netmask == NULL) goto gotError;
674                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
675                 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
676 #ifndef NOT_HAVE_SA_LEN
677                 sinptr->sin_len    = sizeof(struct sockaddr_in);
678 #endif
679                 sinptr->sin_family = AF_INET;
680                 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
681 #endif
682 
683 #ifdef  SIOCGIFBRDADDR
684                 if (flags & IFF_BROADCAST) {
685                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
686                         goto gotError;
687                     }
688                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
689                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
690 #ifndef NOT_HAVE_SA_LEN
691                     sinptr->sin_len    = sizeof( struct sockaddr_in );
692 #endif
693                     sinptr->sin_family = AF_INET;
694                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
695                     if (ifi->ifi_brdaddr == NULL) {
696                         goto gotError;
697                     }
698                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
699                 }
700 #endif
701 
702 #ifdef  SIOCGIFDSTADDR
703                 if (flags & IFF_POINTOPOINT) {
704                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
705                         goto gotError;
706                     }
707                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
708                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
709 #ifndef NOT_HAVE_SA_LEN
710                     sinptr->sin_len    = sizeof( struct sockaddr_in );
711 #endif
712                     sinptr->sin_family = AF_INET;
713                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
714                     if (ifi->ifi_dstaddr == NULL) {
715                         goto gotError;
716                     }
717                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
718                 }
719 #endif
720             }
721             break;
722 
723 #if defined(AF_INET6) && HAVE_IPV6
724         case AF_INET6:
725             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
726             if (ifi->ifi_addr == NULL) {
727                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
728                 if (ifi->ifi_addr == NULL) {
729                     goto gotError;
730                 }
731 
732                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
733                 /* We need to strip that out */
734                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
735                     sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
736                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
737 
738 #ifdef  SIOCGIFNETMASK_IN6
739                 {
740                     struct in6_ifreq ifr6;
741                     if (sockf6 == -1)
742                         sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
743                     memset(&ifr6, 0, sizeof(ifr6));
744                     memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
745                     memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
746                     if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
747                         if (errno == EADDRNOTAVAIL) {
748                             /*
749                              * If the main interface is configured with no IP address but
750                              * an alias interface exists with an IP address, you get
751                              * EADDRNOTAVAIL for the main interface
752                              */
753                             free(ifi->ifi_addr);
754                             free(ifi);
755                             ifipnext  = ifiptr;
756                             *ifipnext = ifipold;
757                             continue;
758                         } else {
759                             goto gotError;
760                         }
761                     }
762                     ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
763                     if (ifi->ifi_netmask == NULL) goto gotError;
764                     sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
765                     memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
766                 }
767 #endif
768             }
769             break;
770 #endif
771 
772         default:
773             break;
774         }
775     }
776     goto done;
777 
778 gotError:
779     if (ifihead != NULL) {
780         free_ifi_info(ifihead);
781         ifihead = NULL;
782     }
783 
784 done:
785     if (buf != NULL) {
786         free(buf);
787     }
788     if (sockfd != -1) {
789         junk = close(sockfd);
790         assert(junk == 0);
791     }
792     if (sockf6 != -1) {
793         junk = close(sockf6);
794         assert(junk == 0);
795     }
796     return(ifihead);    /* pointer to first structure in linked list */
797 }
798 /* end get_ifi_info3 */
799 
800 /* include free_ifi_info */
801 void
802 free_ifi_info(struct ifi_info *ifihead)
803 {
804     struct ifi_info *ifi, *ifinext;
805 
806     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
807         if (ifi->ifi_addr != NULL)
808             free(ifi->ifi_addr);
809         if (ifi->ifi_netmask != NULL)
810             free(ifi->ifi_netmask);
811         if (ifi->ifi_brdaddr != NULL)
812             free(ifi->ifi_brdaddr);
813         if (ifi->ifi_dstaddr != NULL)
814             free(ifi->ifi_dstaddr);
815         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
816         free(ifi);                  /* the ifi_info{} itself */
817     }
818 }
819 /* end free_ifi_info */
820 
821 ssize_t
822 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
823                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
824 {
825     struct msghdr msg;
826     struct iovec iov[1];
827     ssize_t n;
828 
829 #ifdef CMSG_FIRSTHDR
830     struct cmsghdr  *cmptr;
831     union {
832         struct cmsghdr cm;
833         char control[1024];
834 	pad64_t align8; /* ensure structure is 8-byte aligned on sparc */
835     } control_un;
836 
837     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
838 
839     msg.msg_control = (void *) control_un.control;
840     msg.msg_controllen = sizeof(control_un.control);
841     msg.msg_flags = 0;
842 #else
843     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
844 #endif /* CMSG_FIRSTHDR */
845 
846     msg.msg_name = (char *) sa;
847     msg.msg_namelen = *salenptr;
848     iov[0].iov_base = (char *)ptr;
849     iov[0].iov_len = nbytes;
850     msg.msg_iov = iov;
851     msg.msg_iovlen = 1;
852 
853     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
854         return(n);
855 
856     *salenptr = msg.msg_namelen;    /* pass back results */
857     if (pktp) {
858         /* 0.0.0.0, i/f = -1 */
859         /* We set the interface to -1 so that the caller can
860            tell whether we returned a meaningful value or
861            just some default.  Previously this code just
862            set the value to 0, but I'm concerned that 0
863            might be a valid interface value.
864          */
865         memset(pktp, 0, sizeof(struct my_in_pktinfo));
866         pktp->ipi_ifindex = -1;
867     }
868 /* end recvfrom_flags1 */
869 
870 /* include recvfrom_flags2 */
871 #ifndef CMSG_FIRSTHDR
872     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
873     *flagsp = 0;                    /* pass back results */
874     return(n);
875 #else
876 
877     *flagsp = msg.msg_flags;        /* pass back results */
878     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
879         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
880         return(n);
881 
882     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
883          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
884 
885 #ifdef  IP_PKTINFO
886 #if in_pktinfo_definition_is_missing
887         struct in_pktinfo
888         {
889             int ipi_ifindex;
890             struct in_addr ipi_spec_dst;
891             struct in_addr ipi_addr;
892         };
893 #endif
894         if (cmptr->cmsg_level == IPPROTO_IP &&
895             cmptr->cmsg_type == IP_PKTINFO) {
896             struct in_pktinfo *tmp;
897             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
898 
899             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
900             sin->sin_family = AF_INET;
901             sin->sin_addr = tmp->ipi_addr;
902             sin->sin_port = 0;
903             pktp->ipi_ifindex = tmp->ipi_ifindex;
904             continue;
905         }
906 #endif
907 
908 #ifdef  IP_RECVDSTADDR
909         if (cmptr->cmsg_level == IPPROTO_IP &&
910             cmptr->cmsg_type == IP_RECVDSTADDR) {
911             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
912 
913             sin->sin_family = AF_INET;
914             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
915             sin->sin_port = 0;
916             continue;
917         }
918 #endif
919 
920 #ifdef  IP_RECVIF
921         if (cmptr->cmsg_level == IPPROTO_IP &&
922             cmptr->cmsg_type == IP_RECVIF) {
923             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
924 #ifndef HAVE_BROKEN_RECVIF_NAME
925             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
926             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
927 #endif
928 	    /*
929 	     * the is memcpy used for sparc? no idea;)
930 	     * pktp->ipi_ifindex = sdl->sdl_index;
931 	     */
932 	    (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
933 #ifdef HAVE_BROKEN_RECVIF_NAME
934             if (sdl->sdl_index == 0) {
935                 pktp->ipi_ifindex = *(uint_t*)sdl;
936             }
937 #endif
938             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
939             // null terminated because of memset above
940             continue;
941         }
942 #endif
943 
944 #ifdef  IP_RECVTTL
945         if (cmptr->cmsg_level == IPPROTO_IP &&
946             cmptr->cmsg_type == IP_RECVTTL) {
947             *ttl = *(u_char*)CMSG_DATA(cmptr);
948             continue;
949         }
950         else if (cmptr->cmsg_level == IPPROTO_IP &&
951                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
952             *ttl = *(int*)CMSG_DATA(cmptr);
953             continue;
954         }
955 #endif
956 
957 #if defined(IPV6_PKTINFO) && HAVE_IPV6
958         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
959             cmptr->cmsg_type  == IPV6_PKTINFO) {
960             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
961             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
962 
963             sin6->sin6_family   = AF_INET6;
964 #ifndef NOT_HAVE_SA_LEN
965             sin6->sin6_len      = sizeof(*sin6);
966 #endif
967             sin6->sin6_addr     = ip6_info->ipi6_addr;
968             sin6->sin6_flowinfo = 0;
969             sin6->sin6_scope_id = 0;
970             sin6->sin6_port     = 0;
971             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
972             continue;
973         }
974 #endif
975 
976 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
977         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
978             cmptr->cmsg_type == IPV6_HOPLIMIT) {
979             *ttl = *(int*)CMSG_DATA(cmptr);
980             continue;
981         }
982 #endif
983         assert(0);  // unknown ancillary data
984     }
985     return(n);
986 #endif /* CMSG_FIRSTHDR */
987 }
988 
989 // **********************************************************************************************
990 
991 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
992 // Returns 0 on success, -1 on failure.
993 
994 #ifdef NOT_HAVE_DAEMON
995 #include <fcntl.h>
996 #include <sys/stat.h>
997 #include <sys/signal.h>
998 
999 int daemon(int nochdir, int noclose)
1000 {
1001     switch (fork())
1002     {
1003     case -1: return (-1);       // Fork failed
1004     case 0:  break;             // Child -- continue
1005     default: _exit(0);          // Parent -- exit
1006     }
1007 
1008     if (setsid() == -1) return(-1);
1009 
1010     signal(SIGHUP, SIG_IGN);
1011 
1012     switch (fork())             // Fork again, primarily for reasons of Unix trivia
1013     {
1014     case -1: return (-1);       // Fork failed
1015     case 0:  break;             // Child -- continue
1016     default: _exit(0);          // Parent -- exit
1017     }
1018 
1019     if (!nochdir) (void)chdir("/");
1020     umask(0);
1021 
1022     if (!noclose)
1023     {
1024         int fd = open("/dev/null", O_RDWR, 0);
1025         if (fd != -1)
1026         {
1027             // Avoid unnecessarily duplicating a file descriptor to itself
1028             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
1029             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
1030             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
1031             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
1032                 (void)close (fd);
1033         }
1034     }
1035     return (0);
1036 }
1037 #endif /* NOT_HAVE_DAEMON */
1038