• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <fcntl.h>
23 #include <linux/if_packet.h>
24 #include <net/ethernet.h>
25 #include <net/if.h>
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <sys/ioctl.h>
29 
30 #include <algorithm>
31 #include <map>
32 #include <thread>
33 #include <vector>
34 
TEST(ifaddrs,freeifaddrs_null)35 TEST(ifaddrs, freeifaddrs_null) {
36   freeifaddrs(nullptr);
37 }
38 
39 // We can't statically say much about what network interfaces are available, but we can be pretty
40 // sure there's a loopback interface, and that it has IPv4, IPv6, and AF_PACKET entries.
TEST(ifaddrs,getifaddrs_lo)41 TEST(ifaddrs, getifaddrs_lo) {
42   ifaddrs* addrs = nullptr;
43 
44   ASSERT_EQ(0, getifaddrs(&addrs));
45   ASSERT_TRUE(addrs != nullptr);
46 
47   ifaddrs* lo_inet4 = nullptr;
48   ifaddrs* lo_inet6 = nullptr;
49   ifaddrs* lo_packet = nullptr;
50   for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
51     if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) {
52       if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) lo_inet4 = addr;
53       else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET6) lo_inet6 = addr;
54       else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_PACKET) lo_packet = addr;
55     }
56   }
57 
58   // Does the IPv4 entry look right?
59   ASSERT_TRUE(lo_inet4 != nullptr);
60   const sockaddr_in* sa_inet4 = reinterpret_cast<const sockaddr_in*>(lo_inet4->ifa_addr);
61   ASSERT_TRUE(ntohl(sa_inet4->sin_addr.s_addr) == INADDR_LOOPBACK);
62 
63   // Does the IPv6 entry look right?
64   ASSERT_TRUE(lo_inet6 != nullptr);
65   const sockaddr_in6* sa_inet6 = reinterpret_cast<const sockaddr_in6*>(lo_inet6->ifa_addr);
66   ASSERT_TRUE(IN6_IS_ADDR_LOOPBACK(&sa_inet6->sin6_addr));
67 
68   // Does the AF_PACKET entry look right?
69   ASSERT_TRUE(lo_packet != nullptr);
70   const sockaddr_ll* sa_ll = reinterpret_cast<const sockaddr_ll*>(lo_packet->ifa_addr);
71   ASSERT_EQ(6, sa_ll->sll_halen);
72 
73   freeifaddrs(addrs);
74 }
75 
76 // Check that getifaddrs sees the same list of interfaces as /sys/class/net.
TEST(ifaddrs,getifaddrs_interfaces)77 TEST(ifaddrs, getifaddrs_interfaces) {
78   std::vector<std::string> ifaddrs_socks;
79   {
80     ifaddrs* addrs;
81     ASSERT_EQ(0, getifaddrs(&addrs));
82 
83     for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
84       int family = addr->ifa_addr ? addr->ifa_addr->sa_family :
85           addr->ifa_broadaddr ? addr->ifa_broadaddr->sa_family :
86           AF_UNSPEC;
87 
88       if (family == AF_PACKET || family == AF_UNSPEC) {
89         ifaddrs_socks.push_back(std::string(addr->ifa_name));
90       }
91     }
92 
93     freeifaddrs(addrs);
94   }
95 
96   std::vector<std::string> sys_class_net;
97   {
98     std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/sys/class/net"), closedir);
99     ASSERT_TRUE(d != nullptr);
100     dirent* dir;
101     while ((dir = readdir(d.get())) != nullptr) {
102       if (dir->d_type == DT_LNK) {
103         sys_class_net.push_back(std::string(dir->d_name));
104       }
105     }
106   }
107 
108   ASSERT_TRUE(std::is_permutation(ifaddrs_socks.begin(), ifaddrs_socks.end(),
109                                   sys_class_net.begin()));
110 }
111 
CheckAddressIsInSet(const std::string & if_name,bool unicast,const std::set<in_addr_t> & addrs)112 static void CheckAddressIsInSet(const std::string& if_name, bool unicast,
113                                 const std::set<in_addr_t>& addrs) {
114   ifreq ifr;
115   memset(&ifr, 0, sizeof(ifr));
116   ifr.ifr_addr.sa_family = AF_INET;
117   if_name.copy(ifr.ifr_name, IFNAMSIZ - 1);
118 
119   int fd = socket(AF_INET, SOCK_DGRAM, 0);
120   ASSERT_TRUE(fd != -1);
121 
122   int request = SIOCGIFADDR;
123   if (!unicast) {
124     // For non-unicast, the specific ioctl to use depends on whether the IFF_BROADCAST flag is set.
125     ASSERT_EQ(0, ioctl(fd, SIOCGIFFLAGS, &ifr)) << if_name << ' ' << strerror(errno);
126     request = ((ifr.ifr_flags & IFF_BROADCAST) != 0) ? SIOCGIFBRDADDR : SIOCGIFDSTADDR;
127   }
128 
129   ASSERT_EQ(0, ioctl(fd, request, &ifr)) << if_name << ' ' << strerror(errno);
130   close(fd);
131 
132   sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
133   in_addr_t addr = sock->sin_addr.s_addr;
134 
135   EXPECT_TRUE(addrs.find(addr) != addrs.end()) << if_name << ' ' << std::hex << ntohl(addr);
136 }
137 
TEST(ifaddrs,getifaddrs_INET)138 TEST(ifaddrs, getifaddrs_INET) {
139   std::map<std::string, std::set<in_addr_t>> inet_addrs;
140   std::map<std::string, std::set<in_addr_t>> broad_addrs;
141 
142   // Collect the IPv4 addresses for each interface.
143   ifaddrs* addrs;
144   ASSERT_EQ(0, getifaddrs(&addrs));
145   for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
146     if (addr->ifa_name && addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) {
147       auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_addr);
148       inet_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr);
149     }
150     if (addr->ifa_name && addr->ifa_broadaddr && addr->ifa_broadaddr->sa_family == AF_INET) {
151       auto sock = reinterpret_cast<sockaddr_in*>(addr->ifa_broadaddr);
152       broad_addrs[addr->ifa_name].insert(sock->sin_addr.s_addr);
153     }
154   }
155   freeifaddrs(addrs);
156 
157   // Check that the addresses returned by the SIOCGIFADDR and SIOCGIFBRDADDR/SIOCGIFDSTADDR ioctls
158   // are in our collections.
159   for (const auto& it : inet_addrs) CheckAddressIsInSet(it.first, true, it.second);
160   for (const auto& it : broad_addrs) CheckAddressIsInSet(it.first, false, it.second);
161 }
162 
print_sockaddr_ll(const char * what,const sockaddr * p)163 static void print_sockaddr_ll(const char* what, const sockaddr* p) {
164   const sockaddr_ll* s = reinterpret_cast<const sockaddr_ll*>(p);
165   printf("\t\t%s\t", what);
166   for (int i = 0; i < s->sll_halen; ++i) {
167     if (i > 0) printf(":");
168     printf("%02X", s->sll_addr[i]);
169   }
170   printf(" (%d bytes)\n", s->sll_halen);
171 }
172 
print_sockaddr_inet(const char * what,const sockaddr * addr)173 static void print_sockaddr_inet(const char* what, const sockaddr* addr) {
174   char host[NI_MAXHOST];
175   int family = addr->sa_family;
176   int error = getnameinfo(addr,
177                           (family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6),
178                           host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
179   if (error != 0) {
180     printf("%d getnameinfo() failed: %s\n", family, gai_strerror(error));
181     strcpy(host, "???");
182   }
183   printf("\t\t%s: <%s>\n", what, host);
184 }
185 
FamilyToName(int family)186 static const char* FamilyToName(int family) {
187   if (family == AF_INET) return "AF_INET";
188   if (family == AF_INET6) return "AF_INET6";
189   if (family == AF_PACKET) return "AF_PACKET";
190   if (family == AF_UNSPEC) return "AF_UNSPEC";
191   return "?";
192 }
193 
FlagsToString(short flags)194 static std::string FlagsToString(short flags) {
195   std::string result;
196   if ((flags & IFF_UP) != 0) result += " UP";
197   if ((flags & IFF_BROADCAST) != 0) result += " BROADCAST";
198   if ((flags & IFF_DEBUG) != 0) result += " DEBUG";
199   if ((flags & IFF_LOOPBACK) != 0) result += " LOOPBACK";
200   if ((flags & IFF_POINTOPOINT) != 0) result += " POINTOPOINT";
201   if ((flags & IFF_NOTRAILERS) != 0) result += " NOTRAILERS";
202   if ((flags & IFF_RUNNING) != 0) result += " RUNNING";
203   if ((flags & IFF_NOARP) != 0) result += " NOARP";
204   if ((flags & IFF_PROMISC) != 0) result += " PROMISC";
205   if ((flags & IFF_ALLMULTI) != 0) result += " ALLMULTI";
206   if ((flags & IFF_MASTER) != 0) result += " MASTER";
207   if ((flags & IFF_SLAVE) != 0) result += " SLAVE";
208   if ((flags & IFF_MULTICAST) != 0) result += " MULTICAST";
209   if ((flags & IFF_PORTSEL) != 0) result += " PORTSEL";
210   if ((flags & IFF_AUTOMEDIA) != 0) result += " AUTOMEDIA";
211   if ((flags & IFF_DYNAMIC) != 0) result += " DYNAMIC";
212 #if defined(IFF_LOWER_UP)
213   if ((flags & IFF_LOWER_UP) != 0) result += " LOWER_UP";
214 #endif
215 #if defined(IFF_DORMANT)
216   if ((flags & IFF_DORMANT) != 0) result += " DORMANT";
217 #endif
218 #if defined(IFF_ECHO)
219   if ((flags & IFF_ECHO) != 0) result += " ECHO";
220 #endif
221   return result;
222 }
223 
224 // Not really a test, but a useful debugging tool.
TEST(ifaddrs,dump)225 TEST(ifaddrs, dump) {
226   ifaddrs* addrs;
227   ASSERT_EQ(0, getifaddrs(&addrs));
228 
229   for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) {
230     int family = ifa->ifa_addr ? ifa->ifa_addr->sa_family :
231                                  ifa->ifa_broadaddr ? ifa->ifa_broadaddr->sa_family : AF_UNSPEC;
232 
233     printf("\t%s\n"
234            "\t\t%s (%d) flags=%#x%s\n",
235            ifa->ifa_name, FamilyToName(family), family,
236            ifa->ifa_flags, FlagsToString(ifa->ifa_flags).c_str());
237 
238     if (family == AF_PACKET) {
239       if (ifa->ifa_addr) print_sockaddr_ll("hwaddr", ifa->ifa_addr);
240       if (ifa->ifa_broadaddr) print_sockaddr_ll("hwbroad", ifa->ifa_addr);
241     } else if (family == AF_INET || family == AF_INET6) {
242       if (ifa->ifa_addr) print_sockaddr_inet("address", ifa->ifa_addr);
243       if (ifa->ifa_broadaddr && (ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) != 0) {
244         print_sockaddr_inet((ifa->ifa_flags & IFF_BROADCAST) ? "broadcast" : "destination",
245                             ifa->ifa_broadaddr);
246       }
247     }
248 
249     fflush(stdout);
250   }
251 
252   freeifaddrs(addrs);
253 }
254 
TEST(ifaddrs,inet6_scope_ids)255 TEST(ifaddrs, inet6_scope_ids) {
256   ifaddrs* addrs;
257   ASSERT_EQ(0, getifaddrs(&addrs));
258 
259   for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) {
260     if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
261       sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr);
262       // Any link-local IPv6 address should have a scope id. (http://b/27219454.)
263       // 0 isn't a valid interface index, so that would mean the scope id wasn't set.
264       if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) {
265         ASSERT_NE(sa6->sin6_scope_id, 0U);
266       }
267     }
268   }
269 
270   freeifaddrs(addrs);
271 }
272 
TEST(ifaddrs,kernel_bug_31038971)273 TEST(ifaddrs, kernel_bug_31038971) {
274   // Some kernels had a bug that would lead to an NLMSG_ERROR response,
275   // but bionic wasn't setting errno based on the value in the message.
276   // This is the test for the kernel bug, but on a device with a bad
277   // kernel this test was also useful for testing the bionic errno fix.
278   std::vector<std::thread*> threads;
279   for (size_t i = 0; i < 128; ++i) {
280     threads.push_back(new std::thread([]() {
281       ifaddrs* addrs = nullptr;
282       ASSERT_EQ(0, getifaddrs(&addrs)) << strerror(errno);
283       freeifaddrs(addrs);
284     }));
285   }
286   for (auto& t : threads) {
287     t->join();
288     delete t;
289   }
290 }
291 
TEST(ifaddrs,errno_EMFILE)292 TEST(ifaddrs, errno_EMFILE) {
293   std::vector<int> fds;
294   while (true) {
295     int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
296     if (fd == -1) {
297       ASSERT_EQ(EMFILE, errno);
298       break;
299     }
300     fds.push_back(fd);
301   }
302 
303   ifaddrs* addrs;
304   EXPECT_EQ(-1, getifaddrs(&addrs));
305   EXPECT_EQ(EMFILE, errno);
306 
307   for (int fd : fds) close(fd);
308 }
309