14b22b933Srs /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs  *
34b22b933Srs  * Copyright (c) 2002-2004 Apple Computer, 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 */
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*/
874b22b933Srs struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
885ffb0c9bSToomas Soome {
895ffb0c9bSToomas Soome     struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
90cda73f64SToomas Soome     FILE *fp = NULL;
915ffb0c9bSToomas Soome     char addr[8][5];
925ffb0c9bSToomas Soome     int flags, myflags, index, plen, scope;
935ffb0c9bSToomas Soome     char ifname[9], lastname[IFNAMSIZ];
945ffb0c9bSToomas Soome     char addr6[32+7+1]; /* don't forget the seven ':' */
955ffb0c9bSToomas Soome     struct addrinfo hints, *res0;
965ffb0c9bSToomas Soome     int err;
975ffb0c9bSToomas Soome     int sockfd = -1;
985ffb0c9bSToomas Soome     struct ifreq ifr;
995ffb0c9bSToomas Soome 
1005ffb0c9bSToomas Soome     res0=NULL;
1015ffb0c9bSToomas Soome     ifihead = NULL;
1025ffb0c9bSToomas Soome     ifipnext = &ifihead;
1035ffb0c9bSToomas Soome     lastname[0] = 0;
1044b22b933Srs 
1055ffb0c9bSToomas Soome     if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
1065ffb0c9bSToomas Soome         sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
1075ffb0c9bSToomas Soome         if (sockfd < 0) {
1085ffb0c9bSToomas Soome             goto gotError;
1095ffb0c9bSToomas Soome         }
1105ffb0c9bSToomas Soome         while (fscanf(fp,
1115ffb0c9bSToomas Soome                       "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
1125ffb0c9bSToomas Soome                       addr[0],addr[1],addr[2],addr[3],
1135ffb0c9bSToomas Soome                       addr[4],addr[5],addr[6],addr[7],
1145ffb0c9bSToomas Soome                       &index, &plen, &scope, &flags, ifname) != EOF) {
1155ffb0c9bSToomas Soome 
1165ffb0c9bSToomas Soome             myflags = 0;
1175ffb0c9bSToomas Soome             if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
1185ffb0c9bSToomas Soome                 if (doaliases == 0)
1195ffb0c9bSToomas Soome                     continue;   /* already processed this interface */
1205ffb0c9bSToomas Soome                 myflags = IFI_ALIAS;
1215ffb0c9bSToomas Soome             }
1225ffb0c9bSToomas Soome             memcpy(lastname, ifname, IFNAMSIZ);
1235ffb0c9bSToomas Soome             ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
1245ffb0c9bSToomas Soome             if (ifi == NULL) {
1255ffb0c9bSToomas Soome                 goto gotError;
1265ffb0c9bSToomas Soome             }
1275ffb0c9bSToomas Soome 
1285ffb0c9bSToomas Soome             ifipold   = *ifipnext;       /* need this later */
1295ffb0c9bSToomas Soome             ifiptr    = ifipnext;
1305ffb0c9bSToomas Soome             *ifipnext = ifi;            /* prev points to this new one */
1315ffb0c9bSToomas Soome             ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
1325ffb0c9bSToomas Soome 
1335ffb0c9bSToomas Soome             sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1345ffb0c9bSToomas Soome                     addr[0],addr[1],addr[2],addr[3],
1355ffb0c9bSToomas Soome                     addr[4],addr[5],addr[6],addr[7]);
1365ffb0c9bSToomas Soome 
1375ffb0c9bSToomas Soome             /* Add address of the interface */
1385ffb0c9bSToomas Soome             memset(&hints, 0, sizeof(hints));
1395ffb0c9bSToomas Soome             hints.ai_family = AF_INET6;
1405ffb0c9bSToomas Soome             hints.ai_flags = AI_NUMERICHOST;
1415ffb0c9bSToomas Soome             err = getaddrinfo(addr6, NULL, &hints, &res0);
1425ffb0c9bSToomas Soome             if (err) {
1435ffb0c9bSToomas Soome                 goto gotError;
1445ffb0c9bSToomas Soome             }
1455ffb0c9bSToomas Soome             ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
1465ffb0c9bSToomas Soome             if (ifi->ifi_addr == NULL) {
1475ffb0c9bSToomas Soome                 goto gotError;
1485ffb0c9bSToomas Soome             }
1495ffb0c9bSToomas Soome             memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
1505ffb0c9bSToomas Soome 
1515ffb0c9bSToomas Soome             /* Add netmask of the interface */
1525ffb0c9bSToomas Soome             char ipv6addr[INET6_ADDRSTRLEN];
1535ffb0c9bSToomas Soome             plen_to_mask(plen, ipv6addr);
1545ffb0c9bSToomas Soome             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
155cda73f64SToomas Soome             if (ifi->ifi_netmask == NULL) {
1565ffb0c9bSToomas Soome                 goto gotError;
1575ffb0c9bSToomas Soome             }
1585ffb0c9bSToomas Soome 
159cda73f64SToomas Soome             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=family;
160cda73f64SToomas Soome             ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
161cda73f64SToomas Soome             inet_pton(family, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
1625ffb0c9bSToomas Soome 
1635ffb0c9bSToomas Soome             /* Add interface name */
1645ffb0c9bSToomas Soome             memcpy(ifi->ifi_name, ifname, IFI_NAME);
1655ffb0c9bSToomas Soome 
1665ffb0c9bSToomas Soome             /* Add interface index */
1675ffb0c9bSToomas Soome             ifi->ifi_index = index;
1685ffb0c9bSToomas Soome 
1695ffb0c9bSToomas Soome             /* Add interface flags*/
1705ffb0c9bSToomas Soome             memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1715ffb0c9bSToomas Soome             if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
1725ffb0c9bSToomas Soome                 if (errno == EADDRNOTAVAIL) {
1735ffb0c9bSToomas Soome                     /*
1745ffb0c9bSToomas Soome                      * If the main interface is configured with no IP address but
1755ffb0c9bSToomas Soome                      * an alias interface exists with an IP address, you get
1765ffb0c9bSToomas Soome                      * EADDRNOTAVAIL for the main interface
1775ffb0c9bSToomas Soome                      */
1785ffb0c9bSToomas Soome                     free(ifi->ifi_addr);
179cda73f64SToomas Soome                     free(ifi->ifi_netmask);
1805ffb0c9bSToomas Soome                     free(ifi);
1815ffb0c9bSToomas Soome                     ifipnext  = ifiptr;
1825ffb0c9bSToomas Soome                     *ifipnext = ifipold;
1835ffb0c9bSToomas Soome                     continue;
1845ffb0c9bSToomas Soome                 } else {
1855ffb0c9bSToomas Soome                     goto gotError;
1865ffb0c9bSToomas Soome                 }
1875ffb0c9bSToomas Soome             }
1885ffb0c9bSToomas Soome             ifi->ifi_flags = ifr.ifr_flags;
1895ffb0c9bSToomas Soome             freeaddrinfo(res0);
1905ffb0c9bSToomas Soome             res0=NULL;
1915ffb0c9bSToomas Soome         }
1925ffb0c9bSToomas Soome     }
1935ffb0c9bSToomas Soome     goto done;
1945ffb0c9bSToomas Soome 
1955ffb0c9bSToomas Soome gotError:
1965ffb0c9bSToomas Soome     if (ifihead != NULL) {
1975ffb0c9bSToomas Soome         free_ifi_info(ifihead);
1985ffb0c9bSToomas Soome         ifihead = NULL;
1995ffb0c9bSToomas Soome     }
2005ffb0c9bSToomas Soome     if (res0 != NULL) {
2015ffb0c9bSToomas Soome         freeaddrinfo(res0);
2025ffb0c9bSToomas Soome         res0=NULL;
2035ffb0c9bSToomas Soome     }
2045ffb0c9bSToomas Soome done:
2055ffb0c9bSToomas Soome     if (sockfd != -1) {
206*c65ebfc7SToomas Soome         int rv;
207*c65ebfc7SToomas Soome         rv = close(sockfd);
208*c65ebfc7SToomas Soome         assert(rv == 0);
2095ffb0c9bSToomas Soome     }
210cda73f64SToomas Soome     if (fp != NULL) {
211cda73f64SToomas Soome         fclose(fp);
212cda73f64SToomas Soome     }
2135ffb0c9bSToomas Soome     return(ifihead);    /* pointer to first structure in linked list */
2145ffb0c9bSToomas Soome }
2155ffb0c9bSToomas Soome #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
2164b22b933Srs 
2174b22b933Srs #if HAVE_SOLARIS
2184b22b933Srs 
2194b22b933Srs /*
220cda73f64SToomas Soome  * Converts prefix length to network mask. Assumes
2214b22b933Srs  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
2224b22b933Srs  * Unlike plen_to_mask returns netmask in binary form and not
2234b22b933Srs  * in text form.
2244b22b933Srs  */
225*c65ebfc7SToomas Soome static void plen_to_netmask(int prefix, unsigned char *addr)
226*c65ebfc7SToomas Soome {
2274b22b933Srs     for (; prefix > 8; prefix -= 8)
2284b22b933Srs         *addr++ = 0xff;
2294b22b933Srs     for (; prefix > 0; prefix--)
2304b22b933Srs         *addr = (*addr >> 1) | 0x80;
2314b22b933Srs }
2324b22b933Srs 
2334b22b933Srs /*
234cda73f64SToomas Soome  * This function goes through all the IP interfaces associated with a
235cda73f64SToomas Soome  * physical interface and finds the best matched one for use by mDNS.
2364b22b933Srs  * Returns NULL when none of the IP interfaces associated with a physical
237cda73f64SToomas Soome  * interface are usable. Otherwise returns the best matched interface
2384b22b933Srs  * information and a pointer to the best matched lifreq.
2394b22b933Srs  */
2404b22b933Srs struct ifi_info *
2414b22b933Srs select_src_ifi_info_solaris(int sockfd, int numifs,
2424b22b933Srs         struct lifreq *lifrlist, const char *curifname,
2434b22b933Srs         struct lifreq **best_lifr)
2444b22b933Srs {
2454b22b933Srs     struct lifreq *lifr;
2464b22b933Srs     struct lifreq lifrcopy;
2474b22b933Srs     struct ifi_info *ifi;
2484b22b933Srs     char *chptr;
2494b22b933Srs     char cmpifname[LIFNAMSIZ];
2504b22b933Srs     int i;
2515ffb0c9bSToomas Soome     uint64_t best_lifrflags = 0;
2524b22b933Srs     uint64_t ifflags;
2534b22b933Srs 
2544b22b933Srs     *best_lifr = NULL;
2554b22b933Srs 
256cda73f64SToomas Soome     /*
2574b22b933Srs      * Check all logical interfaces associated with the physical
2584b22b933Srs      * interface and figure out which one works best for us.
2594b22b933Srs      */
2604b22b933Srs     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
2614b22b933Srs 
2624b22b933Srs         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
2634b22b933Srs             continue; /* skip interface */
2644b22b933Srs 
2654b22b933Srs         /* Strip logical interface number before checking ifname */
2664b22b933Srs         if ((chptr = strchr(cmpifname, ':')) != NULL)
2674b22b933Srs             *chptr = '\0';
2684b22b933Srs 
269cda73f64SToomas Soome         /*
2704b22b933Srs          * Check ifname to see if the logical interface is associated
2714b22b933Srs          * with the physical interface we are interested in.
2724b22b933Srs          */
2734b22b933Srs         if (strcmp(cmpifname, curifname) != 0)
2744b22b933Srs             continue;
2754b22b933Srs 
2764b22b933Srs         lifrcopy = *lifr;
2774b22b933Srs         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
2784b22b933Srs             /* interface removed */
2794b22b933Srs             if (errno == ENXIO)
2804b22b933Srs                 continue;
2814b22b933Srs             return(NULL);
2824b22b933Srs         }
2834b22b933Srs         ifflags = lifrcopy.lifr_flags;
2844b22b933Srs 
2854b22b933Srs         /* ignore address if not up */
2864b22b933Srs         if ((ifflags & IFF_UP) == 0)
2874b22b933Srs             continue;
2884b22b933Srs         /*
289cda73f64SToomas Soome          * Avoid address if any of the following flags are set:
2904b22b933Srs          *  IFF_NOXMIT: no packets transmitted over interface
2914b22b933Srs          *  IFF_NOLOCAL: no address
2924b22b933Srs          *  IFF_PRIVATE: is not advertised
2934b22b933Srs          */
294e11c3f44Smeem         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
2954b22b933Srs             continue;
2964b22b933Srs 
297cda73f64SToomas Soome        /* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
298bd670b35SErik Nordmark         if (lifr->lifr_addr.ss_family == AF_INET) {
299cda73f64SToomas Soome                struct sockaddr_in *sinptr;
300bd670b35SErik Nordmark 
301cda73f64SToomas Soome                sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
302cda73f64SToomas Soome                if (sinptr->sin_addr.s_addr == INADDR_ANY)
303cda73f64SToomas Soome                        continue;
304cda73f64SToomas Soome        }
305bd670b35SErik Nordmark 
3064b22b933Srs         if (*best_lifr != NULL) {
307cda73f64SToomas Soome             /*
3084b22b933Srs              * Check if we found a better interface by checking
3094b22b933Srs              * the flags. If flags are identical we prefer
3104b22b933Srs              * the new found interface.
3114b22b933Srs              */
3124b22b933Srs             uint64_t diff_flags = best_lifrflags ^ ifflags;
3134b22b933Srs 
3144b22b933Srs             /* If interface has a different set of flags */
3154b22b933Srs             if (diff_flags != 0) {
3164b22b933Srs                 /* Check flags in increasing order of ones we prefer */
3174b22b933Srs 
3184b22b933Srs                 /* Address temporary? */
3194b22b933Srs                 if ((diff_flags & IFF_TEMPORARY) &&
3204b22b933Srs                     (ifflags & IFF_TEMPORARY))
3214b22b933Srs                     continue;
3224b22b933Srs                 /* Deprecated address? */
3234b22b933Srs                 if ((diff_flags & IFF_DEPRECATED) &&
3244b22b933Srs                     (ifflags & IFF_DEPRECATED))
3254b22b933Srs                     continue;
3264b22b933Srs                 /* Last best-matched interface address has preferred? */
3274b22b933Srs                 if ((diff_flags & IFF_PREFERRED) &&
3284b22b933Srs                     ((ifflags & IFF_PREFERRED) == 0))
3294b22b933Srs                     continue;
3304b22b933Srs             }
3314b22b933Srs         }
3324b22b933Srs 
3334b22b933Srs         /* Set best match interface & flags */
3344b22b933Srs         *best_lifr = lifr;
3354b22b933Srs         best_lifrflags = ifflags;
3364b22b933Srs     }
3374b22b933Srs 
3384b22b933Srs     if (*best_lifr == NULL)
3394b22b933Srs         return(NULL);
3404b22b933Srs 
3414b22b933Srs     /* Found a match: return the interface information */
3424b22b933Srs     ifi = calloc(1, sizeof(struct ifi_info));
3434b22b933Srs     if (ifi == NULL)
3444b22b933Srs         return(NULL);
3454b22b933Srs 
346cda73f64SToomas Soome     ifi->ifi_flags = best_lifrflags;
3474b22b933Srs     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
3484b22b933Srs     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
3494b22b933Srs         free(ifi);
3504b22b933Srs         return(NULL);
3514b22b933Srs     }
3524b22b933Srs     return(ifi);
3534b22b933Srs }
3544b22b933Srs 
3554b22b933Srs /*
3564b22b933Srs  * Returns a list of IP interface information on Solaris. The function
3574b22b933Srs  * returns all IP interfaces on the system with IPv4 address assigned
3584b22b933Srs  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
3594b22b933Srs  * when AF_INET6 is passed.
3604b22b933Srs  */
3614b22b933Srs struct ifi_info *get_ifi_info_solaris(int family)
3624b22b933Srs {
3634b22b933Srs     struct ifi_info     *ifi, *ifihead, **ifipnext;
3644b22b933Srs     int   sockfd;
3654b22b933Srs     int  len;
3664b22b933Srs     char  *buf;
3674b22b933Srs     char *cptr;
3684b22b933Srs     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
3694b22b933Srs     struct sockaddr_in *sinptr;
3704b22b933Srs     struct lifnum lifn;
3714b22b933Srs     struct lifconf lifc;
3724b22b933Srs     struct lifreq *lifrp, *best_lifr;
3734b22b933Srs     struct lifreq lifrcopy;
3744b22b933Srs     int numifs, nlifr, n;
3754b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
3764b22b933Srs     struct sockaddr_in6 *sinptr6;
3774b22b933Srs #endif
3784b22b933Srs 
3794b22b933Srs     ifihead = NULL;
3804b22b933Srs 
3814b22b933Srs     sockfd = socket(family, SOCK_DGRAM, 0);
3824b22b933Srs     if (sockfd < 0)
3834b22b933Srs         goto gotError;
3844b22b933Srs 
3854b22b933Srs again:
3864b22b933Srs     lifn.lifn_family = family;
3874b22b933Srs     lifn.lifn_flags = 0;
3884b22b933Srs     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
3894b22b933Srs         goto gotError;
3904b22b933Srs     /*
391cda73f64SToomas Soome      * Pad interface count to detect & retrieve any
3924b22b933Srs      * additional interfaces between IFNUM & IFCONF calls.
3934b22b933Srs      */
3944b22b933Srs     lifn.lifn_count += 4;
3954b22b933Srs     numifs = lifn.lifn_count;
3964b22b933Srs     len = numifs * sizeof (struct lifreq);
3974b22b933Srs     buf = alloca(len);
3984b22b933Srs 
3994b22b933Srs     lifc.lifc_family = family;
4004b22b933Srs     lifc.lifc_len = len;
4014b22b933Srs     lifc.lifc_buf = buf;
4024b22b933Srs     lifc.lifc_flags = 0;
4034b22b933Srs 
4044b22b933Srs     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
4054b22b933Srs         goto gotError;
4064b22b933Srs 
4074b22b933Srs     nlifr = lifc.lifc_len / sizeof(struct lifreq);
4084b22b933Srs     if (nlifr >= numifs)
4094b22b933Srs         goto again;
4104b22b933Srs 
4114b22b933Srs     lifrp = lifc.lifc_req;
4124b22b933Srs     ifipnext = &ifihead;
4134b22b933Srs 
4144b22b933Srs     for (n = nlifr; n > 0; n--, lifrp++) {
4154b22b933Srs 
4164b22b933Srs         if (lifrp->lifr_addr.ss_family != family)
4174b22b933Srs             continue;
4184b22b933Srs 
419cda73f64SToomas Soome         /*
4204b22b933Srs          * See if we have already processed the interface
4214b22b933Srs          * by checking the interface names.
4224b22b933Srs          */
4234b22b933Srs         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
4244b22b933Srs             goto gotError;
4254b22b933Srs         if ((cptr = strchr(ifname, ':')) != NULL)
4264b22b933Srs             *cptr = '\0';
4274b22b933Srs 
428cda73f64SToomas Soome         /*
4294b22b933Srs          * If any of the interfaces found so far share the physical
4304b22b933Srs          * interface name then we have already processed the interface.
4314b22b933Srs          */
4324b22b933Srs         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
433cda73f64SToomas Soome 
4344b22b933Srs             /* Retrieve physical interface name */
4354b22b933Srs             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
4364b22b933Srs 
4374b22b933Srs             /* Strip logical interface number before checking ifname */
4384b22b933Srs             if ((cptr = strchr(cmpifname, ':')) != NULL)
4394b22b933Srs                 *cptr = '\0';
4404b22b933Srs 
4414b22b933Srs             if (strcmp(cmpifname, ifname) == 0)
4424b22b933Srs                 break;
4434b22b933Srs         }
4444b22b933Srs         if (ifi != NULL)
4454b22b933Srs             continue; /* already processed */
4464b22b933Srs 
447cda73f64SToomas Soome         /*
4484b22b933Srs          * New interface, find the one with the preferred source
4494b22b933Srs          * address for our use in Multicast DNS.
4504b22b933Srs          */
4514b22b933Srs         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
4524b22b933Srs             lifc.lifc_req, ifname, &best_lifr)) == NULL)
4534b22b933Srs             continue;
4544b22b933Srs 
4554b22b933Srs         assert(best_lifr != NULL);
4564b22b933Srs         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
4574b22b933Srs                (best_lifr->lifr_addr.ss_family == AF_INET));
4584b22b933Srs 
4594b22b933Srs         switch (best_lifr->lifr_addr.ss_family) {
4604b22b933Srs 
4614b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
4624b22b933Srs         case AF_INET6:
4634b22b933Srs             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
4644b22b933Srs             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
4654b22b933Srs             if (ifi->ifi_addr == NULL)
4664b22b933Srs                 goto gotError;
4674b22b933Srs             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
4684b22b933Srs 
4694b22b933Srs             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
4704b22b933Srs             if (ifi->ifi_netmask == NULL)
4714b22b933Srs                 goto gotError;
4724b22b933Srs             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
4734b22b933Srs             sinptr6->sin6_family = AF_INET6;
4744b22b933Srs             plen_to_netmask(best_lifr->lifr_addrlen,
4754b22b933Srs                     (unsigned char *) &(sinptr6->sin6_addr));
4764b22b933Srs             break;
4774b22b933Srs #endif
4784b22b933Srs 
4794b22b933Srs         case AF_INET:
4804b22b933Srs             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
4814b22b933Srs             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
4824b22b933Srs             if (ifi->ifi_addr == NULL)
4834b22b933Srs                 goto gotError;
4844b22b933Srs 
4854b22b933Srs             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
4864b22b933Srs 
4874b22b933Srs             lifrcopy = *best_lifr;
4884b22b933Srs             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
4894b22b933Srs                 /* interface removed */
4904b22b933Srs                 if (errno == ENXIO) {
4914b22b933Srs                     free(ifi->ifi_addr);
4924b22b933Srs                     free(ifi);
4934b22b933Srs                     continue;
4944b22b933Srs                 }
4954b22b933Srs                 goto gotError;
4964b22b933Srs             }
4974b22b933Srs 
4984b22b933Srs             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
499cda73f64SToomas Soome             if (ifi->ifi_netmask == NULL)
5004b22b933Srs                 goto gotError;
5014b22b933Srs             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
5024b22b933Srs             sinptr->sin_family = AF_INET;
5034b22b933Srs             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
5044b22b933Srs             break;
5054b22b933Srs 
5064b22b933Srs         default:
5074b22b933Srs             /* never reached */
5084b22b933Srs             break;
5094b22b933Srs         }
5104b22b933Srs 
5114b22b933Srs         *ifipnext = ifi;            /* prev points to this new one */
5124b22b933Srs         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
5134b22b933Srs     }
5144b22b933Srs 
5154b22b933Srs     (void) close(sockfd);
5164b22b933Srs     return(ifihead);    /* pointer to first structure in linked list */
5174b22b933Srs 
5184b22b933Srs gotError:
5194b22b933Srs     if (sockfd != -1)
5204b22b933Srs         (void) close(sockfd);
5214b22b933Srs     if (ifihead != NULL)
5224b22b933Srs         free_ifi_info(ifihead);
5234b22b933Srs     return(NULL);
5244b22b933Srs }
5254b22b933Srs 
5264b22b933Srs #endif /* HAVE_SOLARIS */
5274b22b933Srs 
5284b22b933Srs struct ifi_info *get_ifi_info(int family, int doaliases)
5294b22b933Srs {
5305ffb0c9bSToomas Soome     int junk;
5315ffb0c9bSToomas Soome     struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
5325ffb0c9bSToomas Soome     int sockfd, sockf6, len, lastlen, flags, myflags;
5334b22b933Srs #ifdef NOT_HAVE_IF_NAMETOINDEX
5345ffb0c9bSToomas Soome     int index = 200;
5354b22b933Srs #endif
5364b22b933Srs     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
5375ffb0c9bSToomas Soome     struct ifconf ifc;
5384b22b933Srs     struct ifreq        *ifr, ifrcopy;
5394b22b933Srs     struct sockaddr_in  *sinptr;
5405ffb0c9bSToomas Soome 
5414b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
5424b22b933Srs     struct sockaddr_in6 *sinptr6;
5434b22b933Srs #endif
5444b22b933Srs 
5454b22b933Srs #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
5465ffb0c9bSToomas Soome     if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
5474b22b933Srs #elif HAVE_SOLARIS
5484b22b933Srs     return get_ifi_info_solaris(family);
5494b22b933Srs #endif
5504b22b933Srs 
5514b22b933Srs     sockfd = -1;
5524b22b933Srs     sockf6 = -1;
5534b22b933Srs     buf = NULL;
5544b22b933Srs     ifihead = NULL;
5555ffb0c9bSToomas Soome 
5564b22b933Srs     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
5574b22b933Srs     if (sockfd < 0) {
5584b22b933Srs         goto gotError;
5594b22b933Srs     }
5604b22b933Srs 
5614b22b933Srs     lastlen = 0;
5624b22b933Srs     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
5634b22b933Srs     for ( ; ; ) {
5644b22b933Srs         buf = (char*)malloc(len);
5654b22b933Srs         if (buf == NULL) {
5664b22b933Srs             goto gotError;
5674b22b933Srs         }
5684b22b933Srs         ifc.ifc_len = len;
5694b22b933Srs         ifc.ifc_buf = buf;
5704b22b933Srs         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
5714b22b933Srs             if (errno != EINVAL || lastlen != 0) {
5724b22b933Srs                 goto gotError;
5734b22b933Srs             }
5744b22b933Srs         } else {
5754b22b933Srs             if (ifc.ifc_len == lastlen)
5764b22b933Srs                 break;      /* success, len has not changed */
5774b22b933Srs             lastlen = ifc.ifc_len;
5784b22b933Srs         }
5794b22b933Srs         len += 10 * sizeof(struct ifreq);   /* increment */
5804b22b933Srs         free(buf);
5814b22b933Srs     }
5824b22b933Srs     ifihead = NULL;
5834b22b933Srs     ifipnext = &ifihead;
5844b22b933Srs     lastname[0] = 0;
5854b22b933Srs /* end get_ifi_info1 */
5864b22b933Srs 
5874b22b933Srs /* include get_ifi_info2 */
5884b22b933Srs     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
5894b22b933Srs         ifr = (struct ifreq *) ptr;
5904b22b933Srs 
5914b22b933Srs         /* Advance to next one in buffer */
5924b22b933Srs         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
5934b22b933Srs             ptr += sizeof(struct ifreq);
5944b22b933Srs         else
5954b22b933Srs             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
5964b22b933Srs 
5974b22b933Srs //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
5985ffb0c9bSToomas Soome 
5994b22b933Srs         if (ifr->ifr_addr.sa_family != family)
6004b22b933Srs             continue;   /* ignore if not desired address family */
6014b22b933Srs 
6024b22b933Srs         myflags = 0;
6034b22b933Srs         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
6044b22b933Srs             *cptr = 0;      /* replace colon will null */
6054b22b933Srs         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
6064b22b933Srs             if (doaliases == 0)
6074b22b933Srs                 continue;   /* already processed this interface */
6084b22b933Srs             myflags = IFI_ALIAS;
6094b22b933Srs         }
6104b22b933Srs         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
6114b22b933Srs 
6124b22b933Srs         ifrcopy = *ifr;
6134b22b933Srs         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
6144b22b933Srs             goto gotError;
6154b22b933Srs         }
6165ffb0c9bSToomas Soome 
6174b22b933Srs         flags = ifrcopy.ifr_flags;
6184b22b933Srs         if ((flags & IFF_UP) == 0)
6194b22b933Srs             continue;   /* ignore if interface not up */
6204b22b933Srs 
6214b22b933Srs         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
6224b22b933Srs         if (ifi == NULL) {
6234b22b933Srs             goto gotError;
6244b22b933Srs         }
6255ffb0c9bSToomas Soome         ifipold   = *ifipnext;       /* need this later */
6265ffb0c9bSToomas Soome         ifiptr    = ifipnext;
6275ffb0c9bSToomas Soome         *ifipnext = ifi;             /* prev points to this new one */
6285ffb0c9bSToomas Soome         ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
6294b22b933Srs 
6304b22b933Srs         ifi->ifi_flags = flags;     /* IFF_xxx values */
6314b22b933Srs         ifi->ifi_myflags = myflags; /* IFI_xxx values */
6324b22b933Srs #ifndef NOT_HAVE_IF_NAMETOINDEX
6334b22b933Srs         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
6344b22b933Srs #else
6354b22b933Srs         ifrcopy = *ifr;
6364b22b933Srs #ifdef SIOCGIFINDEX
6374b22b933Srs         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
6384b22b933Srs             ifi->ifi_index = ifrcopy.ifr_index;
6394b22b933Srs         else
6404b22b933Srs #endif
6415ffb0c9bSToomas Soome         ifi->ifi_index = index++;       /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
6424b22b933Srs #endif
6434b22b933Srs         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
6444b22b933Srs         ifi->ifi_name[IFI_NAME-1] = '\0';
6454b22b933Srs /* end get_ifi_info2 */
6464b22b933Srs /* include get_ifi_info3 */
6474b22b933Srs         switch (ifr->ifr_addr.sa_family) {
6484b22b933Srs         case AF_INET:
6494b22b933Srs             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
6504b22b933Srs             if (ifi->ifi_addr == NULL) {
6514b22b933Srs                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6524b22b933Srs                 if (ifi->ifi_addr == NULL) {
6534b22b933Srs                     goto gotError;
6544b22b933Srs                 }
6554b22b933Srs                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
6564b22b933Srs 
6574b22b933Srs #ifdef  SIOCGIFNETMASK
6585ffb0c9bSToomas Soome                 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
6595ffb0c9bSToomas Soome                     if (errno == EADDRNOTAVAIL) {
6605ffb0c9bSToomas Soome                         /*
6615ffb0c9bSToomas Soome                          * If the main interface is configured with no IP address but
6625ffb0c9bSToomas Soome                          * an alias interface exists with an IP address, you get
6635ffb0c9bSToomas Soome                          * EADDRNOTAVAIL for the main interface
6645ffb0c9bSToomas Soome                          */
6655ffb0c9bSToomas Soome                         free(ifi->ifi_addr);
6665ffb0c9bSToomas Soome                         free(ifi);
6675ffb0c9bSToomas Soome                         ifipnext  = ifiptr;
6685ffb0c9bSToomas Soome                         *ifipnext = ifipold;
6695ffb0c9bSToomas Soome                         continue;
6705ffb0c9bSToomas Soome                     } else {
6715ffb0c9bSToomas Soome                         goto gotError;
6725ffb0c9bSToomas Soome                     }
6735ffb0c9bSToomas Soome                 }
6745ffb0c9bSToomas Soome 
6755ffb0c9bSToomas Soome                 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6765ffb0c9bSToomas Soome                 if (ifi->ifi_netmask == NULL) goto gotError;
6775ffb0c9bSToomas Soome                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
6785ffb0c9bSToomas Soome                 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
6794b22b933Srs #ifndef NOT_HAVE_SA_LEN
6805ffb0c9bSToomas Soome                 sinptr->sin_len    = sizeof(struct sockaddr_in);
6814b22b933Srs #endif
6825ffb0c9bSToomas Soome                 sinptr->sin_family = AF_INET;
6835ffb0c9bSToomas Soome                 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
6844b22b933Srs #endif
6854b22b933Srs 
6864b22b933Srs #ifdef  SIOCGIFBRDADDR
6874b22b933Srs                 if (flags & IFF_BROADCAST) {
6884b22b933Srs                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
6894b22b933Srs                         goto gotError;
6904b22b933Srs                     }
6914b22b933Srs                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
6925ffb0c9bSToomas Soome                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
6934b22b933Srs #ifndef NOT_HAVE_SA_LEN
6945ffb0c9bSToomas Soome                     sinptr->sin_len    = sizeof( struct sockaddr_in );
6954b22b933Srs #endif
6965ffb0c9bSToomas Soome                     sinptr->sin_family = AF_INET;
6974b22b933Srs                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6984b22b933Srs                     if (ifi->ifi_brdaddr == NULL) {
6994b22b933Srs                         goto gotError;
7004b22b933Srs                     }
7014b22b933Srs                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
7024b22b933Srs                 }
7034b22b933Srs #endif
7044b22b933Srs 
7054b22b933Srs #ifdef  SIOCGIFDSTADDR
7064b22b933Srs                 if (flags & IFF_POINTOPOINT) {
7074b22b933Srs                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
7084b22b933Srs                         goto gotError;
7094b22b933Srs                     }
7104b22b933Srs                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
7114b22b933Srs                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
7124b22b933Srs #ifndef NOT_HAVE_SA_LEN
7135ffb0c9bSToomas Soome                     sinptr->sin_len    = sizeof( struct sockaddr_in );
7144b22b933Srs #endif
7155ffb0c9bSToomas Soome                     sinptr->sin_family = AF_INET;
7164b22b933Srs                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
7174b22b933Srs                     if (ifi->ifi_dstaddr == NULL) {
7184b22b933Srs                         goto gotError;
7194b22b933Srs                     }
7204b22b933Srs                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
7214b22b933Srs                 }
7224b22b933Srs #endif
7234b22b933Srs             }
7244b22b933Srs             break;
7254b22b933Srs 
7264b22b933Srs #if defined(AF_INET6) && HAVE_IPV6
7274b22b933Srs         case AF_INET6:
7284b22b933Srs             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
7294b22b933Srs             if (ifi->ifi_addr == NULL) {
7304b22b933Srs                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
7314b22b933Srs                 if (ifi->ifi_addr == NULL) {
7324b22b933Srs                     goto gotError;
7334b22b933Srs                 }
7345ffb0c9bSToomas Soome 
7354b22b933Srs                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
7364b22b933Srs                 /* We need to strip that out */
7374b22b933Srs                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
7385ffb0c9bSToomas Soome                     sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
7394b22b933Srs                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
7404b22b933Srs 
7414b22b933Srs #ifdef  SIOCGIFNETMASK_IN6
7425ffb0c9bSToomas Soome                 {
7435ffb0c9bSToomas Soome                     struct in6_ifreq ifr6;
7445ffb0c9bSToomas Soome                     if (sockf6 == -1)
7455ffb0c9bSToomas Soome                         sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
7465ffb0c9bSToomas Soome                     memset(&ifr6, 0, sizeof(ifr6));
7475ffb0c9bSToomas Soome                     memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
7485ffb0c9bSToomas Soome                     memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
7495ffb0c9bSToomas Soome                     if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
7505ffb0c9bSToomas Soome                         if (errno == EADDRNOTAVAIL) {
7515ffb0c9bSToomas Soome                             /*
7525ffb0c9bSToomas Soome                              * If the main interface is configured with no IP address but
7535ffb0c9bSToomas Soome                              * an alias interface exists with an IP address, you get
7545ffb0c9bSToomas Soome                              * EADDRNOTAVAIL for the main interface
7555ffb0c9bSToomas Soome                              */
7565ffb0c9bSToomas Soome                             free(ifi->ifi_addr);
7575ffb0c9bSToomas Soome                             free(ifi);
7585ffb0c9bSToomas Soome                             ifipnext  = ifiptr;
7595ffb0c9bSToomas Soome                             *ifipnext = ifipold;
7605ffb0c9bSToomas Soome                             continue;
7615ffb0c9bSToomas Soome                         } else {
7625ffb0c9bSToomas Soome                             goto gotError;
7635ffb0c9bSToomas Soome                         }
7645ffb0c9bSToomas Soome                     }
7655ffb0c9bSToomas Soome                     ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
7665ffb0c9bSToomas Soome                     if (ifi->ifi_netmask == NULL) goto gotError;
7675ffb0c9bSToomas Soome                     sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
7685ffb0c9bSToomas Soome                     memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
7695ffb0c9bSToomas Soome                 }
7704b22b933Srs #endif
7714b22b933Srs             }
7724b22b933Srs             break;
7734b22b933Srs #endif
7744b22b933Srs 
7754b22b933Srs         default:
7764b22b933Srs             break;
7774b22b933Srs         }
7784b22b933Srs     }
7794b22b933Srs     goto done;
7805ffb0c9bSToomas Soome 
7814b22b933Srs gotError:
7824b22b933Srs     if (ifihead != NULL) {
7834b22b933Srs         free_ifi_info(ifihead);
7844b22b933Srs         ifihead = NULL;
7854b22b933Srs     }
7864b22b933Srs 
7874b22b933Srs done:
7884b22b933Srs     if (buf != NULL) {
7894b22b933Srs         free(buf);
7904b22b933Srs     }
7914b22b933Srs     if (sockfd != -1) {
7924b22b933Srs         junk = close(sockfd);
7934b22b933Srs         assert(junk == 0);
7944b22b933Srs     }
7954b22b933Srs     if (sockf6 != -1) {
7964b22b933Srs         junk = close(sockf6);
7974b22b933Srs         assert(junk == 0);
7984b22b933Srs     }
7994b22b933Srs     return(ifihead);    /* pointer to first structure in linked list */
8004b22b933Srs }
8014b22b933Srs /* end get_ifi_info3 */
8024b22b933Srs 
8034b22b933Srs /* include free_ifi_info */
8044b22b933Srs void
8054b22b933Srs free_ifi_info(struct ifi_info *ifihead)
8064b22b933Srs {
8074b22b933Srs     struct ifi_info *ifi, *ifinext;
8084b22b933Srs 
8094b22b933Srs     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
8104b22b933Srs         if (ifi->ifi_addr != NULL)
8114b22b933Srs             free(ifi->ifi_addr);
8125ffb0c9bSToomas Soome         if (ifi->ifi_netmask != NULL)
8135ffb0c9bSToomas Soome             free(ifi->ifi_netmask);
8144b22b933Srs         if (ifi->ifi_brdaddr != NULL)
8154b22b933Srs             free(ifi->ifi_brdaddr);
8164b22b933Srs         if (ifi->ifi_dstaddr != NULL)
8174b22b933Srs             free(ifi->ifi_dstaddr);
8184b22b933Srs         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
8194b22b933Srs         free(ifi);                  /* the ifi_info{} itself */
8204b22b933Srs     }
8214b22b933Srs }
8224b22b933Srs /* end free_ifi_info */
8234b22b933Srs 
8245ffb0c9bSToomas Soome ssize_t
8254b22b933Srs recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
8264b22b933Srs                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
8274b22b933Srs {
8285ffb0c9bSToomas Soome     struct msghdr msg;
8295ffb0c9bSToomas Soome     struct iovec iov[1];
8305ffb0c9bSToomas Soome     ssize_t n;
8314b22b933Srs 
8324b22b933Srs #ifdef CMSG_FIRSTHDR
8334b22b933Srs     struct cmsghdr  *cmptr;
8344b22b933Srs     union {
8355ffb0c9bSToomas Soome         struct cmsghdr cm;
8365ffb0c9bSToomas Soome         char control[1024];
8375ffb0c9bSToomas Soome 	pad64_t align8; /* ensure structure is 8-byte aligned on sparc */
8384b22b933Srs     } control_un;
8394b22b933Srs 
8405ffb0c9bSToomas Soome     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
8414b22b933Srs 
842*c65ebfc7SToomas Soome     msg.msg_control = control_un.control;
8434b22b933Srs     msg.msg_controllen = sizeof(control_un.control);
8444b22b933Srs     msg.msg_flags = 0;
8454b22b933Srs #else
8464b22b933Srs     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
8474b22b933Srs #endif /* CMSG_FIRSTHDR */
8484b22b933Srs 
8494b22b933Srs     msg.msg_name = (char *) sa;
8504b22b933Srs     msg.msg_namelen = *salenptr;
8514b22b933Srs     iov[0].iov_base = (char *)ptr;
8524b22b933Srs     iov[0].iov_len = nbytes;
8534b22b933Srs     msg.msg_iov = iov;
8544b22b933Srs     msg.msg_iovlen = 1;
8554b22b933Srs 
8564b22b933Srs     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
8574b22b933Srs         return(n);
8584b22b933Srs 
8594b22b933Srs     *salenptr = msg.msg_namelen;    /* pass back results */
8604b22b933Srs     if (pktp) {
8614b22b933Srs         /* 0.0.0.0, i/f = -1 */
8625ffb0c9bSToomas Soome         /* We set the interface to -1 so that the caller can
8635ffb0c9bSToomas Soome            tell whether we returned a meaningful value or
8645ffb0c9bSToomas Soome            just some default.  Previously this code just
8655ffb0c9bSToomas Soome            set the value to 0, but I'm concerned that 0
8664b22b933Srs            might be a valid interface value.
8675ffb0c9bSToomas Soome          */
8684b22b933Srs         memset(pktp, 0, sizeof(struct my_in_pktinfo));
8694b22b933Srs         pktp->ipi_ifindex = -1;
8704b22b933Srs     }
8714b22b933Srs /* end recvfrom_flags1 */
8724b22b933Srs 
8734b22b933Srs /* include recvfrom_flags2 */
8744b22b933Srs #ifndef CMSG_FIRSTHDR
8755ffb0c9bSToomas Soome     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
8764b22b933Srs     *flagsp = 0;                    /* pass back results */
8774b22b933Srs     return(n);
8784b22b933Srs #else
8794b22b933Srs 
8804b22b933Srs     *flagsp = msg.msg_flags;        /* pass back results */
8814b22b933Srs     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
8824b22b933Srs         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
8834b22b933Srs         return(n);
8844b22b933Srs 
8854b22b933Srs     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
8864b22b933Srs          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
8874b22b933Srs 
8884b22b933Srs #ifdef  IP_PKTINFO
8894b22b933Srs #if in_pktinfo_definition_is_missing
8905ffb0c9bSToomas Soome         struct in_pktinfo
8915ffb0c9bSToomas Soome         {
8925ffb0c9bSToomas Soome             int ipi_ifindex;
8935ffb0c9bSToomas Soome             struct in_addr ipi_spec_dst;
8945ffb0c9bSToomas Soome             struct in_addr ipi_addr;
8955ffb0c9bSToomas Soome         };
8964b22b933Srs #endif
8975ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IP &&
8984b22b933Srs             cmptr->cmsg_type == IP_PKTINFO) {
8994b22b933Srs             struct in_pktinfo *tmp;
9004b22b933Srs             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9015ffb0c9bSToomas Soome 
9024b22b933Srs             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
9034b22b933Srs             sin->sin_family = AF_INET;
9044b22b933Srs             sin->sin_addr = tmp->ipi_addr;
9054b22b933Srs             sin->sin_port = 0;
9064b22b933Srs             pktp->ipi_ifindex = tmp->ipi_ifindex;
9074b22b933Srs             continue;
9084b22b933Srs         }
9094b22b933Srs #endif
9104b22b933Srs 
9114b22b933Srs #ifdef  IP_RECVDSTADDR
9124b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9134b22b933Srs             cmptr->cmsg_type == IP_RECVDSTADDR) {
9144b22b933Srs             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9155ffb0c9bSToomas Soome 
9164b22b933Srs             sin->sin_family = AF_INET;
9174b22b933Srs             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
9184b22b933Srs             sin->sin_port = 0;
9194b22b933Srs             continue;
9204b22b933Srs         }
9214b22b933Srs #endif
9224b22b933Srs 
9234b22b933Srs #ifdef  IP_RECVIF
9244b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9254b22b933Srs             cmptr->cmsg_type == IP_RECVIF) {
9264b22b933Srs             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
9274b22b933Srs #ifndef HAVE_BROKEN_RECVIF_NAME
9284b22b933Srs             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
9294b22b933Srs             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
9304b22b933Srs #endif
931cda73f64SToomas Soome 	    /*
932cda73f64SToomas Soome 	     * the is memcpy used for sparc? no idea;)
933cda73f64SToomas Soome 	     * pktp->ipi_ifindex = sdl->sdl_index;
9345ffb0c9bSToomas Soome 	     */
935cda73f64SToomas Soome 	    (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
9365ffb0c9bSToomas Soome #ifdef HAVE_BROKEN_RECVIF_NAME
9375ffb0c9bSToomas Soome             if (sdl->sdl_index == 0) {
9385ffb0c9bSToomas Soome                 pktp->ipi_ifindex = *(uint_t*)sdl;
9395ffb0c9bSToomas Soome             }
9405ffb0c9bSToomas Soome #endif
9414b22b933Srs             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
9424b22b933Srs             // null terminated because of memset above
9434b22b933Srs             continue;
9444b22b933Srs         }
9454b22b933Srs #endif
9464b22b933Srs 
9474b22b933Srs #ifdef  IP_RECVTTL
9484b22b933Srs         if (cmptr->cmsg_level == IPPROTO_IP &&
9494b22b933Srs             cmptr->cmsg_type == IP_RECVTTL) {
9505ffb0c9bSToomas Soome             *ttl = *(u_char*)CMSG_DATA(cmptr);
9514b22b933Srs             continue;
9524b22b933Srs         }
9534b22b933Srs         else if (cmptr->cmsg_level == IPPROTO_IP &&
9545ffb0c9bSToomas Soome                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
9555ffb0c9bSToomas Soome             *ttl = *(int*)CMSG_DATA(cmptr);
9564b22b933Srs             continue;
9574b22b933Srs         }
9584b22b933Srs #endif
9594b22b933Srs 
9604b22b933Srs #if defined(IPV6_PKTINFO) && HAVE_IPV6
9615ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9625ffb0c9bSToomas Soome             cmptr->cmsg_type  == IPV6_PKTINFO) {
9634b22b933Srs             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
9645ffb0c9bSToomas Soome             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
9655ffb0c9bSToomas Soome 
9664b22b933Srs             sin6->sin6_family   = AF_INET6;
9674b22b933Srs #ifndef NOT_HAVE_SA_LEN
9684b22b933Srs             sin6->sin6_len      = sizeof(*sin6);
9694b22b933Srs #endif
9704b22b933Srs             sin6->sin6_addr     = ip6_info->ipi6_addr;
9714b22b933Srs             sin6->sin6_flowinfo = 0;
9724b22b933Srs             sin6->sin6_scope_id = 0;
9734b22b933Srs             sin6->sin6_port     = 0;
9745ffb0c9bSToomas Soome             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
9754b22b933Srs             continue;
9764b22b933Srs         }
9774b22b933Srs #endif
9784b22b933Srs 
9794b22b933Srs #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
9805ffb0c9bSToomas Soome         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9814b22b933Srs             cmptr->cmsg_type == IPV6_HOPLIMIT) {
9825ffb0c9bSToomas Soome             *ttl = *(int*)CMSG_DATA(cmptr);
9834b22b933Srs             continue;
9844b22b933Srs         }
9854b22b933Srs #endif
9864b22b933Srs         assert(0);  // unknown ancillary data
9874b22b933Srs     }
9884b22b933Srs     return(n);
9894b22b933Srs #endif /* CMSG_FIRSTHDR */
9904b22b933Srs }
9914b22b933Srs 
9924b22b933Srs // **********************************************************************************************
9934b22b933Srs 
9944b22b933Srs // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
9954b22b933Srs // Returns 0 on success, -1 on failure.
9964b22b933Srs 
9974b22b933Srs #ifdef NOT_HAVE_DAEMON
9984b22b933Srs #include <fcntl.h>
9994b22b933Srs #include <sys/stat.h>
10005ffb0c9bSToomas Soome #include <sys/signal.h>
10014b22b933Srs 
10024b22b933Srs int daemon(int nochdir, int noclose)
10035ffb0c9bSToomas Soome {
10045ffb0c9bSToomas Soome     switch (fork())
10055ffb0c9bSToomas Soome     {
10065ffb0c9bSToomas Soome     case -1: return (-1);       // Fork failed
10075ffb0c9bSToomas Soome     case 0:  break;             // Child -- continue
10085ffb0c9bSToomas Soome     default: _exit(0);          // Parent -- exit
10095ffb0c9bSToomas Soome     }
10105ffb0c9bSToomas Soome 
10115ffb0c9bSToomas Soome     if (setsid() == -1) return(-1);
10125ffb0c9bSToomas Soome 
10135ffb0c9bSToomas Soome     signal(SIGHUP, SIG_IGN);
10145ffb0c9bSToomas Soome 
10155ffb0c9bSToomas Soome     switch (fork())             // Fork again, primarily for reasons of Unix trivia
10164b22b933Srs     {
10175ffb0c9bSToomas Soome     case -1: return (-1);       // Fork failed
10185ffb0c9bSToomas Soome     case 0:  break;             // Child -- continue
10195ffb0c9bSToomas Soome     default: _exit(0);          // Parent -- exit
10204b22b933Srs     }
10215ffb0c9bSToomas Soome 
10225ffb0c9bSToomas Soome     if (!nochdir) (void)chdir("/");
10235ffb0c9bSToomas Soome     umask(0);
10245ffb0c9bSToomas Soome 
10255ffb0c9bSToomas Soome     if (!noclose)
10265ffb0c9bSToomas Soome     {
10275ffb0c9bSToomas Soome         int fd = open("/dev/null", O_RDWR, 0);
10285ffb0c9bSToomas Soome         if (fd != -1)
10295ffb0c9bSToomas Soome         {
10305ffb0c9bSToomas Soome             // Avoid unnecessarily duplicating a file descriptor to itself
10315ffb0c9bSToomas Soome             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
10325ffb0c9bSToomas Soome             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
10335ffb0c9bSToomas Soome             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
10345ffb0c9bSToomas Soome             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
10355ffb0c9bSToomas Soome                 (void)close (fd);
10365ffb0c9bSToomas Soome         }
10375ffb0c9bSToomas Soome     }
10385ffb0c9bSToomas Soome     return (0);
10395ffb0c9bSToomas Soome }
10404b22b933Srs #endif /* NOT_HAVE_DAEMON */
1041