1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <gtest/gtest.h> 18 19 #include <ifaddrs.h> 20 21 #include <dirent.h> 22 #include <linux/if_packet.h> 23 #include <net/ethernet.h> 24 #include <net/if.h> 25 #include <netdb.h> 26 #include <netinet/in.h> 27 #include <sys/ioctl.h> 28 29 #include <algorithm> 30 #include <map> 31 #include <vector> 32 33 TEST(ifaddrs, freeifaddrs_null) { 34 freeifaddrs(nullptr); 35 } 36 37 // We can't statically say much about what network interfaces are available, but we can be pretty 38 // sure there's a loopback interface, and that it has IPv4, IPv6, and AF_PACKET entries. 39 TEST(ifaddrs, getifaddrs_lo) { 40 ifaddrs* addrs = nullptr; 41 42 ASSERT_EQ(0, getifaddrs(&addrs)); 43 ASSERT_TRUE(addrs != nullptr); 44 45 ifaddrs* lo_inet4 = nullptr; 46 ifaddrs* lo_inet6 = nullptr; 47 ifaddrs* lo_packet = nullptr; 48 for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) { 49 if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) { 50 if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) lo_inet4 = addr; 51 else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET6) lo_inet6 = addr; 52 else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_PACKET) lo_packet = addr; 53 } 54 } 55 56 // Does the IPv4 entry look right? 57 ASSERT_TRUE(lo_inet4 != nullptr); 58 const sockaddr_in* sa_inet4 = reinterpret_cast<const sockaddr_in*>(lo_inet4->ifa_addr); 59 ASSERT_TRUE(ntohl(sa_inet4->sin_addr.s_addr) == INADDR_LOOPBACK); 60 61 // Does the IPv6 entry look right? 62 ASSERT_TRUE(lo_inet6 != nullptr); 63 const sockaddr_in6* sa_inet6 = reinterpret_cast<const sockaddr_in6*>(lo_inet6->ifa_addr); 64 ASSERT_TRUE(IN6_IS_ADDR_LOOPBACK(&sa_inet6->sin6_addr)); 65 66 // Does the AF_PACKET entry look right? 67 ASSERT_TRUE(lo_packet != nullptr); 68 const sockaddr_ll* sa_ll = reinterpret_cast<const sockaddr_ll*>(lo_packet->ifa_addr); 69 ASSERT_EQ(6, sa_ll->sll_halen); 70 71 freeifaddrs(addrs); 72 } 73 74 // Check that getifaddrs sees the same list of interfaces as /sys/class/net. 75 TEST(ifaddrs, getifaddrs_interfaces) { 76 std::vector<std::string> ifaddrs_socks; 77 { 78 ifaddrs* addrs; 79 ASSERT_EQ(0, getifaddrs(&addrs)); 80 81 for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) { 82 int family = addr->ifa_addr ? addr->ifa_addr->sa_family : 83 addr->ifa_broadaddr ? addr->ifa_broadaddr->sa_family : 84 AF_UNSPEC; 85 86 if (family == AF_PACKET || family == AF_UNSPEC) { 87 ifaddrs_socks.push_back(std::string(addr->ifa_name)); 88 } 89 } 90 91 freeifaddrs(addrs); 92 } 93 94 std::vector<std::string> sys_class_net; 95 { 96 std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/sys/class/net"), closedir); 97 ASSERT_TRUE(d != nullptr); 98 dirent* dir; 99 while ((dir = readdir(d.get())) != nullptr) { 100 if (dir->d_type == DT_LNK) { 101 sys_class_net.push_back(std::string(dir->d_name)); 102 } 103 } 104 } 105 106 ASSERT_TRUE(std::is_permutation(ifaddrs_socks.begin(), ifaddrs_socks.end(), 107 sys_class_net.begin())); 108 } 109 110 static void CheckAddressIsInSet(const std::string& if_name, bool unicast, 111 const std::set<in_addr_t>& addrs) { 112 ifreq ifr; 113 memset(&ifr, 0, sizeof(ifr)); 114 ifr.ifr_addr.sa_family = AF_INET; 115 if_name.copy(ifr.ifr_name, IFNAMSIZ - 1); 116 117 int fd = socket(AF_INET, SOCK_DGRAM, 0); 118 ASSERT_TRUE(fd != -1); 119 120 int request = SIOCGIFADDR; 121 if (!unicast) { 122 // For non-unicast, the specific ioctl to use depends on whether the IFF_BROADCAST flag is set. 123 ASSERT_EQ(0, ioctl(fd, SIOCGIFFLAGS, &ifr)) << if_name << ' ' << strerror(errno); 124 request = ((ifr.ifr_flags & IFF_BROADCAST) != 0) ? SIOCGIFBRDADDR : SIOCGIFDSTADDR; 125 } 126 127 ASSERT_EQ(0, ioctl(fd, request, &ifr)) << if_name << ' ' << strerror(errno); 128 close(fd); 129 130 sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr); 131 in_addr_t addr = sock->sin_addr.s_addr; 132 133 EXPECT_TRUE(addrs.find(addr) != addrs.end()) << if_name << ' ' << std::hex << ntohl(addr); 134 } 135 136 TEST(ifaddrs, getifaddrs_INET) { 137 std::map<std::string, std::set<in_addr_t>> inet_addrs; 138 std::map<std::string, std::set<in_addr_t>> broad_addrs; 139 140 // Collect the IPv4 addresses for each interface. 141 ifaddrs* addrs; 142 ASSERT_EQ(0, getifaddrs(&addrs)); 143 for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) { 144 if (addr->ifa_name && addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) { 145 auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_addr); 146 inet_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr); 147 } 148 if (addr->ifa_name && addr->ifa_broadaddr && addr->ifa_broadaddr->sa_family == AF_INET) { 149 auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_broadaddr); 150 broad_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr); 151 } 152 } 153 freeifaddrs(addrs); 154 155 // Check that the addresses returned by the SIOCGIFADDR and SIOCGIFBRDADDR/SIOCGIFDSTADDR ioctls 156 // are in our collections. 157 for (const auto& it : inet_addrs) CheckAddressIsInSet(it.first, true, it.second); 158 for (const auto& it : broad_addrs) CheckAddressIsInSet(it.first, false, it.second); 159 } 160 161 static void print_sockaddr_ll(const char* what, const sockaddr* p) { 162 const sockaddr_ll* s = reinterpret_cast<const sockaddr_ll*>(p); 163 printf("\t\t%s\t", what); 164 for (int i = 0; i < s->sll_halen; ++i) { 165 if (i > 0) printf(":"); 166 printf("%02X", s->sll_addr[i]); 167 } 168 printf(" (%d bytes)\n", s->sll_halen); 169 } 170 171 static void print_sockaddr_inet(const char* what, const sockaddr* addr) { 172 char host[NI_MAXHOST]; 173 int family = addr->sa_family; 174 int error = getnameinfo(addr, 175 (family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6), 176 host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); 177 if (error != 0) { 178 printf("%d getnameinfo() failed: %s\n", family, gai_strerror(error)); 179 strcpy(host, "???"); 180 } 181 printf("\t\t%s: <%s>\n", what, host); 182 } 183 184 static const char* FamilyToName(int family) { 185 if (family == AF_INET) return "AF_INET"; 186 if (family == AF_INET6) return "AF_INET6"; 187 if (family == AF_PACKET) return "AF_PACKET"; 188 if (family == AF_UNSPEC) return "AF_UNSPEC"; 189 return "?"; 190 } 191 192 static std::string FlagsToString(short flags) { 193 std::string result; 194 if ((flags & IFF_UP) != 0) result += " UP"; 195 if ((flags & IFF_BROADCAST) != 0) result += " BROADCAST"; 196 if ((flags & IFF_DEBUG) != 0) result += " DEBUG"; 197 if ((flags & IFF_LOOPBACK) != 0) result += " LOOPBACK"; 198 if ((flags & IFF_POINTOPOINT) != 0) result += " POINTOPOINT"; 199 if ((flags & IFF_NOTRAILERS) != 0) result += " NOTRAILERS"; 200 if ((flags & IFF_RUNNING) != 0) result += " RUNNING"; 201 if ((flags & IFF_NOARP) != 0) result += " NOARP"; 202 if ((flags & IFF_PROMISC) != 0) result += " PROMISC"; 203 if ((flags & IFF_ALLMULTI) != 0) result += " ALLMULTI"; 204 if ((flags & IFF_MASTER) != 0) result += " MASTER"; 205 if ((flags & IFF_SLAVE) != 0) result += " SLAVE"; 206 if ((flags & IFF_MULTICAST) != 0) result += " MULTICAST"; 207 if ((flags & IFF_PORTSEL) != 0) result += " PORTSEL"; 208 if ((flags & IFF_AUTOMEDIA) != 0) result += " AUTOMEDIA"; 209 if ((flags & IFF_DYNAMIC) != 0) result += " DYNAMIC"; 210 #if defined(IFF_LOWER_UP) 211 if ((flags & IFF_LOWER_UP) != 0) result += " LOWER_UP"; 212 #endif 213 #if defined(IFF_DORMANT) 214 if ((flags & IFF_DORMANT) != 0) result += " DORMANT"; 215 #endif 216 #if defined(IFF_ECHO) 217 if ((flags & IFF_ECHO) != 0) result += " ECHO"; 218 #endif 219 return result; 220 } 221 222 // Not really a test, but a useful debugging tool. 223 TEST(ifaddrs, dump) { 224 ifaddrs* addrs; 225 ASSERT_EQ(0, getifaddrs(&addrs)); 226 227 for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) { 228 int family = ifa->ifa_addr ? ifa->ifa_addr->sa_family : 229 ifa->ifa_broadaddr ? ifa->ifa_broadaddr->sa_family : AF_UNSPEC; 230 231 printf("\t%s\n" 232 "\t\t%s (%d) flags=%#x%s\n", 233 ifa->ifa_name, FamilyToName(family), family, 234 ifa->ifa_flags, FlagsToString(ifa->ifa_flags).c_str()); 235 236 if (family == AF_PACKET) { 237 if (ifa->ifa_addr) print_sockaddr_ll("hwaddr", ifa->ifa_addr); 238 if (ifa->ifa_broadaddr) print_sockaddr_ll("hwbroad", ifa->ifa_addr); 239 } else if (family == AF_INET || family == AF_INET6) { 240 if (ifa->ifa_addr) print_sockaddr_inet("address", ifa->ifa_addr); 241 if (ifa->ifa_broadaddr && (ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) != 0) { 242 print_sockaddr_inet((ifa->ifa_flags & IFF_BROADCAST) ? "broadcast" : "destination", 243 ifa->ifa_broadaddr); 244 } 245 } 246 247 fflush(stdout); 248 } 249 250 freeifaddrs(addrs); 251 } 252 253 TEST(ifaddrs, inet6_scope_ids) { 254 ifaddrs* addrs; 255 ASSERT_EQ(0, getifaddrs(&addrs)); 256 257 for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) { 258 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 259 sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr); 260 // Any link-local IPv6 address should have a scope id. (http://b/27219454.) 261 // 0 isn't a valid interface index, so that would mean the scope id wasn't set. 262 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { 263 ASSERT_NE(sa6->sin6_scope_id, 0U); 264 } 265 } 266 } 267 268 freeifaddrs(addrs); 269 } 270