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