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