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