15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/* -*- Mode: C; tab-width: 4 -*- 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "mDNSUNP.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/uio.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) macro, usually defined in <sys/param.h> or someplace like that, to make sure the 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should be set to the name of the header to include to get the ALIGN(P) macro. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NEED_ALIGN_MACRO 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include NEED_ALIGN_MACRO 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other platforms don't even have that include file. So, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if we haven't yet got a definition, let's try to find 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) <sys/sockio.h>. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SIOCGIFCONF 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #include <sys/sockio.h> 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* sockaddr_dl is only referenced if we're using IP_RECVIF, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) so only include the header in that case. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifdef IP_RECVIF 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #include <net/if_dl.h> 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <net/if_var.h> 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in_var.h> 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h> 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h> 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Converts a prefix length to IPv6 network mask */ 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void plen_to_mask(int plen, char *addr) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int colons=7; /* Number of colons in IPv6 address */ 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bits_in_block=16; /* Bits per IPv6 block */ 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0;i<=colons;i++) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int block, ones=0xffff, ones_in_block; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (plen>bits_in_block) ones_in_block=bits_in_block; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else ones_in_block=plen; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block = ones & (ones << (bits_in_block-ones_in_block)); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) plen -= ones_in_block; 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Gets IPv6 interface information from the /proc filesystem in linux*/ 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE *fp = NULL; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char addr[8][5]; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags, myflags, index, plen, scope; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char ifname[9], lastname[IFNAMSIZ]; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char addr6[32+7+1]; /* don't forget the seven ':' */ 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct addrinfo hints, *res0; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in6 *sin6; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct in6_addr *addrptr; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int err; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sockfd = -1; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ifreq ifr; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res0=NULL; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifihead = NULL; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipnext = &ifihead; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lastname[0] = 0; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sockfd = socket(AF_INET6, SOCK_DGRAM, 0); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sockfd < 0) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (fscanf(fp, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addr[0],addr[1],addr[2],addr[3], 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addr[4],addr[5],addr[6],addr[7], 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &index, &plen, &scope, &flags, ifname) != EOF) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) myflags = 0; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (doaliases == 0) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; /* already processed this interface */ 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) myflags = IFI_ALIAS; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strncpy(lastname, ifname, IFNAMSIZ); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi == NULL) { 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) goto gotError; 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ifipold = *ifipnext; /* need this later */ 127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ifiptr = ifipnext; 128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *ifipnext = ifi; /* prev points to this new one */ 129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addr[0],addr[1],addr[2],addr[3], 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) addr[4],addr[5],addr[6],addr[7]); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Add address of the interface */ 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&hints, 0, sizeof(hints)); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hints.ai_family = AF_INET6; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hints.ai_flags = AI_NUMERICHOST; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = getaddrinfo(addr6, NULL, &hints, &res0); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_addr == NULL) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6)); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Add netmask of the interface */ 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char ipv6addr[INET6_ADDRSTRLEN]; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) plen_to_mask(plen, ipv6addr); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_addr == NULL) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin6=calloc(1, sizeof(struct sockaddr_in6)); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addrptr=calloc(1, sizeof(struct in6_addr)); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inet_pton(family, ipv6addr, addrptr); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin6->sin6_family=family; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin6->sin6_addr=*addrptr; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sin6->sin6_scope_id=scope; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6)); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(sin6); 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /* Add interface name */ 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) strncpy(ifi->ifi_name, ifname, IFI_NAME); 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /* Add interface index */ 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ifi->ifi_index = index; 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /* Add interface flags*/ 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (errno == EADDRNOTAVAIL) { 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /* 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * If the main interface is configured with no IP address but 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * an alias interface exists with an IP address, you get 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * EADDRNOTAVAIL for the main interface 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ifi->ifi_addr); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ifi); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipnext = ifiptr; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ifipnext = ifipold; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_flags = ifr.ifr_flags; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) freeaddrinfo(res0); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res0=NULL; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto done; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gotError: 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifihead != NULL) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free_ifi_info(ifihead); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifihead = NULL; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res0 != NULL) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) freeaddrinfo(res0); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res0=NULL; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done: 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sockfd != -1) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __ANDROID__ : replaced assert(close(..)) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sockfd_closed = close(sockfd); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(sockfd_closed == 0); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __ANDROID__ : if fp was opened, it needs to be closed 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fp != NULL) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd_closed = fclose(fp); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(fd_closed == 0); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return(ifihead); /* pointer to first structure in linked list */ 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ifi_info *get_ifi_info(int family, int doaliases) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int junk; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int sockfd, sockf6, len, lastlen, flags, myflags; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NOT_HAVE_IF_NAMETOINDEX 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 200; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *ptr, *buf, lastname[IFNAMSIZ], *cptr; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ifconf ifc; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ifreq *ifr, ifrcopy; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in *sinptr; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in6 *sinptr6; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sockfd = -1; 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sockf6 = -1; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf = NULL; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifihead = NULL; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sockfd = socket(AF_INET, SOCK_DGRAM, 0); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sockfd < 0) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) lastlen = 0; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; ; ) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf = (char*)malloc(len); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf == NULL) { 257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) goto gotError; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifc.ifc_len = len; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifc.ifc_buf = buf; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (errno != EINVAL || lastlen != 0) { 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifc.ifc_len == lastlen) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; /* success, len has not changed */ 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lastlen = ifc.ifc_len; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len += 10 * sizeof(struct ifreq); /* increment */ 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(buf); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifihead = NULL; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipnext = &ifihead; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lastname[0] = 0; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* end get_ifi_info1 */ 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* include get_ifi_info2 */ 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifr = (struct ifreq *) ptr; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Advance to next one in buffer */ 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr)) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptr += sizeof(struct ifreq); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifr->ifr_addr.sa_family != family) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; /* ignore if not desired address family */ 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) myflags = 0; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *cptr = 0; /* replace colon will null */ 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (doaliases == 0) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; /* already processed this interface */ 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) myflags = IFI_ALIAS; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifrcopy = *ifr; 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) flags = ifrcopy.ifr_flags; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((flags & IFF_UP) == 0) 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; /* ignore if interface not up */ 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi == NULL) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipold = *ifipnext; /* need this later */ 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifiptr = ifipnext; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ifipnext = ifi; /* prev points to this new one */ 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_flags = flags; /* IFF_xxx values */ 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_myflags = myflags; /* IFI_xxx values */ 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_IF_NAMETOINDEX 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_index = if_nametoindex(ifr->ifr_name); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifrcopy = *ifr; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SIOCGIFINDEX 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy)) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_index = ifrcopy.ifr_index; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */ 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_name[IFI_NAME-1] = '\0'; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* end get_ifi_info2 */ 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* include get_ifi_info3 */ 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ifr->ifr_addr.sa_family) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case AF_INET: 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr = (struct sockaddr_in *) &ifr->ifr_addr; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_addr == NULL) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_addr == NULL) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SIOCGIFNETMASK 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (errno == EADDRNOTAVAIL) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If the main interface is configured with no IP address but 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * an alias interface exists with an IP address, you get 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * EADDRNOTAVAIL for the main interface 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ifi->ifi_addr); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(ifi); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifipnext = ifiptr; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ifipnext = ifipold; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_netmask == NULL) goto gotError; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_SA_LEN 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr->sin_len = sizeof(struct sockaddr_in); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr->sin_family = AF_INET; 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); 375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#ifdef SIOCGIFBRDADDR 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (flags & IFF_BROADCAST) { 379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) { 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto gotError; 381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_SA_LEN 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr->sin_len = sizeof( struct sockaddr_in ); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr->sin_family = AF_INET; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ifi->ifi_brdaddr == NULL) { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SIOCGIFDSTADDR 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags & IFF_POINTOPOINT) { 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto gotError; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_SA_LEN 404 sinptr->sin_len = sizeof( struct sockaddr_in ); 405#endif 406 sinptr->sin_family = AF_INET; 407 ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); 408 if (ifi->ifi_dstaddr == NULL) { 409 goto gotError; 410 } 411 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); 412 } 413#endif 414 } 415 break; 416 417#if defined(AF_INET6) && HAVE_IPV6 418 case AF_INET6: 419 sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; 420 if (ifi->ifi_addr == NULL) { 421 ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); 422 if (ifi->ifi_addr == NULL) { 423 goto gotError; 424 } 425 426 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */ 427 /* We need to strip that out */ 428 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr)) 429 sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0; 430 memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); 431 432#ifdef SIOCGIFNETMASK_IN6 433 { 434 struct in6_ifreq ifr6; 435 if (sockf6 == -1) 436 sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); 437 memset(&ifr6, 0, sizeof(ifr6)); 438 memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); 439 memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); 440 if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) { 441 if (errno == EADDRNOTAVAIL) { 442 /* 443 * If the main interface is configured with no IP address but 444 * an alias interface exists with an IP address, you get 445 * EADDRNOTAVAIL for the main interface 446 */ 447 free(ifi->ifi_addr); 448 free(ifi); 449 ifipnext = ifiptr; 450 *ifipnext = ifipold; 451 continue; 452 } else { 453 goto gotError; 454 } 455 } 456 ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); 457 if (ifi->ifi_netmask == NULL) goto gotError; 458 sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; 459 memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6)); 460 } 461#endif 462 } 463 break; 464#endif 465 466 default: 467 break; 468 } 469 } 470 goto done; 471 472gotError: 473 if (ifihead != NULL) { 474 free_ifi_info(ifihead); 475 ifihead = NULL; 476 } 477 478done: 479 if (buf != NULL) { 480 free(buf); 481 } 482 if (sockfd != -1) { 483 junk = close(sockfd); 484 assert(junk == 0); 485 } 486 if (sockf6 != -1) { 487 junk = close(sockf6); 488 assert(junk == 0); 489 } 490 return(ifihead); /* pointer to first structure in linked list */ 491} 492/* end get_ifi_info3 */ 493 494/* include free_ifi_info */ 495void 496free_ifi_info(struct ifi_info *ifihead) 497{ 498 struct ifi_info *ifi, *ifinext; 499 500 for (ifi = ifihead; ifi != NULL; ifi = ifinext) { 501 if (ifi->ifi_addr != NULL) 502 free(ifi->ifi_addr); 503 if (ifi->ifi_netmask != NULL) 504 free(ifi->ifi_netmask); 505 if (ifi->ifi_brdaddr != NULL) 506 free(ifi->ifi_brdaddr); 507 if (ifi->ifi_dstaddr != NULL) 508 free(ifi->ifi_dstaddr); 509 ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ 510 free(ifi); /* the ifi_info{} itself */ 511 } 512} 513/* end free_ifi_info */ 514 515ssize_t 516recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 517 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl) 518{ 519 struct msghdr msg; 520 struct iovec iov[1]; 521 ssize_t n; 522 523#ifdef CMSG_FIRSTHDR 524 struct cmsghdr *cmptr; 525 union { 526 struct cmsghdr cm; 527 char control[1024]; 528 } control_un; 529 530 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 531 532 msg.msg_control = control_un.control; 533 msg.msg_controllen = sizeof(control_un.control); 534 msg.msg_flags = 0; 535#else 536 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 537#endif /* CMSG_FIRSTHDR */ 538 539 msg.msg_name = (char *) sa; 540 msg.msg_namelen = *salenptr; 541 iov[0].iov_base = (char *)ptr; 542 iov[0].iov_len = nbytes; 543 msg.msg_iov = iov; 544 msg.msg_iovlen = 1; 545 546 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 547 return(n); 548 549 *salenptr = msg.msg_namelen; /* pass back results */ 550 if (pktp) { 551 /* 0.0.0.0, i/f = -1 */ 552 /* We set the interface to -1 so that the caller can 553 tell whether we returned a meaningful value or 554 just some default. Previously this code just 555 set the value to 0, but I'm concerned that 0 556 might be a valid interface value. 557 */ 558 memset(pktp, 0, sizeof(struct my_in_pktinfo)); 559 pktp->ipi_ifindex = -1; 560 } 561/* end recvfrom_flags1 */ 562 563/* include recvfrom_flags2 */ 564#ifndef CMSG_FIRSTHDR 565 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 566 *flagsp = 0; /* pass back results */ 567 return(n); 568#else 569 570 *flagsp = msg.msg_flags; /* pass back results */ 571 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 572 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 573 return(n); 574 575 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 576 cmptr = CMSG_NXTHDR(&msg, cmptr)) { 577 578#ifdef IP_PKTINFO 579#if in_pktinfo_definition_is_missing 580struct in_pktinfo 581{ 582 int ipi_ifindex; 583 struct in_addr ipi_spec_dst; 584 struct in_addr ipi_addr; 585}; 586#endif 587 if (cmptr->cmsg_level == IPPROTO_IP && 588 cmptr->cmsg_type == IP_PKTINFO) { 589 struct in_pktinfo *tmp; 590 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 591 592 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 593 sin->sin_family = AF_INET; 594 sin->sin_addr = tmp->ipi_addr; 595 sin->sin_port = 0; 596 pktp->ipi_ifindex = tmp->ipi_ifindex; 597 continue; 598 } 599#endif 600 601#ifdef IP_RECVDSTADDR 602 if (cmptr->cmsg_level == IPPROTO_IP && 603 cmptr->cmsg_type == IP_RECVDSTADDR) { 604 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 605 606 sin->sin_family = AF_INET; 607 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 608 sin->sin_port = 0; 609 continue; 610 } 611#endif 612 613#ifdef IP_RECVIF 614 if (cmptr->cmsg_level == IPPROTO_IP && 615 cmptr->cmsg_type == IP_RECVIF) { 616 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 617#ifndef HAVE_BROKEN_RECVIF_NAME 618 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 619 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 620#endif 621 pktp->ipi_ifindex = sdl->sdl_index; 622#ifdef HAVE_BROKEN_RECVIF_NAME 623 if (sdl->sdl_index == 0) { 624 pktp->ipi_ifindex = *(uint_t*)sdl; 625 } 626#endif 627 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 628 // null terminated because of memset above 629 continue; 630 } 631#endif 632 633#ifdef IP_RECVTTL 634 if (cmptr->cmsg_level == IPPROTO_IP && 635 cmptr->cmsg_type == IP_RECVTTL) { 636 *ttl = *(u_char*)CMSG_DATA(cmptr); 637 continue; 638 } 639 else if (cmptr->cmsg_level == IPPROTO_IP && 640 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 641 *ttl = *(int*)CMSG_DATA(cmptr); 642 continue; 643 } 644#endif 645 646#if defined(IPV6_PKTINFO) && HAVE_IPV6 647 if (cmptr->cmsg_level == IPPROTO_IPV6 && 648 cmptr->cmsg_type == IPV6_2292_PKTINFO) { 649 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 650 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 651 652 sin6->sin6_family = AF_INET6; 653#ifndef NOT_HAVE_SA_LEN 654 sin6->sin6_len = sizeof(*sin6); 655#endif 656 sin6->sin6_addr = ip6_info->ipi6_addr; 657 sin6->sin6_flowinfo = 0; 658 sin6->sin6_scope_id = 0; 659 sin6->sin6_port = 0; 660 pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 661 continue; 662 } 663#endif 664 665#if defined(IPV6_HOPLIMIT) && HAVE_IPV6 666 if (cmptr->cmsg_level == IPPROTO_IPV6 && 667 cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { 668 *ttl = *(int*)CMSG_DATA(cmptr); 669 continue; 670 } 671#endif 672 assert(0); // unknown ancillary data 673 } 674 return(n); 675#endif /* CMSG_FIRSTHDR */ 676} 677 678// ********************************************************************************************** 679 680// daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4. 681// Returns 0 on success, -1 on failure. 682 683#ifdef NOT_HAVE_DAEMON 684#include <fcntl.h> 685#include <sys/stat.h> 686#include <sys/signal.h> 687 688int daemon(int nochdir, int noclose) 689 { 690 switch (fork()) 691 { 692 case -1: return (-1); // Fork failed 693 case 0: break; // Child -- continue 694 default: _exit(0); // Parent -- exit 695 } 696 697 if (setsid() == -1) return(-1); 698 699 signal(SIGHUP, SIG_IGN); 700 701 switch (fork()) // Fork again, primarily for reasons of Unix trivia 702 { 703 case -1: return (-1); // Fork failed 704 case 0: break; // Child -- continue 705 default: _exit(0); // Parent -- exit 706 } 707 708 if (!nochdir) (void)chdir("/"); 709 umask(0); 710 711 if (!noclose) 712 { 713 int fd = open("/dev/null", O_RDWR, 0); 714 if (fd != -1) 715 { 716 // Avoid unnecessarily duplicating a file descriptor to itself 717 if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO); 718 if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO); 719 if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO); 720 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) 721 (void)close (fd); 722 } 723 } 724 return (0); 725 } 726#endif /* NOT_HAVE_DAEMON */ 727