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