1/* 2 * Copyright (C) 2013 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 <netdb.h> 18 19#include <gtest/gtest.h> 20 21#include <arpa/inet.h> 22#include <string.h> 23#include <sys/types.h> 24#include <sys/socket.h> 25#include <netinet/in.h> 26 27// https://code.google.com/p/android/issues/detail?id=13228 28TEST(netdb, freeaddrinfo_NULL) { 29 freeaddrinfo(NULL); 30} 31 32TEST(netdb, getaddrinfo_NULL_host) { 33 // It's okay for the host argument to be NULL, as long as service isn't. 34 addrinfo* ai = NULL; 35 ASSERT_EQ(0, getaddrinfo(NULL, "smtp", NULL, &ai)); 36 // (sockaddr_in::sin_port and sockaddr_in6::sin6_port overlap.) 37 ASSERT_EQ(25U, ntohs(reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_port)); 38 freeaddrinfo(ai); 39} 40 41TEST(netdb, getaddrinfo_NULL_service) { 42 // It's okay for the service argument to be NULL, as long as host isn't. 43 addrinfo* ai = NULL; 44 ASSERT_EQ(0, getaddrinfo("localhost", NULL, NULL, &ai)); 45 ASSERT_TRUE(ai != NULL); 46 freeaddrinfo(ai); 47} 48 49TEST(netdb, getaddrinfo_NULL_hints) { 50 addrinfo* ai = NULL; 51 ASSERT_EQ(0, getaddrinfo("localhost", "9999", NULL, &ai)); 52 53 bool saw_tcp = false; 54 bool saw_udp = false; 55 for (addrinfo* p = ai; p != NULL; p = p->ai_next) { 56 ASSERT_TRUE(p->ai_family == AF_INET || p->ai_family == AF_INET6); 57 if (p->ai_socktype == SOCK_STREAM) { 58 ASSERT_EQ(IPPROTO_TCP, p->ai_protocol); 59 saw_tcp = true; 60 } else if (p->ai_socktype == SOCK_DGRAM) { 61 ASSERT_EQ(IPPROTO_UDP, p->ai_protocol); 62 saw_udp = true; 63 } 64 } 65 ASSERT_TRUE(saw_tcp); 66 ASSERT_TRUE(saw_udp); 67 68 freeaddrinfo(ai); 69} 70 71TEST(netdb, getaddrinfo_service_lookup) { 72 addrinfo* ai = NULL; 73 ASSERT_EQ(0, getaddrinfo("localhost", "smtp", NULL, &ai)); 74 ASSERT_EQ(SOCK_STREAM, ai->ai_socktype); 75 ASSERT_EQ(IPPROTO_TCP, ai->ai_protocol); 76 ASSERT_EQ(25, ntohs(reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_port)); 77 freeaddrinfo(ai); 78} 79 80TEST(netdb, getaddrinfo_hints) { 81 addrinfo hints; 82 memset(&hints, 0, sizeof(hints)); 83 hints.ai_family = AF_INET; 84 hints.ai_socktype = SOCK_STREAM; 85 hints.ai_protocol = IPPROTO_TCP; 86 87 addrinfo* ai = NULL; 88 ASSERT_EQ(0, getaddrinfo( "localhost", "9999", &hints, &ai)); 89 ASSERT_TRUE(ai != NULL); 90 // In glibc, getaddrinfo() converts ::1 to 127.0.0.1 for localhost, 91 // so one or two addrinfo may be returned. 92 addrinfo* tai = ai; 93 while (tai != NULL) { 94 ASSERT_EQ(AF_INET, tai->ai_family); 95 ASSERT_EQ(SOCK_STREAM, tai->ai_socktype); 96 ASSERT_EQ(IPPROTO_TCP, tai->ai_protocol); 97 tai = tai->ai_next; 98 } 99 freeaddrinfo(ai); 100} 101 102TEST(netdb, getaddrinfo_ip6_localhost) { 103 addrinfo* ai = NULL; 104 ASSERT_EQ(0, getaddrinfo("ip6-localhost", NULL, NULL, &ai)); 105 ASSERT_TRUE(ai != NULL); 106 ASSERT_GE(ai->ai_addrlen, static_cast<socklen_t>(sizeof(sockaddr_in6))); 107 ASSERT_TRUE(ai->ai_addr != NULL); 108 sockaddr_in6 *addr = reinterpret_cast<sockaddr_in6*>(ai->ai_addr); 109 ASSERT_EQ(addr->sin6_family, AF_INET6); 110 ASSERT_EQ(0, memcmp(&addr->sin6_addr, &in6addr_loopback, sizeof(in6_addr))); 111 freeaddrinfo(ai); 112} 113 114TEST(netdb, getnameinfo_salen) { 115 sockaddr_storage ss; 116 memset(&ss, 0, sizeof(ss)); 117 sockaddr* sa = reinterpret_cast<sockaddr*>(&ss); 118 char tmp[16]; 119 120 ss.ss_family = AF_INET; 121 socklen_t too_much = sizeof(ss); 122 socklen_t just_right = sizeof(sockaddr_in); 123 socklen_t too_little = sizeof(sockaddr_in) - 1; 124 125 ASSERT_EQ(0, getnameinfo(sa, too_much, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 126 ASSERT_STREQ("0.0.0.0", tmp); 127 ASSERT_EQ(0, getnameinfo(sa, just_right, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 128 ASSERT_STREQ("0.0.0.0", tmp); 129 ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 130 131 ss.ss_family = AF_INET6; 132 just_right = sizeof(sockaddr_in6); 133 too_little = sizeof(sockaddr_in6) - 1; 134 too_much = just_right + 1; 135 136 ASSERT_EQ(0, getnameinfo(sa, too_much, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 137 ASSERT_STREQ("::", tmp); 138 ASSERT_EQ(0, getnameinfo(sa, just_right, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 139 ASSERT_STREQ("::", tmp); 140 ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST)); 141} 142 143TEST(netdb, getnameinfo_localhost) { 144 sockaddr_in addr; 145 char host[NI_MAXHOST]; 146 memset(&addr, 0, sizeof(sockaddr_in)); 147 addr.sin_family = AF_INET; 148 addr.sin_addr.s_addr = htonl(0x7f000001); 149 ASSERT_EQ(0, getnameinfo(reinterpret_cast<sockaddr*>(&addr), sizeof(addr), 150 host, sizeof(host), NULL, 0, 0)); 151 ASSERT_STREQ(host, "localhost"); 152} 153 154static void VerifyLocalhostName(const char* name) { 155 // Test possible localhost name and aliases, which depend on /etc/hosts or /system/etc/hosts. 156 ASSERT_TRUE(strcmp(name, "localhost") == 0 || 157 strcmp(name, "ip6-localhost") == 0 || 158 strcmp(name, "ip6-loopback") == 0) << name; 159} 160 161TEST(netdb, getnameinfo_ip6_localhost) { 162 sockaddr_in6 addr; 163 char host[NI_MAXHOST]; 164 memset(&addr, 0, sizeof(sockaddr_in6)); 165 addr.sin6_family = AF_INET6; 166 addr.sin6_addr = in6addr_loopback; 167 ASSERT_EQ(0, getnameinfo(reinterpret_cast<sockaddr*>(&addr), sizeof(addr), 168 host, sizeof(host), NULL, 0, 0)); 169 VerifyLocalhostName(host); 170} 171 172static void VerifyLocalhost(hostent *hent) { 173 ASSERT_TRUE(hent != NULL); 174 VerifyLocalhostName(hent->h_name); 175 for (size_t i = 0; hent->h_aliases[i] != NULL; ++i) { 176 VerifyLocalhostName(hent->h_aliases[i]); 177 } 178 ASSERT_EQ(hent->h_addrtype, AF_INET); 179 ASSERT_EQ(hent->h_addr[0], 127); 180 ASSERT_EQ(hent->h_addr[1], 0); 181 ASSERT_EQ(hent->h_addr[2], 0); 182 ASSERT_EQ(hent->h_addr[3], 1); 183} 184 185TEST(netdb, gethostbyname) { 186 hostent* hp = gethostbyname("localhost"); 187 VerifyLocalhost(hp); 188} 189 190TEST(netdb, gethostbyname2) { 191 hostent* hp = gethostbyname2("localhost", AF_INET); 192 VerifyLocalhost(hp); 193} 194 195TEST(netdb, gethostbyname_r) { 196 hostent hent; 197 hostent *hp; 198 char buf[512]; 199 int err; 200 int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err); 201 ASSERT_EQ(0, result); 202 VerifyLocalhost(hp); 203 204 // Change hp->h_addr to test reentrancy. 205 hp->h_addr[0] = 0; 206 207 hostent hent2; 208 hostent *hp2; 209 char buf2[512]; 210 result = gethostbyname_r("localhost", &hent2, buf2, sizeof(buf2), &hp2, &err); 211 ASSERT_EQ(0, result); 212 VerifyLocalhost(hp2); 213 214 ASSERT_EQ(0, hp->h_addr[0]); 215} 216 217TEST(netdb, gethostbyname2_r) { 218 hostent hent; 219 hostent *hp; 220 char buf[512]; 221 int err; 222 int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err); 223 ASSERT_EQ(0, result); 224 VerifyLocalhost(hp); 225 226 // Change hp->h_addr to test reentrancy. 227 hp->h_addr[0] = 0; 228 229 hostent hent2; 230 hostent *hp2; 231 char buf2[512]; 232 result = gethostbyname2_r("localhost", AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err); 233 ASSERT_EQ(0, result); 234 VerifyLocalhost(hp2); 235 236 ASSERT_EQ(0, hp->h_addr[0]); 237} 238 239TEST(netdb, gethostbyaddr) { 240 in_addr addr = { htonl(0x7f000001) }; 241 hostent *hp = gethostbyaddr(&addr, sizeof(addr), AF_INET); 242 VerifyLocalhost(hp); 243} 244 245TEST(netdb, gethostbyaddr_r) { 246 in_addr addr = { htonl(0x7f000001) }; 247 hostent hent; 248 hostent *hp; 249 char buf[512]; 250 int err; 251 int result = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err); 252 ASSERT_EQ(0, result); 253 VerifyLocalhost(hp); 254 255 // Change hp->h_addr to test reentrancy. 256 hp->h_addr[0] = 0; 257 258 hostent hent2; 259 hostent *hp2; 260 char buf2[512]; 261 result = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err); 262 ASSERT_EQ(0, result); 263 VerifyLocalhost(hp2); 264 265 ASSERT_EQ(0, hp->h_addr[0]); 266} 267 268TEST(netdb, gethostbyname_r_ERANGE) { 269 hostent hent; 270 hostent *hp; 271 char buf[4]; // Use too small buffer. 272 int err; 273 int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err); 274 ASSERT_EQ(ERANGE, result); 275 ASSERT_EQ(NULL, hp); 276} 277 278TEST(netdb, gethostbyname2_r_ERANGE) { 279 hostent hent; 280 hostent *hp; 281 char buf[4]; // Use too small buffer. 282 int err; 283 int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err); 284 ASSERT_EQ(ERANGE, result); 285 ASSERT_EQ(NULL, hp); 286} 287 288TEST(netdb, gethostbyaddr_r_ERANGE) { 289 in_addr addr = { htonl(0x7f000001) }; 290 hostent hent; 291 hostent *hp; 292 char buf[4]; // Use too small buffer. 293 int err; 294 int result = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err); 295 ASSERT_EQ(ERANGE, result); 296 ASSERT_EQ(NULL, hp); 297} 298 299TEST(netdb, getservbyname) { 300 // smtp is TCP-only, so we know we'll get 25/tcp back. 301 servent* s = getservbyname("smtp", NULL); 302 ASSERT_TRUE(s != NULL); 303 ASSERT_EQ(25, ntohs(s->s_port)); 304 ASSERT_STREQ("tcp", s->s_proto); 305 306 // We get the same result by explicitly asking for tcp. 307 s = getservbyname("smtp", "tcp"); 308 ASSERT_TRUE(s != NULL); 309 ASSERT_EQ(25, ntohs(s->s_port)); 310 ASSERT_STREQ("tcp", s->s_proto); 311 312 // And we get a failure if we explicitly ask for udp. 313 s = getservbyname("smtp", "udp"); 314 ASSERT_TRUE(s == NULL); 315 316 // But there are actually udp services. 317 s = getservbyname("echo", "udp"); 318 ASSERT_TRUE(s != NULL); 319 ASSERT_EQ(7, ntohs(s->s_port)); 320 ASSERT_STREQ("udp", s->s_proto); 321} 322