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