addrs-bsd.c (3029B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #if defined(BSD) || defined(DARWIN) 6 #include "addrs-bsd.h" 7 #include <csi_platform.h> 8 #include <assert.h> 9 #include <string.h> 10 #include "util.h" 11 #include "stun_util.h" 12 #include "util.h" 13 #include <r_macros.h> 14 15 #include <sys/types.h> /* getifaddrs */ 16 #include <ifaddrs.h> /* getifaddrs */ 17 #include <sys/socket.h> 18 #include <sys/ioctl.h> 19 #include <errno.h> 20 #include <netinet/in.h> 21 #include <netinet6/in6_var.h> 22 23 static int 24 stun_ifaddr_get_v6_flags(struct ifaddrs *ifaddr) 25 { 26 if (ifaddr->ifa_addr->sa_family != AF_INET6) { 27 return 0; 28 } 29 30 int flags = 0; 31 int s = socket(AF_INET6, SOCK_DGRAM, 0); 32 if (!s) { 33 r_log(NR_LOG_STUN, LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed, errno=%d", errno); 34 assert(0); 35 return 0; 36 } 37 struct in6_ifreq ifr6; 38 memset(&ifr6, 0, sizeof(ifr6)); 39 strncpy(ifr6.ifr_name, ifaddr->ifa_name, sizeof(ifr6.ifr_name)); 40 /* ifr_addr is a sockaddr_in6, ifa_addr is a sockaddr* */ 41 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ifaddr->ifa_addr; 42 ifr6.ifr_addr = *sin6; 43 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) != -1) { 44 flags = ifr6.ifr_ifru.ifru_flags6; 45 } else { 46 r_log(NR_LOG_STUN, LOG_ERR, "ioctl(SIOCGIFAFLAG_IN6) failed, errno=%d", errno); 47 assert(0); 48 } 49 close(s); 50 return flags; 51 } 52 53 static int 54 stun_ifaddr_is_disallowed_v6(int flags) { 55 return flags & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED); 56 } 57 58 int stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count) 59 { 60 int r,_status,flags; 61 struct ifaddrs* if_addrs_head=NULL; 62 struct ifaddrs* if_addr; 63 64 *count = 0; 65 66 if (maxaddrs <= 0) 67 ABORT(R_BAD_ARGS); 68 69 if (getifaddrs(&if_addrs_head) == -1) { 70 r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno); 71 ABORT(R_INTERNAL); 72 } 73 74 if_addr = if_addrs_head; 75 76 while (if_addr && *count < maxaddrs) { 77 /* This can be null */ 78 if (if_addr->ifa_addr) { 79 switch (if_addr->ifa_addr->sa_family) { 80 case AF_INET: 81 case AF_INET6: 82 flags = stun_ifaddr_get_v6_flags(if_addr); 83 if (!stun_ifaddr_is_disallowed_v6(flags)) { 84 if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) { 85 r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r); 86 } else { 87 if (flags & IN6_IFF_TEMPORARY) { 88 addrs[*count].flags |= NR_ADDR_FLAG_TEMPORARY; 89 } 90 (void)strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname)); 91 ++(*count); 92 } 93 } 94 break; 95 default: 96 ; 97 } 98 } 99 100 if_addr = if_addr->ifa_next; 101 } 102 103 _status=0; 104 abort: 105 if (if_addrs_head) { 106 freeifaddrs(if_addrs_head); 107 } 108 return(_status); 109 } 110 #endif