xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNSUNP.c (revision 5ffb0c9b03b5149ff4f5821a62be4a52408ada2a)
14b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs200217  *
34b22b933Srs200217  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
44b22b933Srs200217  *
54b22b933Srs200217  * Licensed under the Apache License, Version 2.0 (the "License");
64b22b933Srs200217  * you may not use this file except in compliance with the License.
74b22b933Srs200217  * You may obtain a copy of the License at
84b22b933Srs200217  *
94b22b933Srs200217  *     http://www.apache.org/licenses/LICENSE-2.0
104b22b933Srs200217  *
114b22b933Srs200217  * Unless required by applicable law or agreed to in writing, software
124b22b933Srs200217  * distributed under the License is distributed on an "AS IS" BASIS,
134b22b933Srs200217  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144b22b933Srs200217  * See the License for the specific language governing permissions and
154b22b933Srs200217  * limitations under the License.
164b22b933Srs200217  */
174b22b933Srs200217 
184b22b933Srs200217 #include "mDNSUNP.h"
194b22b933Srs200217 
204b22b933Srs200217 #include <errno.h>
214b22b933Srs200217 #include <assert.h>
224b22b933Srs200217 #include <string.h>
234b22b933Srs200217 #include <stdlib.h>
244b22b933Srs200217 #include <sys/uio.h>
254b22b933Srs200217 #include <sys/ioctl.h>
26*5ffb0c9bSToomas Soome #include <signal.h>
274b22b933Srs200217 #include <unistd.h>
284b22b933Srs200217 #include <stdio.h>
294b22b933Srs200217 
304b22b933Srs200217 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
314b22b933Srs200217    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
324b22b933Srs200217    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
334b22b933Srs200217    should be set to the name of the header to include to get the ALIGN(P) macro.
344b22b933Srs200217  */
354b22b933Srs200217 #ifdef NEED_ALIGN_MACRO
364b22b933Srs200217 #include NEED_ALIGN_MACRO
374b22b933Srs200217 #endif
384b22b933Srs200217 
394b22b933Srs200217 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
404b22b933Srs200217    other platforms don't even have that include file.  So,
414b22b933Srs200217    if we haven't yet got a definition, let's try to find
424b22b933Srs200217    <sys/sockio.h>.
434b22b933Srs200217  */
444b22b933Srs200217 
454b22b933Srs200217 #ifndef SIOCGIFCONF
464b22b933Srs200217     #include <sys/sockio.h>
474b22b933Srs200217 #endif
484b22b933Srs200217 
494b22b933Srs200217 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
504b22b933Srs200217    so only include the header in that case.
514b22b933Srs200217  */
524b22b933Srs200217 
534b22b933Srs200217 #ifdef  IP_RECVIF
544b22b933Srs200217     #include <net/if_dl.h>
554b22b933Srs200217 #endif
564b22b933Srs200217 
574b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
584b22b933Srs200217 #if !HAVE_SOLARIS
594b22b933Srs200217 #include <net/if_var.h>
604b22b933Srs200217 #else
614b22b933Srs200217 #include <alloca.h>
624b22b933Srs200217 #endif /* !HAVE_SOLARIS */
634b22b933Srs200217 #include <netinet/in_var.h>
64*5ffb0c9bSToomas Soome // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
654b22b933Srs200217 #endif
664b22b933Srs200217 
67*5ffb0c9bSToomas Soome #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
684b22b933Srs200217 #include <netdb.h>
694b22b933Srs200217 #include <arpa/inet.h>
704b22b933Srs200217 
714b22b933Srs200217 /* Converts a prefix length to IPv6 network mask */
724b22b933Srs200217 void plen_to_mask(int plen, char *addr) {
734b22b933Srs200217     int i;
744b22b933Srs200217     int colons=7; /* Number of colons in IPv6 address */
754b22b933Srs200217     int bits_in_block=16; /* Bits per IPv6 block */
764b22b933Srs200217     for(i=0; i<=colons; i++) {
774b22b933Srs200217         int block, ones=0xffff, ones_in_block;
784b22b933Srs200217         if (plen>bits_in_block) ones_in_block=bits_in_block;
794b22b933Srs200217         else ones_in_block=plen;
804b22b933Srs200217         block = ones & (ones << (bits_in_block-ones_in_block));
814b22b933Srs200217         i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
824b22b933Srs200217         plen -= ones_in_block;
834b22b933Srs200217     }
844b22b933Srs200217 }
854b22b933Srs200217 
864b22b933Srs200217 /* Gets IPv6 interface information from the /proc filesystem in linux*/
874b22b933Srs200217 struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
884b22b933Srs200217 {
89*5ffb0c9bSToomas Soome     struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
904b22b933Srs200217     FILE *fp;
914b22b933Srs200217     char addr[8][5];
924b22b933Srs200217     int flags, myflags, index, plen, scope;
93*5ffb0c9bSToomas Soome     char ifname[9], lastname[IFNAMSIZ];
944b22b933Srs200217     char addr6[32+7+1]; /* don't forget the seven ':' */
954b22b933Srs200217     struct addrinfo hints, *res0;
964b22b933Srs200217     struct sockaddr_in6 *sin6;
974b22b933Srs200217     struct in6_addr *addrptr;
984b22b933Srs200217     int err;
99*5ffb0c9bSToomas Soome     int sockfd = -1;
100*5ffb0c9bSToomas Soome     struct ifreq ifr;
1014b22b933Srs200217 
1024b22b933Srs200217     res0=NULL;
1034b22b933Srs200217     ifihead = NULL;
1044b22b933Srs200217     ifipnext = &ifihead;
1054b22b933Srs200217     lastname[0] = 0;
1064b22b933Srs200217 
1074b22b933Srs200217     if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
108*5ffb0c9bSToomas Soome         sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
109*5ffb0c9bSToomas Soome         if (sockfd < 0) {
110*5ffb0c9bSToomas Soome             goto gotError;
111*5ffb0c9bSToomas Soome         }
1124b22b933Srs200217         while (fscanf(fp,
1134b22b933Srs200217                       "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
1144b22b933Srs200217                       addr[0],addr[1],addr[2],addr[3],
1154b22b933Srs200217                       addr[4],addr[5],addr[6],addr[7],
1164b22b933Srs200217                       &index, &plen, &scope, &flags, ifname) != EOF) {
1174b22b933Srs200217 
1184b22b933Srs200217             myflags = 0;
1194b22b933Srs200217             if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
1204b22b933Srs200217                 if (doaliases == 0)
1214b22b933Srs200217                     continue;   /* already processed this interface */
1224b22b933Srs200217                 myflags = IFI_ALIAS;
1234b22b933Srs200217             }
1244b22b933Srs200217             memcpy(lastname, ifname, IFNAMSIZ);
1254b22b933Srs200217             ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
1264b22b933Srs200217             if (ifi == NULL) {
1274b22b933Srs200217                 goto gotError;
1284b22b933Srs200217             }
1294b22b933Srs200217 
130*5ffb0c9bSToomas Soome             ifipold   = *ifipnext;       /* need this later */
131*5ffb0c9bSToomas Soome             ifiptr    = ifipnext;
1324b22b933Srs200217             *ifipnext = ifi;            /* prev points to this new one */
1334b22b933Srs200217             ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
1344b22b933Srs200217 
1354b22b933Srs200217             sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1364b22b933Srs200217                     addr[0],addr[1],addr[2],addr[3],
1374b22b933Srs200217                     addr[4],addr[5],addr[6],addr[7]);
1384b22b933Srs200217 
1394b22b933Srs200217             /* Add address of the interface */
1404b22b933Srs200217             memset(&hints, 0, sizeof(hints));
1414b22b933Srs200217             hints.ai_family = AF_INET6;
1424b22b933Srs200217             hints.ai_flags = AI_NUMERICHOST;
1434b22b933Srs200217             err = getaddrinfo(addr6, NULL, &hints, &res0);
1444b22b933Srs200217             if (err) {
1454b22b933Srs200217                 goto gotError;
1464b22b933Srs200217             }
1474b22b933Srs200217             ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
1484b22b933Srs200217             if (ifi->ifi_addr == NULL) {
1494b22b933Srs200217                 goto gotError;
1504b22b933Srs200217             }
1514b22b933Srs200217             memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
1524b22b933Srs200217 
1534b22b933Srs200217             /* Add netmask of the interface */
1544b22b933Srs200217             char ipv6addr[INET6_ADDRSTRLEN];
1554b22b933Srs200217             plen_to_mask(plen, ipv6addr);
1564b22b933Srs200217             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
1574b22b933Srs200217             if (ifi->ifi_addr == NULL) {
1584b22b933Srs200217                 goto gotError;
1594b22b933Srs200217             }
1604b22b933Srs200217             sin6=calloc(1, sizeof(struct sockaddr_in6));
1614b22b933Srs200217             addrptr=calloc(1, sizeof(struct in6_addr));
1624b22b933Srs200217             inet_pton(family, ipv6addr, addrptr);
1634b22b933Srs200217             sin6->sin6_family=family;
1644b22b933Srs200217             sin6->sin6_addr=*addrptr;
1654b22b933Srs200217             sin6->sin6_scope_id=scope;
1664b22b933Srs200217             memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
1674b22b933Srs200217             free(sin6);
1684b22b933Srs200217 
1694b22b933Srs200217 
1704b22b933Srs200217             /* Add interface name */
1714b22b933Srs200217             memcpy(ifi->ifi_name, ifname, IFI_NAME);
1724b22b933Srs200217 
1734b22b933Srs200217             /* Add interface index */
1744b22b933Srs200217             ifi->ifi_index = index;
1754b22b933Srs200217 
176*5ffb0c9bSToomas Soome             /* Add interface flags*/
177*5ffb0c9bSToomas Soome             memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
178*5ffb0c9bSToomas Soome             if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
179*5ffb0c9bSToomas Soome                 if (errno == EADDRNOTAVAIL) {
180*5ffb0c9bSToomas Soome                     /*
181*5ffb0c9bSToomas Soome                      * If the main interface is configured with no IP address but
182*5ffb0c9bSToomas Soome                      * an alias interface exists with an IP address, you get
183*5ffb0c9bSToomas Soome                      * EADDRNOTAVAIL for the main interface
184*5ffb0c9bSToomas Soome                      */
185*5ffb0c9bSToomas Soome                     free(ifi->ifi_addr);
186*5ffb0c9bSToomas Soome                     free(ifi);
187*5ffb0c9bSToomas Soome                     ifipnext  = ifiptr;
188*5ffb0c9bSToomas Soome                     *ifipnext = ifipold;
189*5ffb0c9bSToomas Soome                     continue;
190*5ffb0c9bSToomas Soome                 } else {
191*5ffb0c9bSToomas Soome                     goto gotError;
192*5ffb0c9bSToomas Soome                 }
193*5ffb0c9bSToomas Soome             }
194*5ffb0c9bSToomas Soome             ifi->ifi_flags = ifr.ifr_flags;
1954b22b933Srs200217             freeaddrinfo(res0);
1964b22b933Srs200217             res0=NULL;
1974b22b933Srs200217         }
1984b22b933Srs200217     }
1994b22b933Srs200217     goto done;
2004b22b933Srs200217 
2014b22b933Srs200217 gotError:
2024b22b933Srs200217     if (ifihead != NULL) {
2034b22b933Srs200217         free_ifi_info(ifihead);
2044b22b933Srs200217         ifihead = NULL;
2054b22b933Srs200217     }
2064b22b933Srs200217     if (res0 != NULL) {
2074b22b933Srs200217         freeaddrinfo(res0);
2084b22b933Srs200217         res0=NULL;
2094b22b933Srs200217     }
2104b22b933Srs200217 done:
211*5ffb0c9bSToomas Soome     if (sockfd != -1) {
212*5ffb0c9bSToomas Soome         assert(close(sockfd) == 0);
213*5ffb0c9bSToomas Soome     }
2144b22b933Srs200217     return(ifihead);    /* pointer to first structure in linked list */
2154b22b933Srs200217 }
216*5ffb0c9bSToomas Soome #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
2174b22b933Srs200217 
2184b22b933Srs200217 #if HAVE_SOLARIS
2194b22b933Srs200217 
2204b22b933Srs200217 /*
2214b22b933Srs200217  * Converts prefix length to network mask. Assumes
2224b22b933Srs200217  * addr points to a zeroed out buffer and prefix <= sizeof(addr)
2234b22b933Srs200217  * Unlike plen_to_mask returns netmask in binary form and not
2244b22b933Srs200217  * in text form.
2254b22b933Srs200217  */
2264b22b933Srs200217 static void plen_to_netmask(int prefix, unsigned char *addr) {
2274b22b933Srs200217     for (; prefix > 8; prefix -= 8)
2284b22b933Srs200217         *addr++ = 0xff;
2294b22b933Srs200217     for (; prefix > 0; prefix--)
2304b22b933Srs200217         *addr = (*addr >> 1) | 0x80;
2314b22b933Srs200217 }
2324b22b933Srs200217 
2334b22b933Srs200217 /*
2344b22b933Srs200217  * This function goes through all the IP interfaces associated with a
2354b22b933Srs200217  * physical interface and finds the best matched one for use by mDNS.
2364b22b933Srs200217  * Returns NULL when none of the IP interfaces associated with a physical
2374b22b933Srs200217  * interface are usable. Otherwise returns the best matched interface
2384b22b933Srs200217  * information and a pointer to the best matched lifreq.
2394b22b933Srs200217  */
2404b22b933Srs200217 struct ifi_info *
2414b22b933Srs200217 select_src_ifi_info_solaris(int sockfd, int numifs,
2424b22b933Srs200217         struct lifreq *lifrlist, const char *curifname,
2434b22b933Srs200217         struct lifreq **best_lifr)
2444b22b933Srs200217 {
2454b22b933Srs200217     struct lifreq *lifr;
2464b22b933Srs200217     struct lifreq lifrcopy;
2474b22b933Srs200217     struct ifi_info *ifi;
2484b22b933Srs200217     char *chptr;
2494b22b933Srs200217     char cmpifname[LIFNAMSIZ];
2504b22b933Srs200217     int i;
251*5ffb0c9bSToomas Soome     uint64_t best_lifrflags = 0;
2524b22b933Srs200217     uint64_t ifflags;
2534b22b933Srs200217 
2544b22b933Srs200217     *best_lifr = NULL;
2554b22b933Srs200217 
2564b22b933Srs200217     /*
2574b22b933Srs200217      * Check all logical interfaces associated with the physical
2584b22b933Srs200217      * interface and figure out which one works best for us.
2594b22b933Srs200217      */
2604b22b933Srs200217     for (i = numifs, lifr = lifrlist; i > 0; --i, ++lifr) {
2614b22b933Srs200217 
2624b22b933Srs200217         if (strlcpy(cmpifname, lifr->lifr_name, sizeof(cmpifname)) >= sizeof(cmpifname))
2634b22b933Srs200217             continue; /* skip interface */
2644b22b933Srs200217 
2654b22b933Srs200217         /* Strip logical interface number before checking ifname */
2664b22b933Srs200217         if ((chptr = strchr(cmpifname, ':')) != NULL)
2674b22b933Srs200217             *chptr = '\0';
2684b22b933Srs200217 
2694b22b933Srs200217         /*
2704b22b933Srs200217          * Check ifname to see if the logical interface is associated
2714b22b933Srs200217          * with the physical interface we are interested in.
2724b22b933Srs200217          */
2734b22b933Srs200217         if (strcmp(cmpifname, curifname) != 0)
2744b22b933Srs200217             continue;
2754b22b933Srs200217 
2764b22b933Srs200217         lifrcopy = *lifr;
2774b22b933Srs200217         if (ioctl(sockfd, SIOCGLIFFLAGS, &lifrcopy) < 0) {
2784b22b933Srs200217             /* interface removed */
2794b22b933Srs200217             if (errno == ENXIO)
2804b22b933Srs200217                 continue;
2814b22b933Srs200217             return(NULL);
2824b22b933Srs200217         }
2834b22b933Srs200217         ifflags = lifrcopy.lifr_flags;
2844b22b933Srs200217 
2854b22b933Srs200217         /* ignore address if not up */
2864b22b933Srs200217         if ((ifflags & IFF_UP) == 0)
2874b22b933Srs200217             continue;
2884b22b933Srs200217         /*
2894b22b933Srs200217          * Avoid address if any of the following flags are set:
2904b22b933Srs200217          *  IFF_NOXMIT: no packets transmitted over interface
2914b22b933Srs200217          *  IFF_NOLOCAL: no address
2924b22b933Srs200217          *  IFF_PRIVATE: is not advertised
2934b22b933Srs200217          */
294e11c3f44Smeem         if (ifflags & (IFF_NOXMIT | IFF_NOLOCAL | IFF_PRIVATE))
2954b22b933Srs200217             continue;
2964b22b933Srs200217 
297bd670b35SErik Nordmark 	/* A DHCP client will have IFF_UP set yet the address is zero. Ignore */
298bd670b35SErik Nordmark         if (lifr->lifr_addr.ss_family == AF_INET) {
299bd670b35SErik Nordmark 		struct sockaddr_in *sinptr;
300bd670b35SErik Nordmark 
301bd670b35SErik Nordmark 		sinptr = (struct sockaddr_in *) &lifr->lifr_addr;
302bd670b35SErik Nordmark 		if (sinptr->sin_addr.s_addr == INADDR_ANY)
303bd670b35SErik Nordmark 			continue;
304bd670b35SErik Nordmark 	}
305bd670b35SErik Nordmark 
3064b22b933Srs200217         if (*best_lifr != NULL) {
3074b22b933Srs200217             /*
3084b22b933Srs200217              * Check if we found a better interface by checking
3094b22b933Srs200217              * the flags. If flags are identical we prefer
3104b22b933Srs200217              * the new found interface.
3114b22b933Srs200217              */
3124b22b933Srs200217             uint64_t diff_flags = best_lifrflags ^ ifflags;
3134b22b933Srs200217 
3144b22b933Srs200217             /* If interface has a different set of flags */
3154b22b933Srs200217             if (diff_flags != 0) {
3164b22b933Srs200217                 /* Check flags in increasing order of ones we prefer */
3174b22b933Srs200217 
3184b22b933Srs200217                 /* Address temporary? */
3194b22b933Srs200217                 if ((diff_flags & IFF_TEMPORARY) &&
3204b22b933Srs200217                     (ifflags & IFF_TEMPORARY))
3214b22b933Srs200217                     continue;
3224b22b933Srs200217                 /* Deprecated address? */
3234b22b933Srs200217                 if ((diff_flags & IFF_DEPRECATED) &&
3244b22b933Srs200217                     (ifflags & IFF_DEPRECATED))
3254b22b933Srs200217                     continue;
3264b22b933Srs200217                 /* Last best-matched interface address has preferred? */
3274b22b933Srs200217                 if ((diff_flags & IFF_PREFERRED) &&
3284b22b933Srs200217                     ((ifflags & IFF_PREFERRED) == 0))
3294b22b933Srs200217                     continue;
3304b22b933Srs200217             }
3314b22b933Srs200217         }
3324b22b933Srs200217 
3334b22b933Srs200217         /* Set best match interface & flags */
3344b22b933Srs200217         *best_lifr = lifr;
3354b22b933Srs200217         best_lifrflags = ifflags;
3364b22b933Srs200217     }
3374b22b933Srs200217 
3384b22b933Srs200217     if (*best_lifr == NULL)
3394b22b933Srs200217         return(NULL);
3404b22b933Srs200217 
3414b22b933Srs200217     /* Found a match: return the interface information */
3424b22b933Srs200217     ifi = calloc(1, sizeof(struct ifi_info));
3434b22b933Srs200217     if (ifi == NULL)
3444b22b933Srs200217         return(NULL);
3454b22b933Srs200217 
3464b22b933Srs200217     ifi->ifi_flags = best_lifrflags;
3474b22b933Srs200217     ifi->ifi_index = if_nametoindex((*best_lifr)->lifr_name);
3484b22b933Srs200217     if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
3494b22b933Srs200217         free(ifi);
3504b22b933Srs200217         return(NULL);
3514b22b933Srs200217     }
3524b22b933Srs200217     return(ifi);
3534b22b933Srs200217 }
3544b22b933Srs200217 
3554b22b933Srs200217 /*
3564b22b933Srs200217  * Returns a list of IP interface information on Solaris. The function
3574b22b933Srs200217  * returns all IP interfaces on the system with IPv4 address assigned
3584b22b933Srs200217  * when passed AF_INET and returns IP interfaces with IPv6 address assigned
3594b22b933Srs200217  * when AF_INET6 is passed.
3604b22b933Srs200217  */
3614b22b933Srs200217 struct ifi_info *get_ifi_info_solaris(int family)
3624b22b933Srs200217 {
3634b22b933Srs200217     struct ifi_info     *ifi, *ifihead, **ifipnext;
3644b22b933Srs200217     int   sockfd;
3654b22b933Srs200217     int  len;
3664b22b933Srs200217     char  *buf;
3674b22b933Srs200217     char *cptr;
3684b22b933Srs200217     char  ifname[LIFNAMSIZ], cmpifname[LIFNAMSIZ];
3694b22b933Srs200217     struct sockaddr_in *sinptr;
3704b22b933Srs200217     struct lifnum lifn;
3714b22b933Srs200217     struct lifconf lifc;
3724b22b933Srs200217     struct lifreq *lifrp, *best_lifr;
3734b22b933Srs200217     struct lifreq lifrcopy;
3744b22b933Srs200217     int numifs, nlifr, n;
3754b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6
3764b22b933Srs200217     struct sockaddr_in6 *sinptr6;
3774b22b933Srs200217 #endif
3784b22b933Srs200217 
3794b22b933Srs200217     ifihead = NULL;
3804b22b933Srs200217 
3814b22b933Srs200217     sockfd = socket(family, SOCK_DGRAM, 0);
3824b22b933Srs200217     if (sockfd < 0)
3834b22b933Srs200217         goto gotError;
3844b22b933Srs200217 
3854b22b933Srs200217 again:
3864b22b933Srs200217     lifn.lifn_family = family;
3874b22b933Srs200217     lifn.lifn_flags = 0;
3884b22b933Srs200217     if (ioctl(sockfd, SIOCGLIFNUM, &lifn) < 0)
3894b22b933Srs200217         goto gotError;
3904b22b933Srs200217     /*
3914b22b933Srs200217      * Pad interface count to detect & retrieve any
3924b22b933Srs200217      * additional interfaces between IFNUM & IFCONF calls.
3934b22b933Srs200217      */
3944b22b933Srs200217     lifn.lifn_count += 4;
3954b22b933Srs200217     numifs = lifn.lifn_count;
3964b22b933Srs200217     len = numifs * sizeof (struct lifreq);
3974b22b933Srs200217     buf = alloca(len);
3984b22b933Srs200217 
3994b22b933Srs200217     lifc.lifc_family = family;
4004b22b933Srs200217     lifc.lifc_len = len;
4014b22b933Srs200217     lifc.lifc_buf = buf;
4024b22b933Srs200217     lifc.lifc_flags = 0;
4034b22b933Srs200217 
4044b22b933Srs200217     if (ioctl(sockfd, SIOCGLIFCONF, &lifc) < 0)
4054b22b933Srs200217         goto gotError;
4064b22b933Srs200217 
4074b22b933Srs200217     nlifr = lifc.lifc_len / sizeof(struct lifreq);
4084b22b933Srs200217     if (nlifr >= numifs)
4094b22b933Srs200217         goto again;
4104b22b933Srs200217 
4114b22b933Srs200217     lifrp = lifc.lifc_req;
4124b22b933Srs200217     ifipnext = &ifihead;
4134b22b933Srs200217 
4144b22b933Srs200217     for (n = nlifr; n > 0; n--, lifrp++) {
4154b22b933Srs200217 
4164b22b933Srs200217         if (lifrp->lifr_addr.ss_family != family)
4174b22b933Srs200217             continue;
4184b22b933Srs200217 
4194b22b933Srs200217         /*
4204b22b933Srs200217          * See if we have already processed the interface
4214b22b933Srs200217          * by checking the interface names.
4224b22b933Srs200217          */
4234b22b933Srs200217         if (strlcpy(ifname, lifrp->lifr_name, sizeof(ifname)) >= sizeof(ifname))
4244b22b933Srs200217             goto gotError;
4254b22b933Srs200217         if ((cptr = strchr(ifname, ':')) != NULL)
4264b22b933Srs200217             *cptr = '\0';
4274b22b933Srs200217 
4284b22b933Srs200217         /*
4294b22b933Srs200217          * If any of the interfaces found so far share the physical
4304b22b933Srs200217          * interface name then we have already processed the interface.
4314b22b933Srs200217          */
4324b22b933Srs200217         for (ifi = ifihead; ifi != NULL; ifi = ifi->ifi_next) {
4334b22b933Srs200217 
4344b22b933Srs200217             /* Retrieve physical interface name */
4354b22b933Srs200217             (void) strlcpy(cmpifname, ifi->ifi_name, sizeof(cmpifname));
4364b22b933Srs200217 
4374b22b933Srs200217             /* Strip logical interface number before checking ifname */
4384b22b933Srs200217             if ((cptr = strchr(cmpifname, ':')) != NULL)
4394b22b933Srs200217                 *cptr = '\0';
4404b22b933Srs200217 
4414b22b933Srs200217             if (strcmp(cmpifname, ifname) == 0)
4424b22b933Srs200217                 break;
4434b22b933Srs200217         }
4444b22b933Srs200217         if (ifi != NULL)
4454b22b933Srs200217             continue; /* already processed */
4464b22b933Srs200217 
4474b22b933Srs200217         /*
4484b22b933Srs200217          * New interface, find the one with the preferred source
4494b22b933Srs200217          * address for our use in Multicast DNS.
4504b22b933Srs200217          */
4514b22b933Srs200217         if ((ifi = select_src_ifi_info_solaris(sockfd, nlifr,
4524b22b933Srs200217             lifc.lifc_req, ifname, &best_lifr)) == NULL)
4534b22b933Srs200217             continue;
4544b22b933Srs200217 
4554b22b933Srs200217         assert(best_lifr != NULL);
4564b22b933Srs200217         assert((best_lifr->lifr_addr.ss_family == AF_INET6) ||
4574b22b933Srs200217                (best_lifr->lifr_addr.ss_family == AF_INET));
4584b22b933Srs200217 
4594b22b933Srs200217         switch (best_lifr->lifr_addr.ss_family) {
4604b22b933Srs200217 
4614b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6
4624b22b933Srs200217         case AF_INET6:
4634b22b933Srs200217             sinptr6 = (struct sockaddr_in6 *) &best_lifr->lifr_addr;
4644b22b933Srs200217             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6));
4654b22b933Srs200217             if (ifi->ifi_addr == NULL)
4664b22b933Srs200217                 goto gotError;
4674b22b933Srs200217             memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
4684b22b933Srs200217 
4694b22b933Srs200217             ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
4704b22b933Srs200217             if (ifi->ifi_netmask == NULL)
4714b22b933Srs200217                 goto gotError;
4724b22b933Srs200217             sinptr6 = (struct sockaddr_in6 *)(ifi->ifi_netmask);
4734b22b933Srs200217             sinptr6->sin6_family = AF_INET6;
4744b22b933Srs200217             plen_to_netmask(best_lifr->lifr_addrlen,
4754b22b933Srs200217                     (unsigned char *) &(sinptr6->sin6_addr));
4764b22b933Srs200217             break;
4774b22b933Srs200217 #endif
4784b22b933Srs200217 
4794b22b933Srs200217         case AF_INET:
4804b22b933Srs200217             sinptr = (struct sockaddr_in *) &best_lifr->lifr_addr;
4814b22b933Srs200217             ifi->ifi_addr = malloc(sizeof(struct sockaddr_in));
4824b22b933Srs200217             if (ifi->ifi_addr == NULL)
4834b22b933Srs200217                 goto gotError;
4844b22b933Srs200217 
4854b22b933Srs200217             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
4864b22b933Srs200217 
4874b22b933Srs200217             lifrcopy = *best_lifr;
4884b22b933Srs200217             if (ioctl(sockfd, SIOCGLIFNETMASK, &lifrcopy) < 0) {
4894b22b933Srs200217                 /* interface removed */
4904b22b933Srs200217                 if (errno == ENXIO) {
4914b22b933Srs200217                     free(ifi->ifi_addr);
4924b22b933Srs200217                     free(ifi);
4934b22b933Srs200217                     continue;
4944b22b933Srs200217                 }
4954b22b933Srs200217                 goto gotError;
4964b22b933Srs200217             }
4974b22b933Srs200217 
4984b22b933Srs200217             ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in));
4994b22b933Srs200217             if (ifi->ifi_netmask == NULL)
5004b22b933Srs200217                 goto gotError;
5014b22b933Srs200217             sinptr = (struct sockaddr_in *) &lifrcopy.lifr_addr;
5024b22b933Srs200217             sinptr->sin_family = AF_INET;
5034b22b933Srs200217             memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
5044b22b933Srs200217             break;
5054b22b933Srs200217 
5064b22b933Srs200217         default:
5074b22b933Srs200217             /* never reached */
5084b22b933Srs200217             break;
5094b22b933Srs200217         }
5104b22b933Srs200217 
5114b22b933Srs200217         *ifipnext = ifi;            /* prev points to this new one */
5124b22b933Srs200217         ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
5134b22b933Srs200217     }
5144b22b933Srs200217 
5154b22b933Srs200217     (void) close(sockfd);
5164b22b933Srs200217     return(ifihead);    /* pointer to first structure in linked list */
5174b22b933Srs200217 
5184b22b933Srs200217 gotError:
5194b22b933Srs200217     if (sockfd != -1)
5204b22b933Srs200217         (void) close(sockfd);
5214b22b933Srs200217     if (ifihead != NULL)
5224b22b933Srs200217         free_ifi_info(ifihead);
5234b22b933Srs200217     return(NULL);
5244b22b933Srs200217 }
5254b22b933Srs200217 
5264b22b933Srs200217 #endif /* HAVE_SOLARIS */
5274b22b933Srs200217 
5284b22b933Srs200217 struct ifi_info *get_ifi_info(int family, int doaliases)
5294b22b933Srs200217 {
5304b22b933Srs200217     int junk;
531*5ffb0c9bSToomas Soome     struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
5324b22b933Srs200217     int sockfd, sockf6, len, lastlen, flags, myflags;
5334b22b933Srs200217 #ifdef NOT_HAVE_IF_NAMETOINDEX
5344b22b933Srs200217     int index = 200;
5354b22b933Srs200217 #endif
5364b22b933Srs200217     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
5374b22b933Srs200217     struct ifconf ifc;
5384b22b933Srs200217     struct ifreq        *ifr, ifrcopy;
5394b22b933Srs200217     struct sockaddr_in  *sinptr;
5404b22b933Srs200217 
5414b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6
5424b22b933Srs200217     struct sockaddr_in6 *sinptr6;
5434b22b933Srs200217 #endif
5444b22b933Srs200217 
5454b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
5464b22b933Srs200217     if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
5474b22b933Srs200217 #elif HAVE_SOLARIS
5484b22b933Srs200217     return get_ifi_info_solaris(family);
5494b22b933Srs200217 #endif
5504b22b933Srs200217 
5514b22b933Srs200217     sockfd = -1;
5524b22b933Srs200217     sockf6 = -1;
5534b22b933Srs200217     buf = NULL;
5544b22b933Srs200217     ifihead = NULL;
5554b22b933Srs200217 
5564b22b933Srs200217     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
5574b22b933Srs200217     if (sockfd < 0) {
5584b22b933Srs200217         goto gotError;
5594b22b933Srs200217     }
5604b22b933Srs200217 
5614b22b933Srs200217     lastlen = 0;
5624b22b933Srs200217     len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
5634b22b933Srs200217     for ( ; ; ) {
5644b22b933Srs200217         buf = (char*)malloc(len);
5654b22b933Srs200217         if (buf == NULL) {
5664b22b933Srs200217             goto gotError;
5674b22b933Srs200217         }
5684b22b933Srs200217         ifc.ifc_len = len;
5694b22b933Srs200217         ifc.ifc_buf = buf;
5704b22b933Srs200217         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
5714b22b933Srs200217             if (errno != EINVAL || lastlen != 0) {
5724b22b933Srs200217                 goto gotError;
5734b22b933Srs200217             }
5744b22b933Srs200217         } else {
5754b22b933Srs200217             if (ifc.ifc_len == lastlen)
5764b22b933Srs200217                 break;      /* success, len has not changed */
5774b22b933Srs200217             lastlen = ifc.ifc_len;
5784b22b933Srs200217         }
5794b22b933Srs200217         len += 10 * sizeof(struct ifreq);   /* increment */
5804b22b933Srs200217         free(buf);
5814b22b933Srs200217     }
5824b22b933Srs200217     ifihead = NULL;
5834b22b933Srs200217     ifipnext = &ifihead;
5844b22b933Srs200217     lastname[0] = 0;
5854b22b933Srs200217 /* end get_ifi_info1 */
5864b22b933Srs200217 
5874b22b933Srs200217 /* include get_ifi_info2 */
5884b22b933Srs200217     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
5894b22b933Srs200217         ifr = (struct ifreq *) ptr;
5904b22b933Srs200217 
5914b22b933Srs200217         /* Advance to next one in buffer */
5924b22b933Srs200217         if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
5934b22b933Srs200217             ptr += sizeof(struct ifreq);
5944b22b933Srs200217         else
5954b22b933Srs200217             ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
5964b22b933Srs200217 
5974b22b933Srs200217 //      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
5984b22b933Srs200217 
5994b22b933Srs200217         if (ifr->ifr_addr.sa_family != family)
6004b22b933Srs200217             continue;   /* ignore if not desired address family */
6014b22b933Srs200217 
6024b22b933Srs200217         myflags = 0;
6034b22b933Srs200217         if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
6044b22b933Srs200217             *cptr = 0;      /* replace colon will null */
6054b22b933Srs200217         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
6064b22b933Srs200217             if (doaliases == 0)
6074b22b933Srs200217                 continue;   /* already processed this interface */
6084b22b933Srs200217             myflags = IFI_ALIAS;
6094b22b933Srs200217         }
6104b22b933Srs200217         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
6114b22b933Srs200217 
6124b22b933Srs200217         ifrcopy = *ifr;
6134b22b933Srs200217         if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
6144b22b933Srs200217             goto gotError;
6154b22b933Srs200217         }
6164b22b933Srs200217 
6174b22b933Srs200217         flags = ifrcopy.ifr_flags;
6184b22b933Srs200217         if ((flags & IFF_UP) == 0)
6194b22b933Srs200217             continue;   /* ignore if interface not up */
6204b22b933Srs200217 
6214b22b933Srs200217         ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
6224b22b933Srs200217         if (ifi == NULL) {
6234b22b933Srs200217             goto gotError;
6244b22b933Srs200217         }
625*5ffb0c9bSToomas Soome         ifipold   = *ifipnext;       /* need this later */
626*5ffb0c9bSToomas Soome         ifiptr    = ifipnext;
6274b22b933Srs200217         *ifipnext = ifi;             /* prev points to this new one */
6284b22b933Srs200217         ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
6294b22b933Srs200217 
6304b22b933Srs200217         ifi->ifi_flags = flags;     /* IFF_xxx values */
6314b22b933Srs200217         ifi->ifi_myflags = myflags; /* IFI_xxx values */
6324b22b933Srs200217 #ifndef NOT_HAVE_IF_NAMETOINDEX
6334b22b933Srs200217         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
6344b22b933Srs200217 #else
6354b22b933Srs200217         ifrcopy = *ifr;
6364b22b933Srs200217 #ifdef SIOCGIFINDEX
6374b22b933Srs200217         if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
6384b22b933Srs200217             ifi->ifi_index = ifrcopy.ifr_index;
6394b22b933Srs200217         else
6404b22b933Srs200217 #endif
6414b22b933Srs200217         ifi->ifi_index = index++;       /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
6424b22b933Srs200217 #endif
6434b22b933Srs200217         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
6444b22b933Srs200217         ifi->ifi_name[IFI_NAME-1] = '\0';
6454b22b933Srs200217 /* end get_ifi_info2 */
6464b22b933Srs200217 /* include get_ifi_info3 */
6474b22b933Srs200217         switch (ifr->ifr_addr.sa_family) {
6484b22b933Srs200217         case AF_INET:
6494b22b933Srs200217             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
6504b22b933Srs200217             if (ifi->ifi_addr == NULL) {
6514b22b933Srs200217                 ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6524b22b933Srs200217                 if (ifi->ifi_addr == NULL) {
6534b22b933Srs200217                     goto gotError;
6544b22b933Srs200217                 }
6554b22b933Srs200217                 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
6564b22b933Srs200217 
6574b22b933Srs200217 #ifdef  SIOCGIFNETMASK
658*5ffb0c9bSToomas Soome                 if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
659*5ffb0c9bSToomas Soome                     if (errno == EADDRNOTAVAIL) {
660*5ffb0c9bSToomas Soome                         /*
661*5ffb0c9bSToomas Soome                          * If the main interface is configured with no IP address but
662*5ffb0c9bSToomas Soome                          * an alias interface exists with an IP address, you get
663*5ffb0c9bSToomas Soome                          * EADDRNOTAVAIL for the main interface
664*5ffb0c9bSToomas Soome                          */
665*5ffb0c9bSToomas Soome                         free(ifi->ifi_addr);
666*5ffb0c9bSToomas Soome                         free(ifi);
667*5ffb0c9bSToomas Soome                         ifipnext  = ifiptr;
668*5ffb0c9bSToomas Soome                         *ifipnext = ifipold;
669*5ffb0c9bSToomas Soome                         continue;
670*5ffb0c9bSToomas Soome                     } else {
671*5ffb0c9bSToomas Soome                         goto gotError;
672*5ffb0c9bSToomas Soome                     }
673*5ffb0c9bSToomas Soome                 }
674*5ffb0c9bSToomas Soome 
6754b22b933Srs200217                 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6764b22b933Srs200217                 if (ifi->ifi_netmask == NULL) goto gotError;
6774b22b933Srs200217                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
6784b22b933Srs200217                 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
6794b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
6804b22b933Srs200217                 sinptr->sin_len    = sizeof(struct sockaddr_in);
6814b22b933Srs200217 #endif
6824b22b933Srs200217                 sinptr->sin_family = AF_INET;
6834b22b933Srs200217                 memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
6844b22b933Srs200217 #endif
6854b22b933Srs200217 
6864b22b933Srs200217 #ifdef  SIOCGIFBRDADDR
6874b22b933Srs200217                 if (flags & IFF_BROADCAST) {
6884b22b933Srs200217                     if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
6894b22b933Srs200217                         goto gotError;
6904b22b933Srs200217                     }
6914b22b933Srs200217                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
6924b22b933Srs200217                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
6934b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
6944b22b933Srs200217                     sinptr->sin_len    = sizeof( struct sockaddr_in );
6954b22b933Srs200217 #endif
6964b22b933Srs200217                     sinptr->sin_family = AF_INET;
6974b22b933Srs200217                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
6984b22b933Srs200217                     if (ifi->ifi_brdaddr == NULL) {
6994b22b933Srs200217                         goto gotError;
7004b22b933Srs200217                     }
7014b22b933Srs200217                     memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
7024b22b933Srs200217                 }
7034b22b933Srs200217 #endif
7044b22b933Srs200217 
7054b22b933Srs200217 #ifdef  SIOCGIFDSTADDR
7064b22b933Srs200217                 if (flags & IFF_POINTOPOINT) {
7074b22b933Srs200217                     if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
7084b22b933Srs200217                         goto gotError;
7094b22b933Srs200217                     }
7104b22b933Srs200217                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
7114b22b933Srs200217                     /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
7124b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
7134b22b933Srs200217                     sinptr->sin_len    = sizeof( struct sockaddr_in );
7144b22b933Srs200217 #endif
7154b22b933Srs200217                     sinptr->sin_family = AF_INET;
7164b22b933Srs200217                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
7174b22b933Srs200217                     if (ifi->ifi_dstaddr == NULL) {
7184b22b933Srs200217                         goto gotError;
7194b22b933Srs200217                     }
7204b22b933Srs200217                     memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
7214b22b933Srs200217                 }
7224b22b933Srs200217 #endif
7234b22b933Srs200217             }
7244b22b933Srs200217             break;
7254b22b933Srs200217 
7264b22b933Srs200217 #if defined(AF_INET6) && HAVE_IPV6
7274b22b933Srs200217         case AF_INET6:
7284b22b933Srs200217             sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
7294b22b933Srs200217             if (ifi->ifi_addr == NULL) {
7304b22b933Srs200217                 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
7314b22b933Srs200217                 if (ifi->ifi_addr == NULL) {
7324b22b933Srs200217                     goto gotError;
7334b22b933Srs200217                 }
7344b22b933Srs200217 
7354b22b933Srs200217                 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
7364b22b933Srs200217                 /* We need to strip that out */
7374b22b933Srs200217                 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
7384b22b933Srs200217                     sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
7394b22b933Srs200217                 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
7404b22b933Srs200217 
7414b22b933Srs200217 #ifdef  SIOCGIFNETMASK_IN6
7424b22b933Srs200217                 {
7434b22b933Srs200217                     struct in6_ifreq ifr6;
7444b22b933Srs200217                     if (sockf6 == -1)
7454b22b933Srs200217                         sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
746*5ffb0c9bSToomas Soome                     memset(&ifr6, 0, sizeof(ifr6));
7474b22b933Srs200217                     memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
7484b22b933Srs200217                     memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
749*5ffb0c9bSToomas Soome                     if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
750*5ffb0c9bSToomas Soome                         if (errno == EADDRNOTAVAIL) {
751*5ffb0c9bSToomas Soome                             /*
752*5ffb0c9bSToomas Soome                              * If the main interface is configured with no IP address but
753*5ffb0c9bSToomas Soome                              * an alias interface exists with an IP address, you get
754*5ffb0c9bSToomas Soome                              * EADDRNOTAVAIL for the main interface
755*5ffb0c9bSToomas Soome                              */
756*5ffb0c9bSToomas Soome                             free(ifi->ifi_addr);
757*5ffb0c9bSToomas Soome                             free(ifi);
758*5ffb0c9bSToomas Soome                             ifipnext  = ifiptr;
759*5ffb0c9bSToomas Soome                             *ifipnext = ifipold;
760*5ffb0c9bSToomas Soome                             continue;
761*5ffb0c9bSToomas Soome                         } else {
762*5ffb0c9bSToomas Soome                             goto gotError;
763*5ffb0c9bSToomas Soome                         }
764*5ffb0c9bSToomas Soome                     }
7654b22b933Srs200217                     ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
7664b22b933Srs200217                     if (ifi->ifi_netmask == NULL) goto gotError;
7674b22b933Srs200217                     sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
7684b22b933Srs200217                     memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
7694b22b933Srs200217                 }
7704b22b933Srs200217 #endif
7714b22b933Srs200217             }
7724b22b933Srs200217             break;
7734b22b933Srs200217 #endif
7744b22b933Srs200217 
7754b22b933Srs200217         default:
7764b22b933Srs200217             break;
7774b22b933Srs200217         }
7784b22b933Srs200217     }
7794b22b933Srs200217     goto done;
7804b22b933Srs200217 
7814b22b933Srs200217 gotError:
7824b22b933Srs200217     if (ifihead != NULL) {
7834b22b933Srs200217         free_ifi_info(ifihead);
7844b22b933Srs200217         ifihead = NULL;
7854b22b933Srs200217     }
7864b22b933Srs200217 
7874b22b933Srs200217 done:
7884b22b933Srs200217     if (buf != NULL) {
7894b22b933Srs200217         free(buf);
7904b22b933Srs200217     }
7914b22b933Srs200217     if (sockfd != -1) {
7924b22b933Srs200217         junk = close(sockfd);
7934b22b933Srs200217         assert(junk == 0);
7944b22b933Srs200217     }
7954b22b933Srs200217     if (sockf6 != -1) {
7964b22b933Srs200217         junk = close(sockf6);
7974b22b933Srs200217         assert(junk == 0);
7984b22b933Srs200217     }
7994b22b933Srs200217     return(ifihead);    /* pointer to first structure in linked list */
8004b22b933Srs200217 }
8014b22b933Srs200217 /* end get_ifi_info3 */
8024b22b933Srs200217 
8034b22b933Srs200217 /* include free_ifi_info */
8044b22b933Srs200217 void
8054b22b933Srs200217 free_ifi_info(struct ifi_info *ifihead)
8064b22b933Srs200217 {
8074b22b933Srs200217     struct ifi_info *ifi, *ifinext;
8084b22b933Srs200217 
8094b22b933Srs200217     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
8104b22b933Srs200217         if (ifi->ifi_addr != NULL)
8114b22b933Srs200217             free(ifi->ifi_addr);
812*5ffb0c9bSToomas Soome         if (ifi->ifi_netmask != NULL)
813*5ffb0c9bSToomas Soome             free(ifi->ifi_netmask);
8144b22b933Srs200217         if (ifi->ifi_brdaddr != NULL)
8154b22b933Srs200217             free(ifi->ifi_brdaddr);
8164b22b933Srs200217         if (ifi->ifi_dstaddr != NULL)
8174b22b933Srs200217             free(ifi->ifi_dstaddr);
8184b22b933Srs200217         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
8194b22b933Srs200217         free(ifi);                  /* the ifi_info{} itself */
8204b22b933Srs200217     }
8214b22b933Srs200217 }
8224b22b933Srs200217 /* end free_ifi_info */
8234b22b933Srs200217 
8244b22b933Srs200217 ssize_t
8254b22b933Srs200217 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
8264b22b933Srs200217                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
8274b22b933Srs200217 {
8284b22b933Srs200217     struct msghdr msg;
8294b22b933Srs200217     struct iovec iov[1];
8304b22b933Srs200217     ssize_t n;
8314b22b933Srs200217 
8324b22b933Srs200217 #ifdef CMSG_FIRSTHDR
8334b22b933Srs200217     struct cmsghdr  *cmptr;
8344b22b933Srs200217     union {
8354b22b933Srs200217         struct cmsghdr cm;
8364b22b933Srs200217         char control[1024];
8374b22b933Srs200217 	pad64_t align8; /* ensure structure is 8-byte aligned on sparc */
8384b22b933Srs200217     } control_un;
8394b22b933Srs200217 
8404b22b933Srs200217     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
8414b22b933Srs200217 
8424b22b933Srs200217     msg.msg_control = (void *) control_un.control;
8434b22b933Srs200217     msg.msg_controllen = sizeof(control_un.control);
8444b22b933Srs200217     msg.msg_flags = 0;
8454b22b933Srs200217 #else
8464b22b933Srs200217     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
8474b22b933Srs200217 #endif /* CMSG_FIRSTHDR */
8484b22b933Srs200217 
8494b22b933Srs200217     msg.msg_name = (char *) sa;
8504b22b933Srs200217     msg.msg_namelen = *salenptr;
8514b22b933Srs200217     iov[0].iov_base = (char *)ptr;
8524b22b933Srs200217     iov[0].iov_len = nbytes;
8534b22b933Srs200217     msg.msg_iov = iov;
8544b22b933Srs200217     msg.msg_iovlen = 1;
8554b22b933Srs200217 
8564b22b933Srs200217     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
8574b22b933Srs200217         return(n);
8584b22b933Srs200217 
8594b22b933Srs200217     *salenptr = msg.msg_namelen;    /* pass back results */
8604b22b933Srs200217     if (pktp) {
8614b22b933Srs200217         /* 0.0.0.0, i/f = -1 */
8624b22b933Srs200217         /* We set the interface to -1 so that the caller can
8634b22b933Srs200217            tell whether we returned a meaningful value or
8644b22b933Srs200217            just some default.  Previously this code just
8654b22b933Srs200217            set the value to 0, but I'm concerned that 0
8664b22b933Srs200217            might be a valid interface value.
8674b22b933Srs200217          */
8684b22b933Srs200217         memset(pktp, 0, sizeof(struct my_in_pktinfo));
8694b22b933Srs200217         pktp->ipi_ifindex = -1;
8704b22b933Srs200217     }
8714b22b933Srs200217 /* end recvfrom_flags1 */
8724b22b933Srs200217 
8734b22b933Srs200217 /* include recvfrom_flags2 */
8744b22b933Srs200217 #ifndef CMSG_FIRSTHDR
8754b22b933Srs200217     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
8764b22b933Srs200217     *flagsp = 0;                    /* pass back results */
8774b22b933Srs200217     return(n);
8784b22b933Srs200217 #else
8794b22b933Srs200217 
8804b22b933Srs200217     *flagsp = msg.msg_flags;        /* pass back results */
8814b22b933Srs200217     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
8824b22b933Srs200217         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
8834b22b933Srs200217         return(n);
8844b22b933Srs200217 
8854b22b933Srs200217     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
8864b22b933Srs200217          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
8874b22b933Srs200217 
8884b22b933Srs200217 #ifdef  IP_PKTINFO
8894b22b933Srs200217 #if in_pktinfo_definition_is_missing
8904b22b933Srs200217         struct in_pktinfo
8914b22b933Srs200217         {
8924b22b933Srs200217             int ipi_ifindex;
8934b22b933Srs200217             struct in_addr ipi_spec_dst;
8944b22b933Srs200217             struct in_addr ipi_addr;
8954b22b933Srs200217         };
8964b22b933Srs200217 #endif
8974b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IP &&
8984b22b933Srs200217             cmptr->cmsg_type == IP_PKTINFO) {
8994b22b933Srs200217             struct in_pktinfo *tmp;
9004b22b933Srs200217             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9014b22b933Srs200217 
9024b22b933Srs200217             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
9034b22b933Srs200217             sin->sin_family = AF_INET;
9044b22b933Srs200217             sin->sin_addr = tmp->ipi_addr;
9054b22b933Srs200217             sin->sin_port = 0;
9064b22b933Srs200217             pktp->ipi_ifindex = tmp->ipi_ifindex;
9074b22b933Srs200217             continue;
9084b22b933Srs200217         }
9094b22b933Srs200217 #endif
9104b22b933Srs200217 
9114b22b933Srs200217 #ifdef  IP_RECVDSTADDR
9124b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IP &&
9134b22b933Srs200217             cmptr->cmsg_type == IP_RECVDSTADDR) {
9144b22b933Srs200217             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
9154b22b933Srs200217 
9164b22b933Srs200217             sin->sin_family = AF_INET;
9174b22b933Srs200217             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
9184b22b933Srs200217             sin->sin_port = 0;
9194b22b933Srs200217             continue;
9204b22b933Srs200217         }
9214b22b933Srs200217 #endif
9224b22b933Srs200217 
9234b22b933Srs200217 #ifdef  IP_RECVIF
9244b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IP &&
9254b22b933Srs200217             cmptr->cmsg_type == IP_RECVIF) {
9264b22b933Srs200217             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
9274b22b933Srs200217 #ifndef HAVE_BROKEN_RECVIF_NAME
9284b22b933Srs200217             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
9294b22b933Srs200217             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
9304b22b933Srs200217 #endif
931*5ffb0c9bSToomas Soome             /*
932*5ffb0c9bSToomas Soome              * the is memcpy used for sparc? no idea;)
933*5ffb0c9bSToomas Soome              * pktp->ipi_ifindex = sdl->sdl_index;
934*5ffb0c9bSToomas Soome 	     */
9354b22b933Srs200217             (void) memcpy(&pktp->ipi_ifindex, CMSG_DATA(cmptr), sizeof(uint_t));
936*5ffb0c9bSToomas Soome #ifdef HAVE_BROKEN_RECVIF_NAME
937*5ffb0c9bSToomas Soome             if (sdl->sdl_index == 0) {
938*5ffb0c9bSToomas Soome                 pktp->ipi_ifindex = *(uint_t*)sdl;
939*5ffb0c9bSToomas Soome             }
940*5ffb0c9bSToomas Soome #endif
9414b22b933Srs200217             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
9424b22b933Srs200217             // null terminated because of memset above
9434b22b933Srs200217             continue;
9444b22b933Srs200217         }
9454b22b933Srs200217 #endif
9464b22b933Srs200217 
9474b22b933Srs200217 #ifdef  IP_RECVTTL
9484b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IP &&
9494b22b933Srs200217             cmptr->cmsg_type == IP_RECVTTL) {
9504b22b933Srs200217             *ttl = *(u_char*)CMSG_DATA(cmptr);
9514b22b933Srs200217             continue;
9524b22b933Srs200217         }
9534b22b933Srs200217         else if (cmptr->cmsg_level == IPPROTO_IP &&
9544b22b933Srs200217                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
9554b22b933Srs200217             *ttl = *(int*)CMSG_DATA(cmptr);
9564b22b933Srs200217             continue;
9574b22b933Srs200217         }
9584b22b933Srs200217 #endif
9594b22b933Srs200217 
9604b22b933Srs200217 #if defined(IPV6_PKTINFO) && HAVE_IPV6
9614b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9624b22b933Srs200217             cmptr->cmsg_type  == IPV6_PKTINFO) {
9634b22b933Srs200217             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
9644b22b933Srs200217             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
9654b22b933Srs200217 
9664b22b933Srs200217             sin6->sin6_family   = AF_INET6;
9674b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
9684b22b933Srs200217             sin6->sin6_len      = sizeof(*sin6);
9694b22b933Srs200217 #endif
9704b22b933Srs200217             sin6->sin6_addr     = ip6_info->ipi6_addr;
9714b22b933Srs200217             sin6->sin6_flowinfo = 0;
9724b22b933Srs200217             sin6->sin6_scope_id = 0;
9734b22b933Srs200217             sin6->sin6_port     = 0;
9744b22b933Srs200217             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
9754b22b933Srs200217             continue;
9764b22b933Srs200217         }
9774b22b933Srs200217 #endif
9784b22b933Srs200217 
9794b22b933Srs200217 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
9804b22b933Srs200217         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
9814b22b933Srs200217             cmptr->cmsg_type == IPV6_HOPLIMIT) {
9824b22b933Srs200217             *ttl = *(int*)CMSG_DATA(cmptr);
9834b22b933Srs200217             continue;
9844b22b933Srs200217         }
9854b22b933Srs200217 #endif
9864b22b933Srs200217         assert(0);  // unknown ancillary data
9874b22b933Srs200217     }
9884b22b933Srs200217     return(n);
9894b22b933Srs200217 #endif /* CMSG_FIRSTHDR */
9904b22b933Srs200217 }
9914b22b933Srs200217 
9924b22b933Srs200217 // **********************************************************************************************
9934b22b933Srs200217 
9944b22b933Srs200217 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
9954b22b933Srs200217 // Returns 0 on success, -1 on failure.
9964b22b933Srs200217 
9974b22b933Srs200217 #ifdef NOT_HAVE_DAEMON
9984b22b933Srs200217 #include <fcntl.h>
9994b22b933Srs200217 #include <sys/stat.h>
1000*5ffb0c9bSToomas Soome #include <sys/signal.h>
10014b22b933Srs200217 
10024b22b933Srs200217 int daemon(int nochdir, int noclose)
10034b22b933Srs200217 {
10044b22b933Srs200217     switch (fork())
10054b22b933Srs200217     {
10064b22b933Srs200217     case -1: return (-1);       // Fork failed
10074b22b933Srs200217     case 0:  break;             // Child -- continue
10084b22b933Srs200217     default: _exit(0);          // Parent -- exit
10094b22b933Srs200217     }
10104b22b933Srs200217 
10114b22b933Srs200217     if (setsid() == -1) return(-1);
10124b22b933Srs200217 
10134b22b933Srs200217     signal(SIGHUP, SIG_IGN);
10144b22b933Srs200217 
10154b22b933Srs200217     switch (fork())             // Fork again, primarily for reasons of Unix trivia
10164b22b933Srs200217     {
10174b22b933Srs200217     case -1: return (-1);       // Fork failed
10184b22b933Srs200217     case 0:  break;             // Child -- continue
10194b22b933Srs200217     default: _exit(0);          // Parent -- exit
10204b22b933Srs200217     }
10214b22b933Srs200217 
10224b22b933Srs200217     if (!nochdir) (void)chdir("/");
10234b22b933Srs200217     umask(0);
10244b22b933Srs200217 
10254b22b933Srs200217     if (!noclose)
10264b22b933Srs200217     {
10274b22b933Srs200217         int fd = open("/dev/null", O_RDWR, 0);
10284b22b933Srs200217         if (fd != -1)
10294b22b933Srs200217         {
10304b22b933Srs200217             // Avoid unnecessarily duplicating a file descriptor to itself
10314b22b933Srs200217             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
10324b22b933Srs200217             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
10334b22b933Srs200217             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
10344b22b933Srs200217             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
10354b22b933Srs200217                 (void)close (fd);
10364b22b933Srs200217         }
10374b22b933Srs200217     }
10384b22b933Srs200217     return (0);
10394b22b933Srs200217 }
10404b22b933Srs200217 #endif /* NOT_HAVE_DAEMON */
1041