14b22b933Srs /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs  *
3*3b436d06SToomas Soome  * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
44b22b933Srs  *
54b22b933Srs  * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs  * you may not use this file except in compliance with the License.
74b22b933Srs  * You may obtain a copy of the License at
85ffb0c9bSToomas Soome  *
94b22b933Srs  *     http://www.apache.org/licenses/LICENSE-2.0
105ffb0c9bSToomas Soome  *
114b22b933Srs  * Unless required by applicable law or agreed to in writing, software
124b22b933Srs  * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs  * See the License for the specific language governing permissions and
154b22b933Srs  * limitations under the License.
163ee6e123SRichard Lowe  */
174b22b933Srs 
184b22b933Srs #include "mDNSUNP.h"
194b22b933Srs 
204b22b933Srs #include <errno.h>
214b22b933Srs #include <assert.h>
224b22b933Srs #include <string.h>
234b22b933Srs #include <stdlib.h>
244b22b933Srs #include <sys/uio.h>
254b22b933Srs #include <sys/ioctl.h>
265ffb0c9bSToomas Soome #include <signal.h>
274b22b933Srs #include <unistd.h>
284b22b933Srs #include <stdio.h>
294b22b933Srs 
304b22b933Srs /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
314b22b933Srs    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
324b22b933Srs    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
334b22b933Srs    should be set to the name of the header to include to get the ALIGN(P) macro.
345ffb0c9bSToomas Soome  */
354b22b933Srs #ifdef NEED_ALIGN_MACRO
364b22b933Srs #include NEED_ALIGN_MACRO
374b22b933Srs #endif
384b22b933Srs 
395ffb0c9bSToomas Soome /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
405ffb0c9bSToomas Soome    other platforms don't even have that include file.  So,
415ffb0c9bSToomas Soome    if we haven't yet got a definition, let's try to find
424b22b933Srs    <sys/sockio.h>.
435ffb0c9bSToomas Soome  */
444b22b933Srs 
454b22b933Srs #ifndef SIOCGIFCONF
464b22b933Srs     #include <sys/sockio.h>
474b22b933Srs #endif
484b22b933Srs 
495ffb0c9bSToomas Soome /* sockaddr_dl is only referenced if we're using IP_RECVIF,
504b22b933Srs    so only include the header in that case.
515ffb0c9bSToomas Soome  */
524b22b933Srs 
534b22b933Srs #ifdef  IP_RECVIF
544b22b933Srs     #include <net/if_dl.h>
554b22b933Srs #endif
564b22b933Srs 
574b22b933Srs #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
584b22b933Srs #if !HAVE_SOLARIS
594b22b933Srs #include <net/if_var.h>
604b22b933Srs #else
614b22b933Srs #include <alloca.h>
625ffb0c9bSToomas Soome #endif /* !HAVE_SOLARIS */
634b22b933Srs #include <netinet/in_var.h>
645ffb0c9bSToomas Soome // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
654b22b933Srs #endif
664b22b933Srs 
675ffb0c9bSToomas Soome #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
684b22b933Srs #include <netdb.h>
694b22b933Srs #include <arpa/inet.h>
704b22b933Srs 
714b22b933Srs /* Converts a prefix length to IPv6 network mask */
plen_to_mask(int plen,char * addr)724b22b933Srs void plen_to_mask(int plen, char *addr) {
735ffb0c9bSToomas Soome     int i;
745ffb0c9bSToomas Soome     int colons=7; /* Number of colons in IPv6 address */
755ffb0c9bSToomas Soome     int bits_in_block=16; /* Bits per IPv6 block */
765ffb0c9bSToomas Soome     for(i=0; i<=colons; i++) {
775ffb0c9bSToomas Soome         int block, ones=0xffff, ones_in_block;
785ffb0c9bSToomas Soome         if (plen>bits_in_block) ones_in_block=bits_in_block;
795ffb0c9bSToomas Soome         else ones_in_block=plen;
805ffb0c9bSToomas Soome         block = ones & (ones << (bits_in_block-ones_in_block));
815ffb0c9bSToomas Soome         i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
825ffb0c9bSToomas Soome         plen -= ones_in_block;
835ffb0c9bSToomas Soome     }
845ffb0c9bSToomas Soome }
854b22b933Srs 
864b22b933Srs /* Gets IPv6 interface information from the /proc filesystem in linux*/
get_ifi_info_linuxv6(int doaliases)87*3b436d06SToomas Soome struct ifi_info *get_ifi_info_linuxv6(int doaliases)
885ffb0c9bSToomas Soome {
895ffb0c9bSToomas Soome     struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
90cda73f64SToomas Soome     FILE *fp = NULL;
91*3b436d06SToomas Soome     int i, nitems, flags, index, plen, scope;
925ffb0c9bSToomas Soome     struct addrinfo hints, *res0;
935ffb0c9bSToomas Soome     int err;
945ffb0c9bSToomas Soome     int sockfd = -1;
955ffb0c9bSToomas Soome     struct ifreq ifr;
96*3b436d06SToomas Soome     char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ];
975ffb0c9bSToomas Soome 
985ffb0c9bSToomas Soome     res0=NULL;
995ffb0c9bSToomas Soome     ifihead = NULL;
1005ffb0c9bSToomas Soome     ifipnext = &ifihead;
1014b22b933Srs 
1025ffb0c9bSToomas Soome     if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
1035ffb0c9bSToomas Soome         sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
1045ffb0c9bSToomas Soome         if (sockfd < 0) {
1055ffb0c9bSToomas Soome             goto gotError;
1065ffb0c9bSToomas Soome         }
107*3b436d06SToomas Soome 
108*3b436d06SToomas Soome         // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
109*3b436d06SToomas Soome 
110*3b436d06SToomas Soome         // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
111*3b436d06SToomas Soome         // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
112*3b436d06SToomas Soome         // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
113*3b436d06SToomas Soome         // example, it could be defined in hexadecimal or as an arithmetic expression.
114*3b436d06SToomas Soome 
115*3b436d06SToomas Soome         snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1);
116*3b436d06SToomas Soome 
117*3b436d06SToomas Soome         // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
118*3b436d06SToomas Soome         // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
119*3b436d06SToomas Soome 
120*3b436d06SToomas Soome         for (i = 4; i < 39; i += 5) addrStr[i] = ':';
121*3b436d06SToomas Soome         addrStr[39] = '\0';
122*3b436d06SToomas Soome 
123*3b436d06SToomas Soome         lastname[0] = '\0';
124*3b436d06SToomas Soome         for (;;) {
125*3b436d06SToomas Soome             nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
126*3b436d06SToomas Soome                 &addrStr[0],  &addrStr[5],  &addrStr[10], &addrStr[15],
127*3b436d06SToomas Soome                 &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35],
128*3b436d06SToomas Soome                 &index, &plen, &scope, &flags);
129*3b436d06SToomas Soome             if (nitems != 12) break;
130*3b436d06SToomas Soome 
131*3b436d06SToomas Soome             nitems = fscanf(fp, ifnameFmt, ifname);
132*3b436d06SToomas Soome             if (nitems != 1) break;
133*3b436d06SToomas Soome 
134*3b436d06SToomas Soome             if (strcmp(lastname, ifname) == 0) {
1355ffb0c9bSToomas Soome                 if (doaliases == 0)
1365ffb0c9bSToomas Soome                     continue;   /* already processed this interface */
1375ffb0c9bSToomas Soome             }
1385ffb0c9bSToomas Soome             memcpy(lastname, ifname, IFNAMSIZ);
1395ffb0c9bSToomas Soome             ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
1405ffb0c9bSToomas Soome             if (ifi == NULL) {
1415ffb0c9bSToomas Soome                 goto gotError;
1425ffb0c9bSToomas Soome             }
1435ffb0c9bSToomas Soome 
1445ffb0c9bSToomas Soome             ifipold   = *ifipnext;       /* need this later */
1455ffb0c9bSToomas Soome             ifiptr    = ifipnext;
1465ffb0c9bSToomas Soome             *ifipnext = ifi;            /* prev points to this new one */
1475ffb0c9bSToomas Soome             ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
1485ffb0c9bSToomas Soome 
1495ffb0c9bSToomas Soome             /* Add address of the interface */
1505ffb0c9bSToomas Soome             memset(&hints, 0, sizeof(hints));
1515ffb0c9bSToomas Soome             hints.ai_family = AF_INET6;
1525ffb0c9bSToomas Soome             hints.ai_flags = AI_NUMERICHOST;
153*3b436d06SToomas Soome             err = getaddrinfo(addrStr, NULL, &hints, &res0);
1545ffb0c9bSToomas Soome             if (err) {
1555ffb0c9bSToomas Soome                 goto gotError;
1565ffb0c9bSToomas Soome             }
1575ffb0c9bSToomas Soome             ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
1585ffb0c9bSToomas Soome             if (ifi->ifi_addr == NULL) {
1595ffb0c9bSToomas Soome                 goto gotError;
1605ffb0c9bSToomas Soome             }
1615ffb0c9bSToomas Soome             memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
1625ffb0c9bSToomas Soome 
1635ffb0c9bSToomas Soome             /* Add netmask of the interface */
1645ffb0c9bSToomas Soome             char ipv6addr[INET6_ADDRSTRLEN];
1655ffb0c9bSToomas Soome             plen_to_mask(plen, ipv6addr);
1665ffb0c9bSToomas Soome             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
167cda73f64SToomas Soome             if (ifi->ifi_netmask == NULL) {
1685ffb0c9bSToomas Soome                 goto gotError;
1695ffb0c9bSToomas Soome             }
1705ffb0c9bSToomas Soome 
171*3b436d06SToomas Soome             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6;
172cda73f64SToomas Soome             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
173*3b436d06SToomas Soome             inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
1745ffb0c9bSToomas Soome 
1755ffb0c9bSToomas Soome             /* Add interface name */
1765ffb0c9bSToomas Soome             memcpy(ifi->ifi_name, ifname, IFI_NAME);
1775ffb0c9bSToomas Soome 
1785ffb0c9bSToomas Soome             /* Add interface index */
1795ffb0c9bSToomas Soome             ifi->ifi_index = index;
1805ffb0c9bSToomas Soome 
1815ffb0c9bSToomas Soome             /* Add interface flags*/
1825ffb0c9bSToomas Soome             memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1835ffb0c9bSToomas Soome             if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
1845ffb0c9bSToomas Soome                 if (errno == EADDRNOTAVAIL) {
1855ffb0c9bSToomas Soome                     /*
1865ffb0c9bSToomas Soome                      * If the main interface is configured with no IP address but
1875ffb0c9bSToomas Soome                      * an alias interface exists with an IP address, you get
1885ffb0c9bSToomas Soome                      * EADDRNOTAVAIL for the main interface
1895ffb0c9bSToomas Soome                      */
1905ffb0c9bSToomas Soome                     free(ifi->ifi_addr);
191cda73f64SToomas Soome                     free(ifi->ifi_netmask);
1925ffb0c9bSToomas Soome                     free(ifi);
1935ffb0c9bSToomas Soome                     ifipnext  = ifiptr;
1945ffb0c9bSToomas Soome                     *ifipnext = ifipold;
1955ffb0c9bSToomas Soome                     continue;
1965ffb0c9bSToomas Soome                 } else {
1975ffb0c9bSToomas Soome                     goto gotError;
1985ffb0c9bSToomas Soome                 }
1995ffb0c9bSToomas Soome             }
2005ffb0c9bSToomas Soome             ifi->ifi_flags = ifr.ifr_flags;
2015ffb0c9bSToomas Soome             freeaddrinfo(res0);
2025ffb0c9bSToomas Soome             res0=NULL;
2035ffb0c9bSToomas Soome         }
2045ffb0c9bSToomas Soome     }
2055ffb0c9bSToomas Soome     goto done;
2065ffb0c9bSToomas Soome 
2075ffb0c9bSToomas Soome gotError:
2085ffb0c9bSToomas Soome     if (ifihead != NULL) {
2095ffb0c9bSToomas Soome         free_ifi_info(ifihead);
2105ffb0c9bSToomas Soome         ifihead = NULL;
2115ffb0c9bSToomas Soome     }
2125ffb0c9bSToomas Soome     if (res0 != NULL) {
2135ffb0c9bSToomas Soome         freeaddrinfo(res0);
2145ffb0c9bSToomas Soome         res0=NULL;
2155ffb0c9bSToomas Soome     }
2165ffb0c9bSToomas Soome done:
2175ffb0c9bSToomas Soome     if (sockfd != -1) {
218c65ebfc7SToomas Soome         int rv;
219c65ebfc7SToomas Soome         rv = close(sockfd);
220c65ebfc7SToomas Soome         assert(rv == 0);
2215ffb0c9bSToomas Soome     }
222cda73f64SToomas Soome     if (fp != NULL) {
223cda73f64SToomas Soome         fclose(fp);
224cda73f64SToomas Soome     }
2255ffb0c9bSToomas Soome     return(ifihead);    /* pointer to first structure in linked list */
2265ffb0c9bSToomas Soome }
2275ffb0c9bSToomas Soome #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
2284b22b933Srs 
2294b22b933Srs #if HAVE_SOLARIS
2304b22b933Srs 
2314b22b933Srs /*
232cda73f64SToomas Soome  * Converts prefix length to network mask. Assumes
2334b22b933Srs  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
2344b22b933Srs  * Unlike plen_to_mask returns netmask in binary form and not
2354b22b933Srs  * in text form.
2364b22b933Srs  */
plen_to_netmask(int prefix,unsigned char * addr)237*3b436d06SToomas Soome static void plen_to_netmask(int prefix, unsigned char *addr) {
2384b22b933Srs     for (; prefix > 8; prefix -= 8)
2394b22b933Srs         *addr++ = 0xff;
2404b22b933Srs     for (; prefix > 0; prefix--)
2414b22b933Srs         *addr = (*addr >> 1) | 0x80;
2424b22b933Srs }
2434b22b933Srs 
2444b22b933Srs /*
245cda73f64SToomas Soome  * This function goes through all the IP interfaces associated with a
246cda73f64SToomas Soome  * physical interface and finds the best matched one for use by mDNS.
2474b22b933Srs  * Returns NULL when none of the IP interfaces associated with a physical
248cda73f64SToomas Soome  * interface are usable. Otherwise returns the best matched interface
2494b22b933Srs  * information and a pointer to the best matched lifreq.
2504b22b933Srs  */
2514b22b933Srs struct ifi_info *
select_src_ifi_info_solaris(int sockfd,int numifs,struct lifreq * lifrlist,const char * curifname,struct lifreq ** best_lifr)2524b22b933Srs select_src_ifi_info_solaris(int sockfd, int numifs,
2534b22b933Srs         struct lifreq *lifrlist, const char *curifname,
2544b22b933Srs         struct lifreq **best_lifr)
2554b22b933Srs {
2564b22b933Srs     struct lifreq *lifr;
2574b22b933Srs     struct lifreq lifrcopy;
2584b22b933Srs     struct ifi_info *ifi;
2594b22b933Srs     char *chptr;
2604b22b933Srs     char cmpifname[LIFNAMSIZ];
2614b22b933Srs     int i;
2625ffb0c9bSToomas Soome     uint64_t best_lifrflags = 0;
2634b22b933Srs     uint64_t ifflags;
2644b22b933Srs 
2654b22b933Srs     *best_lifr = NULL;
2664b22b933Srs 
267cda73f64SToomas Soome     /*
2684b22b933Srs      * Check all logical interfaces associated with the physical
2694b22b933Srs      * interface and figure out which one works best for us.
2704b22b933Srs      */
2714b22b933Srs     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
2724b22b933Srs 
2734b22b933Srs         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
2744b22b933Srs             continue; /* skip interface */
2754b22b933Srs 
2764b22b933Srs         /* Strip logical interface number before checking ifname */
2774b22b933Srs         if ((chptr = strchr(cmpifname, ':')) != NULL)
2784b22b933Srs             *chptr = '\0';
2794b22b933Srs 
280cda73f64SToomas Soome         /*
2814b22b933Srs          * Check ifname to see if the logical interface is associated
2824b22b933Srs          * with the physical interface we are interested in.
2834b22b933Srs          */
2844b22b933Srs         if (strcmp(cmpifname, curifname) != 0)
2854b22b933Srs             continue;
2864b22b933Srs 
2874b22b933Srs         lifrcopy = *lifr;
2884b22b933Srs         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
2894b22b933Srs             /* interface removed */
2904b22b933Srs             if (errno == ENXIO)
2914b22b933Srs                 continue;
2924b22b933Srs             return(NULL);
2934b22b933Srs         }
2944b22b933Srs         ifflags = lifrcopy.lifr_flags;
2954b22b933Srs 
2964b22b933Srs         /* ignore address if not up */
2974b22b933Srs         if ((ifflags & IFF_UP) == 0)
2984b22b933Srs             continue;
2994b22b933Srs         /*
300cda73f64SToomas Soome          * Avoid address if any of the following flags are set:
3014b22b933Srs          *  IFF_NOXMIT: no packets transmitted over interface
3024b22b933Srs          *  IFF_NOLOCAL: no address
3034b22b933Srs          *  IFF_PRIVATE: is not advertised
3044b22b933Srs          */
305e11c3f44Smeem         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
3064b22b933Srs             continue;
3074b22b933Srs 
308cda73f64SToomas Soome        /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
309bd670b35SErik Nordmark         if (lifr->lifr_addr.ss_family == AF_INET) {
310cda73f64SToomas Soome                struct sockaddr_in *sinptr;
311bd670b35SErik Nordmark 
312cda73f64SToomas Soome                sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
313cda73f64SToomas Soome                if (sinptr->sin_addr.s_addr == INADDR_ANY)
314cda73f64SToomas Soome                        continue;
315cda73f64SToomas Soome        }
316bd670b35SErik Nordmark 
3174b22b933Srs         if (*best_lifr != NULL) {
318cda73f64SToomas Soome             /*
3194b22b933Srs              * Check if we found a better interface by checking
3204b22b933Srs              * the flags. If flags are identical we prefer
3214b22b933Srs              * the new found interface.
3224b22b933Srs              */
3234b22b933Srs             uint64_t diff_flags = best_lifrflags ^ ifflags;
3244b22b933Srs 
3254b22b933Srs             /* If interface has a different set of flags */
3264b22b933Srs             if (diff_flags != 0) {
3274b22b933Srs                 /* Check flags in increasing order of ones we prefer */
3284b22b933Srs 
3294b22b933Srs                 /* Address temporary? */
3304b22b933Srs                 if ((diff_flags & IFF_TEMPORARY) &&
3314b22b933Srs                     (ifflags & IFF_TEMPORARY))
3324b22b933Srs                     continue;
3334b22b933Srs                 /* Deprecated address? */
3344b22b933Srs                 if ((diff_flags & IFF_DEPRECATED) &&
3354b22b933Srs                     (ifflags & IFF_DEPRECATED))
3364b22b933Srs                     continue;
3374b22b933Srs                 /* Last best-matched interface address has preferred? */
3384b22b933Srs                 if ((diff_flags & IFF_PREFERRED) &&
3394b22b933Srs                     ((ifflags & IFF_PREFERRED) == 0))
3404b22b933Srs                     continue;
3414b22b933Srs             }
3424b22b933Srs         }
3434b22b933Srs 
3444b22b933Srs         /* Set best match interface & flags */
3454b22b933Srs         *best_lifr = lifr;
3464b22b933Srs         best_lifrflags = ifflags;
3474b22b933Srs     }
3484b22b933Srs 
3494b22b933Srs     if (*best_lifr == NULL)
3504b22b933Srs         return(NULL);
3514b22b933Srs 
3524b22b933Srs     /* Found a match: return the interface information */
3534b22b933Srs     ifi = calloc(1, sizeof(struct ifi_info));
3544b22b933Srs     if (ifi == NULL)
3554b22b933Srs         return(NULL);
3564b22b933Srs 
357cda73f64SToomas Soome     ifi->ifi_flags = best_lifrflags;
3584b22b933Srs     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
3594b22b933Srs     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
3604b22b933Srs         free(ifi);
3614b22b933Srs         return(NULL);
3624b22b933Srs     }
3634b22b933Srs     return(ifi);
3644b22b933Srs }
3654b22b933Srs 
3664b22b933Srs /*
3674b22b933Srs  * Returns a list of IP interface information on Solaris. The function
3684b22b933Srs  * returns all IP interfaces on the system with IPv4 address assigned
3694b22b933Srs  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
3704b22b933Srs  * when AF_INET6 is passed.
3714b22b933Srs  */
get_ifi_info_solaris(int family)3724b22b933Srs struct ifi_info *get_ifi_info_solaris(int family)
3734b22b933Srs {
3744b22b933Srs     struct ifi_info     *ifi, *ifihead, **ifipnext;
3754b22b933Srs     int   sockfd;
3764b22b933Srs     int  len;
3774b22b933Srs     char  *buf;
3784b22b933Srs     char *cptr;
3794b22b933Srs     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
3804b22b933Srs     struct sockaddr_in *sinptr;
3814b22b933Srs     struct lifnum lifn;
3824b22b933Srs     struct lifconf lifc;
3834b22b933Srs     struct lifreq *lifrp, *best_lifr;
3844b22b933Srs     struct lifreq lifrcopy;
3854b22b933Srs     int numifs, nlifr, n;
3864b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
3874b22b933Srs     struct sockaddr_in6 *sinptr6;
3884b22b933Srs #endif
3894b22b933Srs 
3904b22b933Srs     ifihead = NULL;
3914b22b933Srs 
3924b22b933Srs     sockfd = socket(family, SOCK_DGRAM, 0);
3934b22b933Srs     if (sockfd < 0)
3944b22b933Srs         goto gotError;
3954b22b933Srs 
3964b22b933Srs again:
3974b22b933Srs     lifn.lifn_family = family;
3984b22b933Srs     lifn.lifn_flags = 0;
3994b22b933Srs     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
4004b22b933Srs         goto gotError;
4014b22b933Srs     /*
402cda73f64SToomas Soome      * Pad interface count to detect & retrieve any
4034b22b933Srs      * additional interfaces between IFNUM & IFCONF calls.
4044b22b933Srs      */
4054b22b933Srs     lifn.lifn_count += 4;
4064b22b933Srs     numifs = lifn.lifn_count;
4074b22b933Srs     len = numifs * sizeof (struct lifreq);
4084b22b933Srs     buf = alloca(len);
4094b22b933Srs 
4104b22b933Srs     lifc.lifc_family = family;
4114b22b933Srs     lifc.lifc_len = len;
4124b22b933Srs     lifc.lifc_buf = buf;
4134b22b933Srs     lifc.lifc_flags = 0;
4144b22b933Srs 
4154b22b933Srs     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
4164b22b933Srs         goto gotError;
4174b22b933Srs 
4184b22b933Srs     nlifr = lifc.lifc_len / sizeof(struct lifreq);
4194b22b933Srs     if (nlifr >= numifs)
4204b22b933Srs         goto again;
4214b22b933Srs 
4224b22b933Srs     lifrp = lifc.lifc_req;
4234b22b933Srs     ifipnext = &ifihead;
4244b22b933Srs 
4254b22b933Srs     for (n = nlifr; n > 0; n--, lifrp++) {
4264b22b933Srs 
4274b22b933Srs         if (lifrp->lifr_addr.ss_family != family)
4284b22b933Srs             continue;
4294b22b933Srs 
430cda73f64SToomas Soome         /*
4314b22b933Srs          * See if we have already processed the interface
4324b22b933Srs          * by checking the interface names.
4334b22b933Srs          */
4344b22b933Srs         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
4354b22b933Srs             goto gotError;
4364b22b933Srs         if ((cptr = strchr(ifname, ':')) != NULL)
4374b22b933Srs             *cptr = '\0';
4384b22b933Srs 
439cda73f64SToomas Soome         /*
4404b22b933Srs          * If any of the interfaces found so far share the physical
4414b22b933Srs          * interface name then we have already processed the interface.
4424b22b933Srs          */
4434b22b933Srs         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
444cda73f64SToomas Soome 
4454b22b933Srs             /* Retrieve physical interface name */
4464b22b933Srs             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
4474b22b933Srs 
4484b22b933Srs             /* Strip logical interface number before checking ifname */
4494b22b933Srs             if ((cptr = strchr(cmpifname, ':')) != NULL)
4504b22b933Srs                 *cptr = '\0';
4514b22b933Srs 
4524b22b933Srs             if (strcmp(cmpifname, ifname) == 0)
4534b22b933Srs                 break;
4544b22b933Srs         }
4554b22b933Srs         if (ifi != NULL)
4564b22b933Srs             continue; /* already processed */
4574b22b933Srs 
458cda73f64SToomas Soome         /*
4594b22b933Srs          * New interface, find the one with the preferred source
4604b22b933Srs          * address for our use in Multicast DNS.
4614b22b933Srs          */
4624b22b933Srs         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
4634b22b933Srs             lifc.lifc_req, ifname, &best_lifr)) == NULL)
4644b22b933Srs             continue;
4654b22b933Srs 
4664b22b933Srs         assert(best_lifr != NULL);
4674b22b933Srs         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
4684b22b933Srs                (best_lifr->lifr_addr.ss_family == AF_INET));
4694b22b933Srs 
4704b22b933Srs         switch (best_lifr->lifr_addr.ss_family) {
4714b22b933Srs 
4724b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
4734b22b933Srs         case AF_INET6:
4744b22b933Srs             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
4754b22b933Srs             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
4764b22b933Srs             if (ifi->ifi_addr == NULL)
4774b22b933Srs                 goto gotError;
4784b22b933Srs             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
4794b22b933Srs 
4804b22b933Srs             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
4814b22b933Srs             if (ifi->ifi_netmask == NULL)
4824b22b933Srs                 goto gotError;
4834b22b933Srs             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
4844b22b933Srs             sinptr6->sin6_family = AF_INET6;
4854b22b933Srs             plen_to_netmask(best_lifr->lifr_addrlen,
4864b22b933Srs                     (unsigned char *) &(sinptr6->sin6_addr));
4874b22b933Srs             break;
4884b22b933Srs #endif
4894b22b933Srs 
4904b22b933Srs         case AF_INET:
4914b22b933Srs             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
4924b22b933Srs             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
4934b22b933Srs             if (ifi->ifi_addr == NULL)
4944b22b933Srs                 goto gotError;
4954b22b933Srs 
4964b22b933Srs             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
4974b22b933Srs 
4984b22b933Srs             lifrcopy = *best_lifr;
4994b22b933Srs             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
5004b22b933Srs                 /* interface removed */
5014b22b933Srs                 if (errno == ENXIO) {
5024b22b933Srs                     free(ifi->ifi_addr);
5034b22b933Srs                     free(ifi);
5044b22b933Srs                     continue;
5054b22b933Srs                 }
5064b22b933Srs                 goto gotError;
5074b22b933Srs             }
5084b22b933Srs 
5094b22b933Srs             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
510cda73f64SToomas Soome             if (ifi->ifi_netmask == NULL)
5114b22b933Srs                 goto gotError;
5124b22b933Srs             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
5134b22b933Srs             sinptr->sin_family = AF_INET;
5144b22b933Srs             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
5154b22b933Srs             break;
5164b22b933Srs 
5174b22b933Srs         default:
5184b22b933Srs             /* never reached */
5194b22b933Srs             break;
5204b22b933Srs         }
5214b22b933Srs 
5224b22b933Srs         *ifipnext = ifi;            /* prev points to this new one */
5234b22b933Srs         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
5244b22b933Srs     }
5254b22b933Srs 
5264b22b933Srs     (void) close(sockfd);
5274b22b933Srs     return(ifihead);    /* pointer to first structure in linked list */
5284b22b933Srs 
5294b22b933Srs gotError:
5304b22b933Srs     if (sockfd != -1)
5314b22b933Srs         (void) close(sockfd);
5324b22b933Srs     if (ifihead != NULL)
5334b22b933Srs         free_ifi_info(ifihead);
5344b22b933Srs     return(NULL);
5354b22b933Srs }
5364b22b933Srs 
5374b22b933Srs #endif /* HAVE_SOLARIS */
5384b22b933Srs 
get_ifi_info(int family,int doaliases)5394b22b933Srs struct ifi_info *get_ifi_info(int family, int doaliases)
5404b22b933Srs {
5415ffb0c9bSToomas Soome     int junk;
5425ffb0c9bSToomas Soome     struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
5435ffb0c9bSToomas Soome     int sockfd, sockf6, len, lastlen, flags, myflags;
5444b22b933Srs #ifdef NOT_HAVE_IF_NAMETOINDEX
5455ffb0c9bSToomas Soome     int index = 200;
5464b22b933Srs #endif
5474b22b933Srs     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
5485ffb0c9bSToomas Soome     struct ifconf ifc;
5494b22b933Srs     struct ifreq        *ifr, ifrcopy;
5504b22b933Srs     struct sockaddr_in  *sinptr;
5515ffb0c9bSToomas Soome 
5524b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
5534b22b933Srs     struct sockaddr_in6 *sinptr6;
5544b22b933Srs #endif
5554b22b933Srs 
5564b22b933Srs #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
557*3b436d06SToomas Soome     if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
5584b22b933Srs #elif HAVE_SOLARIS
5594b22b933Srs     return get_ifi_info_solaris(family);
5604b22b933Srs #endif
5614b22b933Srs 
5624b22b933Srs     sockfd = -1;
5634b22b933Srs     sockf6 = -1;
5644b22b933Srs     buf = NULL;
5654b22b933Srs     ifihead = NULL;
5665ffb0c9bSToomas Soome 
5674b22b933Srs     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
5684b22b933Srs     if (sockfd < 0) {
5694b22b933Srs         goto gotError;
5704b22b933Srs     }
5714b22b933Srs 
5724b22b933Srs     lastlen = 0;
5734b22b933Srs     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
5744b22b933Srs     for ( ; ; ) {
5754b22b933Srs         buf = (char*)malloc(len);
5764b22b933Srs         if (buf == NULL) {
5774b22b933Srs             goto gotError;
5784b22b933Srs         }
5794b22b933Srs         ifc.ifc_len = len;
5804b22b933Srs         ifc.ifc_buf = buf;
5814b22b933Srs         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
5824b22b933Srs             if (errno != EINVAL || lastlen != 0) {
5834b22b933Srs                 goto gotError;
5844b22b933Srs             }
5854b22b933Srs         } else {
5864b22b933Srs             if (ifc.ifc_len == lastlen)
5874b22b933Srs                 break;      /* success, len has not changed */
5884b22b933Srs             lastlen = ifc.ifc_len;
5894b22b933Srs         }
5904b22b933Srs         len += 10 * sizeof(struct ifreq);   /* increment */
5914b22b933Srs         free(buf);
5924b22b933Srs     }
5934b22b933Srs     ifihead = NULL;
5944b22b933Srs     ifipnext = &ifihead;
5954b22b933Srs     lastname[0] = 0;
5964b22b933Srs /* end get_ifi_info1 */
5974b22b933Srs 
5984b22b933Srs /* include get_ifi_info2 */
5994b22b933Srs     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
6004b22b933Srs         ifr = (struct ifreq *) ptr;
6014b22b933Srs 
6024b22b933Srs         /* Advance to next one in buffer */
6034b22b933Srs         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
6044b22b933Srs             ptr += sizeof(struct ifreq);
6054b22b933Srs         else
6064b22b933Srs             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
6074b22b933Srs 
6084b22b933Srs //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
6095ffb0c9bSToomas Soome 
6104b22b933Srs         if (ifr->ifr_addr.sa_family != family)
6114b22b933Srs             continue;   /* ignore if not desired address family */
6124b22b933Srs 
6134b22b933Srs         myflags = 0;
6144b22b933Srs         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
6154b22b933Srs             *cptr = 0;      /* replace colon will null */
6164b22b933Srs         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
6174b22b933Srs             if (doaliases == 0)
6184b22b933Srs                 continue;   /* already processed this interface */
6194b22b933Srs             myflags = IFI_ALIAS;
6204b22b933Srs         }
6214b22b933Srs         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
6224b22b933Srs 
6234b22b933Srs         ifrcopy = *ifr;
6244b22b933Srs         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
6254b22b933Srs             goto gotError;
6264b22b933Srs         }
6275ffb0c9bSToomas Soome 
6284b22b933Srs         flags = ifrcopy.ifr_flags;
6294b22b933Srs         if ((flags & IFF_UP) == 0)
6304b22b933Srs             continue;   /* ignore if interface not up */
6314b22b933Srs 
6324b22b933Srs         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
6334b22b933Srs         if (ifi == NULL) {
6344b22b933Srs             goto gotError;
6354b22b933Srs         }
6365ffb0c9bSToomas Soome         ifipold   = *ifipnext;       /* need this later */
6375ffb0c9bSToomas Soome         ifiptr    = ifipnext;
6385ffb0c9bSToomas Soome         *ifipnext = ifi;             /* prev points to this new one */
6395ffb0c9bSToomas Soome         ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
6404b22b933Srs 
6414b22b933Srs         ifi->ifi_flags = flags;     /* IFF_xxx values */
6424b22b933Srs         ifi->ifi_myflags = myflags; /* IFI_xxx values */
6434b22b933Srs #ifndef NOT_HAVE_IF_NAMETOINDEX
6444b22b933Srs         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
6454b22b933Srs #else
6464b22b933Srs         ifrcopy = *ifr;
6474b22b933Srs #ifdef SIOCGIFINDEX
6484b22b933Srs         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
6494b22b933Srs             ifi->ifi_index = ifrcopy.ifr_index;
6504b22b933Srs         else
6514b22b933Srs #endif
6525ffb0c9bSToomas Soome         ifi->ifi_index = index++;       /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
6534b22b933Srs #endif
6544b22b933Srs         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
6554b22b933Srs         ifi->ifi_name[IFI_NAME-1] = '\0';
6564b22b933Srs /* end get_ifi_info2 */
6574b22b933Srs /* include get_ifi_info3 */
6584b22b933Srs         switch (ifr->ifr_addr.sa_family) {
6594b22b933Srs         case AF_INET:
6604b22b933Srs             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
6614b22b933Srs             if (ifi->ifi_addr == NULL) {
6624b22b933Srs                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6634b22b933Srs                 if (ifi->ifi_addr == NULL) {
6644b22b933Srs                     goto gotError;
6654b22b933Srs                 }
6664b22b933Srs                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
6674b22b933Srs 
6684b22b933Srs #ifdef  SIOCGIFNETMASK
6695ffb0c9bSToomas Soome                 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
6705ffb0c9bSToomas Soome                     if (errno == EADDRNOTAVAIL) {
6715ffb0c9bSToomas Soome                         /*
6725ffb0c9bSToomas Soome                          * If the main interface is configured with no IP address but
6735ffb0c9bSToomas Soome                          * an alias interface exists with an IP address, you get
6745ffb0c9bSToomas Soome                          * EADDRNOTAVAIL for the main interface
6755ffb0c9bSToomas Soome                          */
6765ffb0c9bSToomas Soome                         free(ifi->ifi_addr);
6775ffb0c9bSToomas Soome                         free(ifi);
6785ffb0c9bSToomas Soome                         ifipnext  = ifiptr;
6795ffb0c9bSToomas Soome                         *ifipnext = ifipold;
6805ffb0c9bSToomas Soome                         continue;
6815ffb0c9bSToomas Soome                     } else {
6825ffb0c9bSToomas Soome                         goto gotError;
6835ffb0c9bSToomas Soome                     }
6845ffb0c9bSToomas Soome                 }
6855ffb0c9bSToomas Soome 
6865ffb0c9bSToomas Soome                 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6875ffb0c9bSToomas Soome                 if (ifi->ifi_netmask == NULL) goto gotError;
6885ffb0c9bSToomas Soome                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
6895ffb0c9bSToomas Soome                 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
6904b22b933Srs #ifndef NOT_HAVE_SA_LEN
6915ffb0c9bSToomas Soome                 sinptr->sin_len    = sizeof(struct sockaddr_in);
6924b22b933Srs #endif
6935ffb0c9bSToomas Soome                 sinptr->sin_family = AF_INET;
6945ffb0c9bSToomas Soome                 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
6954b22b933Srs #endif
6964b22b933Srs 
6974b22b933Srs #ifdef  SIOCGIFBRDADDR
6984b22b933Srs                 if (flags & IFF_BROADCAST) {
6994b22b933Srs                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
7004b22b933Srs                         goto gotError;
7014b22b933Srs                     }
7024b22b933Srs                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
7035ffb0c9bSToomas Soome                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
7044b22b933Srs #ifndef NOT_HAVE_SA_LEN
7055ffb0c9bSToomas Soome                     sinptr->sin_len    = sizeof( struct sockaddr_in );
7064b22b933Srs #endif
7075ffb0c9bSToomas Soome                     sinptr->sin_family = AF_INET;
7084b22b933Srs                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
7094b22b933Srs                     if (ifi->ifi_brdaddr == NULL) {
7104b22b933Srs                         goto gotError;
7114b22b933Srs                     }
7124b22b933Srs                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
7134b22b933Srs                 }
7144b22b933Srs #endif
7154b22b933Srs 
7164b22b933Srs #ifdef  SIOCGIFDSTADDR
7174b22b933Srs                 if (flags & IFF_POINTOPOINT) {
7184b22b933Srs                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
7194b22b933Srs                         goto gotError;
7204b22b933Srs                     }
7214b22b933Srs                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
7224b22b933Srs                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
7234b22b933Srs #ifndef NOT_HAVE_SA_LEN
7245ffb0c9bSToomas Soome                     sinptr->sin_len    = sizeof( struct sockaddr_in );
7254b22b933Srs #endif
7265ffb0c9bSToomas Soome                     sinptr->sin_family = AF_INET;
7274b22b933Srs                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
7284b22b933Srs                     if (ifi->ifi_dstaddr == NULL) {
7294b22b933Srs                         goto gotError;
7304b22b933Srs                     }
7314b22b933Srs                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
7324b22b933Srs                 }
7334b22b933Srs #endif
7344b22b933Srs             }
7354b22b933Srs             break;
7364b22b933Srs 
7374b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
7384b22b933Srs         case AF_INET6:
7394b22b933Srs             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
7404b22b933Srs             if (ifi->ifi_addr == NULL) {
7414b22b933Srs                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
7424b22b933Srs                 if (ifi->ifi_addr == NULL) {
7434b22b933Srs                     goto gotError;
7444b22b933Srs                 }
7455ffb0c9bSToomas Soome 
7464b22b933Srs                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
7474b22b933Srs                 /* We need to strip that out */
7484b22b933Srs                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
7495ffb0c9bSToomas Soome                     sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
7504b22b933Srs                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
7514b22b933Srs 
7524b22b933Srs #ifdef  SIOCGIFNETMASK_IN6
7535ffb0c9bSToomas Soome                 {
7545ffb0c9bSToomas Soome                     struct in6_ifreq ifr6;
7555ffb0c9bSToomas Soome                     if (sockf6 == -1)
7565ffb0c9bSToomas Soome                         sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
7575ffb0c9bSToomas Soome                     memset(&ifr6, 0, sizeof(ifr6));
7585ffb0c9bSToomas Soome                     memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
7595ffb0c9bSToomas Soome                     memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
7605ffb0c9bSToomas Soome                     if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
7615ffb0c9bSToomas Soome                         if (errno == EADDRNOTAVAIL) {
7625ffb0c9bSToomas Soome                             /*
7635ffb0c9bSToomas Soome                              * If the main interface is configured with no IP address but
7645ffb0c9bSToomas Soome                              * an alias interface exists with an IP address, you get
7655ffb0c9bSToomas Soome                              * EADDRNOTAVAIL for the main interface
7665ffb0c9bSToomas Soome                              */
7675ffb0c9bSToomas Soome                             free(ifi->ifi_addr);
7685ffb0c9bSToomas Soome                             free(ifi);
7695ffb0c9bSToomas Soome                             ifipnext  = ifiptr;
7705ffb0c9bSToomas Soome                             *ifipnext = ifipold;
7715ffb0c9bSToomas Soome                             continue;
7725ffb0c9bSToomas Soome                         } else {
7735ffb0c9bSToomas Soome                             goto gotError;
7745ffb0c9bSToomas Soome                         }
7755ffb0c9bSToomas Soome                     }
7765ffb0c9bSToomas Soome                     ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
7775ffb0c9bSToomas Soome                     if (ifi->ifi_netmask == NULL) goto gotError;
7785ffb0c9bSToomas Soome                     sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
7795ffb0c9bSToomas Soome                     memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
7805ffb0c9bSToomas Soome                 }
7814b22b933Srs #endif
7824b22b933Srs             }
7834b22b933Srs             break;
7844b22b933Srs #endif
7854b22b933Srs 
7864b22b933Srs         default:
7874b22b933Srs             break;
7884b22b933Srs         }
7894b22b933Srs     }
7904b22b933Srs     goto done;
7915ffb0c9bSToomas Soome 
7924b22b933Srs gotError:
7934b22b933Srs     if (ifihead != NULL) {
7944b22b933Srs         free_ifi_info(ifihead);
7954b22b933Srs         ifihead = NULL;
7964b22b933Srs     }
7974b22b933Srs 
7984b22b933Srs done:
7994b22b933Srs     if (buf != NULL) {
8004b22b933Srs         free(buf);
8014b22b933Srs     }
8024b22b933Srs     if (sockfd != -1) {
8034b22b933Srs         junk = close(sockfd);
8044b22b933Srs         assert(junk == 0);
8054b22b933Srs     }
8064b22b933Srs     if (sockf6 != -1) {
8074b22b933Srs         junk = close(sockf6);
8084b22b933Srs         assert(junk == 0);
8094b22b933Srs     }
8104b22b933Srs     return(ifihead);    /* pointer to first structure in linked list */
8114b22b933Srs }
8124b22b933Srs /* end get_ifi_info3 */
8134b22b933Srs 
8144b22b933Srs /* include free_ifi_info */
8154b22b933Srs void
free_ifi_info(struct ifi_info * ifihead)8164b22b933Srs free_ifi_info(struct ifi_info *ifihead)
8174b22b933Srs {
8184b22b933Srs     struct ifi_info *ifi, *ifinext;
8194b22b933Srs 
8204b22b933Srs     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
8214b22b933Srs         if (ifi->ifi_addr != NULL)
8224b22b933Srs             free(ifi->ifi_addr);
8235ffb0c9bSToomas Soome         if (ifi->ifi_netmask != NULL)
8245ffb0c9bSToomas Soome             free(ifi->ifi_netmask);
8254b22b933Srs         if (ifi->ifi_brdaddr != NULL)
8264b22b933Srs             free(ifi->ifi_brdaddr);
8274b22b933Srs         if (ifi->ifi_dstaddr != NULL)
8284b22b933Srs             free(ifi->ifi_dstaddr);
8294b22b933Srs         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
8304b22b933Srs         free(ifi);                  /* the ifi_info{} itself */
8314b22b933Srs     }
8324b22b933Srs }
8334b22b933Srs /* end free_ifi_info */
8344b22b933Srs 
8355ffb0c9bSToomas Soome 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)8364b22b933Srs recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
8374b22b933Srs                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
8384b22b933Srs {
8395ffb0c9bSToomas Soome     struct msghdr msg;
8405ffb0c9bSToomas Soome     struct iovec iov[1];
8415ffb0c9bSToomas Soome     ssize_t n;
8424b22b933Srs 
8434b22b933Srs #ifdef CMSG_FIRSTHDR
8444b22b933Srs     struct cmsghdr  *cmptr;
8454b22b933Srs     union {
8465ffb0c9bSToomas Soome         struct cmsghdr cm;
8475ffb0c9bSToomas Soome         char control[1024];
8485ffb0c9bSToomas Soome 	pad64_t align8; /* ensure structure is 8-byte aligned on sparc */
8494b22b933Srs     } control_un;
8504b22b933Srs 
8515ffb0c9bSToomas Soome     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
8524b22b933Srs 
853*3b436d06SToomas Soome     msg.msg_control = (void *) control_un.control;
8544b22b933Srs     msg.msg_controllen = sizeof(control_un.control);
8554b22b933Srs     msg.msg_flags = 0;
8564b22b933Srs #else
8574b22b933Srs     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
8584b22b933Srs #endif /* CMSG_FIRSTHDR */
8594b22b933Srs 
8604b22b933Srs     msg.msg_name = (char *) sa;
8614b22b933Srs     msg.msg_namelen = *salenptr;
8624b22b933Srs     iov[0].iov_base = (char *)ptr;
8634b22b933Srs     iov[0].iov_len = nbytes;
8644b22b933Srs     msg.msg_iov = iov;
8654b22b933Srs     msg.msg_iovlen = 1;
8664b22b933Srs 
8674b22b933Srs     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
8684b22b933Srs         return(n);
8694b22b933Srs 
8704b22b933Srs     *salenptr = msg.msg_namelen;    /* pass back results */
8714b22b933Srs     if (pktp) {
8724b22b933Srs         /* 0.0.0.0, i/f = -1 */
8735ffb0c9bSToomas Soome         /* We set the interface to -1 so that the caller can
8745ffb0c9bSToomas Soome            tell whether we returned a meaningful value or
8755ffb0c9bSToomas Soome            just some default.  Previously this code just
8765ffb0c9bSToomas Soome            set the value to 0, but I'm concerned that 0
8774b22b933Srs            might be a valid interface value.
8785ffb0c9bSToomas Soome          */
8794b22b933Srs         memset(pktp, 0, sizeof(struct my_in_pktinfo));
8804b22b933Srs         pktp->ipi_ifindex = -1;
8814b22b933Srs     }
8824b22b933Srs /* end recvfrom_flags1 */
8834b22b933Srs 
8844b22b933Srs /* include recvfrom_flags2 */
8854b22b933Srs #ifndef CMSG_FIRSTHDR
8865ffb0c9bSToomas Soome     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
8874b22b933Srs     *flagsp = 0;                    /* pass back results */
8884b22b933Srs     return(n);
8894b22b933Srs #else
8904b22b933Srs 
8914b22b933Srs     *flagsp = msg.msg_flags;        /* pass back results */
8924b22b933Srs     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
8934b22b933Srs         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
8944b22b933Srs         return(n);
8954b22b933Srs 
8964b22b933Srs     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
8974b22b933Srs          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
8984b22b933Srs 
8994b22b933Srs #ifdef  IP_PKTINFO
9004b22b933Srs #if in_pktinfo_definition_is_missing
9015ffb0c9bSToomas Soome         struct in_pktinfo
9025ffb0c9bSToomas Soome         {
9035ffb0c9bSToomas Soome             int ipi_ifindex;
9045ffb0c9bSToomas Soome             struct in_addr ipi_spec_dst;
9055ffb0c9bSToomas Soome             struct in_addr ipi_addr;
9065ffb0c9bSToomas Soome         };
9074b22b933Srs #endif
9085ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IP &&
9094b22b933Srs             cmptr->cmsg_type == IP_PKTINFO) {
9104b22b933Srs             struct in_pktinfo *tmp;
9114b22b933Srs             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9125ffb0c9bSToomas Soome 
9134b22b933Srs             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
9144b22b933Srs             sin->sin_family = AF_INET;
9154b22b933Srs             sin->sin_addr = tmp->ipi_addr;
9164b22b933Srs             sin->sin_port = 0;
9174b22b933Srs             pktp->ipi_ifindex = tmp->ipi_ifindex;
9184b22b933Srs             continue;
9194b22b933Srs         }
9204b22b933Srs #endif
9214b22b933Srs 
9224b22b933Srs #ifdef  IP_RECVDSTADDR
9234b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9244b22b933Srs             cmptr->cmsg_type == IP_RECVDSTADDR) {
9254b22b933Srs             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9265ffb0c9bSToomas Soome 
9274b22b933Srs             sin->sin_family = AF_INET;
9284b22b933Srs             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
9294b22b933Srs             sin->sin_port = 0;
9304b22b933Srs             continue;
9314b22b933Srs         }
9324b22b933Srs #endif
9334b22b933Srs 
9344b22b933Srs #ifdef  IP_RECVIF
9354b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9364b22b933Srs             cmptr->cmsg_type == IP_RECVIF) {
9374b22b933Srs             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
9384b22b933Srs #ifndef HAVE_BROKEN_RECVIF_NAME
9394b22b933Srs             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
9404b22b933Srs             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
9414b22b933Srs #endif
942cda73f64SToomas Soome 	    /*
943cda73f64SToomas Soome 	     * the is memcpy used for sparc? no idea;)
944cda73f64SToomas Soome 	     * pktp->ipi_ifindex = sdl->sdl_index;
9455ffb0c9bSToomas Soome 	     */
946cda73f64SToomas Soome 	    (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
9475ffb0c9bSToomas Soome #ifdef HAVE_BROKEN_RECVIF_NAME
9485ffb0c9bSToomas Soome             if (sdl->sdl_index == 0) {
9495ffb0c9bSToomas Soome                 pktp->ipi_ifindex = *(uint_t*)sdl;
9505ffb0c9bSToomas Soome             }
9515ffb0c9bSToomas Soome #endif
9524b22b933Srs             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
9534b22b933Srs             // null terminated because of memset above
9544b22b933Srs             continue;
9554b22b933Srs         }
9564b22b933Srs #endif
9574b22b933Srs 
9584b22b933Srs #ifdef  IP_RECVTTL
9594b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9604b22b933Srs             cmptr->cmsg_type == IP_RECVTTL) {
9615ffb0c9bSToomas Soome             *ttl = *(u_char*)CMSG_DATA(cmptr);
9624b22b933Srs             continue;
9634b22b933Srs         }
9644b22b933Srs         else if (cmptr->cmsg_level == IPPROTO_IP &&
9655ffb0c9bSToomas Soome                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
9665ffb0c9bSToomas Soome             *ttl = *(int*)CMSG_DATA(cmptr);
9674b22b933Srs             continue;
9684b22b933Srs         }
9694b22b933Srs #endif
9704b22b933Srs 
9714b22b933Srs #if defined(IPV6_PKTINFO) && HAVE_IPV6
9725ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9735ffb0c9bSToomas Soome             cmptr->cmsg_type  == IPV6_PKTINFO) {
9744b22b933Srs             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
9755ffb0c9bSToomas Soome             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
9765ffb0c9bSToomas Soome 
9774b22b933Srs             sin6->sin6_family   = AF_INET6;
9784b22b933Srs #ifndef NOT_HAVE_SA_LEN
9794b22b933Srs             sin6->sin6_len      = sizeof(*sin6);
9804b22b933Srs #endif
9814b22b933Srs             sin6->sin6_addr     = ip6_info->ipi6_addr;
9824b22b933Srs             sin6->sin6_flowinfo = 0;
9834b22b933Srs             sin6->sin6_scope_id = 0;
9844b22b933Srs             sin6->sin6_port     = 0;
9855ffb0c9bSToomas Soome             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
9864b22b933Srs             continue;
9874b22b933Srs         }
9884b22b933Srs #endif
9894b22b933Srs 
9904b22b933Srs #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
9915ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9924b22b933Srs             cmptr->cmsg_type == IPV6_HOPLIMIT) {
9935ffb0c9bSToomas Soome             *ttl = *(int*)CMSG_DATA(cmptr);
9944b22b933Srs             continue;
9954b22b933Srs         }
9964b22b933Srs #endif
9974b22b933Srs         assert(0);  // unknown ancillary data
9984b22b933Srs     }
9994b22b933Srs     return(n);
10004b22b933Srs #endif /* CMSG_FIRSTHDR */
10014b22b933Srs }
10024b22b933Srs 
10034b22b933Srs // **********************************************************************************************
10044b22b933Srs 
10054b22b933Srs // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
10064b22b933Srs // Returns 0 on success, -1 on failure.
10074b22b933Srs 
10084b22b933Srs #ifdef NOT_HAVE_DAEMON
10094b22b933Srs #include <fcntl.h>
10104b22b933Srs #include <sys/stat.h>
10115ffb0c9bSToomas Soome #include <sys/signal.h>
10124b22b933Srs 
daemon(int nochdir,int noclose)10134b22b933Srs int daemon(int nochdir, int noclose)
10145ffb0c9bSToomas Soome {
10155ffb0c9bSToomas Soome     switch (fork())
10165ffb0c9bSToomas Soome     {
10175ffb0c9bSToomas Soome     case -1: return (-1);       // Fork failed
10185ffb0c9bSToomas Soome     case 0:  break;             // Child -- continue
10195ffb0c9bSToomas Soome     default: _exit(0);          // Parent -- exit
10205ffb0c9bSToomas Soome     }
10215ffb0c9bSToomas Soome 
10225ffb0c9bSToomas Soome     if (setsid() == -1) return(-1);
10235ffb0c9bSToomas Soome 
10245ffb0c9bSToomas Soome     signal(SIGHUP, SIG_IGN);
10255ffb0c9bSToomas Soome 
10265ffb0c9bSToomas Soome     switch (fork())             // Fork again, primarily for reasons of Unix trivia
10274b22b933Srs     {
10285ffb0c9bSToomas Soome     case -1: return (-1);       // Fork failed
10295ffb0c9bSToomas Soome     case 0:  break;             // Child -- continue
10305ffb0c9bSToomas Soome     default: _exit(0);          // Parent -- exit
10314b22b933Srs     }
10325ffb0c9bSToomas Soome 
10335ffb0c9bSToomas Soome     if (!nochdir) (void)chdir("/");
10345ffb0c9bSToomas Soome     umask(0);
10355ffb0c9bSToomas Soome 
10365ffb0c9bSToomas Soome     if (!noclose)
10375ffb0c9bSToomas Soome     {
10385ffb0c9bSToomas Soome         int fd = open("/dev/null", O_RDWR, 0);
10395ffb0c9bSToomas Soome         if (fd != -1)
10405ffb0c9bSToomas Soome         {
10415ffb0c9bSToomas Soome             // Avoid unnecessarily duplicating a file descriptor to itself
10425ffb0c9bSToomas Soome             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
10435ffb0c9bSToomas Soome             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
10445ffb0c9bSToomas Soome             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
10455ffb0c9bSToomas Soome             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
10465ffb0c9bSToomas Soome                 (void)close (fd);
10475ffb0c9bSToomas Soome         }
10485ffb0c9bSToomas Soome     }
10495ffb0c9bSToomas Soome     return (0);
10505ffb0c9bSToomas Soome }
10514b22b933Srs #endif /* NOT_HAVE_DAEMON */
1052