blob: 4c120d9076f2d342c8afaf5810a297f7d5a73cb8 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */
2/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Issues to be discussed:
35 * - Thread safe-ness must be checked.
36 * - Return values. There are nonstandard return values defined and used
37 * in the source code. This is because RFC2553 is silent about which error
38 * code must be returned for which situation.
39 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
40 * says to use inet_aton() to convert IPv4 numeric to binary (alows
41 * classful form as a result).
42 * current code - disallow classful form for IPv4 (due to use of inet_pton).
43 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
44 * invalid.
45 * current code - SEGV on freeaddrinfo(NULL)
46 * Note:
47 * - We use getipnodebyname() just for thread-safeness. There's no intent
48 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
49 * getipnodebyname().
50 * - The code filters out AFs that are not supported by the kernel,
51 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
52 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
53 * in ai_flags?
54 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
55 * (1) what should we do against numeric hostname (2) what should we do
56 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
57 * non-loopback address configured? global address configured?
58 * - To avoid search order issue, we have a big amount of code duplicate
59 * from gethnamaddr.c and some other places. The issues that there's no
60 * lower layer function to lookup "IPv4 or IPv6" record. Calling
61 * gethostbyname2 from getaddrinfo will end up in wrong search order, as
62 * follows:
63 * - The code makes use of following calls when asked to resolver with
64 * ai_family = PF_UNSPEC:
65 * getipnodebyname(host, AF_INET6);
66 * getipnodebyname(host, AF_INET);
67 * This will result in the following queries if the node is configure to
68 * prefer /etc/hosts than DNS:
69 * lookup /etc/hosts for IPv6 address
70 * lookup DNS for IPv6 address
71 * lookup /etc/hosts for IPv4 address
72 * lookup DNS for IPv4 address
73 * which may not meet people's requirement.
74 * The right thing to happen is to have underlying layer which does
75 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
76 * This would result in a bit of code duplicate with _dns_ghbyname() and
77 * friends.
78 */
79
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -070080#include <fcntl.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081#include <sys/cdefs.h>
82#include <sys/types.h>
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -070083#include <sys/stat.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084#include <sys/param.h>
85#include <sys/socket.h>
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -070086#include <sys/un.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087#include <net/if.h>
88#include <netinet/in.h>
89#include <arpa/inet.h>
Calin Juravle569fb982014-03-04 15:01:29 +000090#include <arpa/nameser.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091#include <assert.h>
92#include <ctype.h>
93#include <errno.h>
94#include <netdb.h>
Szymon Jakubczakea9bf672014-02-14 17:07:23 -050095#include "resolv_cache.h"
96#include "resolv_netid.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080097#include "resolv_private.h"
Robert Greenwalt1d8d9a32013-08-02 15:24:45 -070098#include <stdbool.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080099#include <stddef.h>
100#include <stdio.h>
101#include <stdlib.h>
102#include <string.h>
Carl Shapiro2cc2b2b2011-03-21 20:01:03 -0700103#include <strings.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800104#include <unistd.h>
105
106#include <syslog.h>
107#include <stdarg.h>
108#include "nsswitch.h"
109
Brad Fitzpatrick78585642010-10-28 13:22:20 -0700110#ifdef ANDROID_CHANGES
111#include <sys/system_properties.h>
112#endif /* ANDROID_CHANGES */
113
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700114typedef union sockaddr_union {
115 struct sockaddr generic;
116 struct sockaddr_in in;
117 struct sockaddr_in6 in6;
118} sockaddr_union;
119
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800120#define SUCCESS 0
121#define ANY 0
122#define YES 1
123#define NO 0
124
125static const char in_addrany[] = { 0, 0, 0, 0 };
126static const char in_loopback[] = { 127, 0, 0, 1 };
127#ifdef INET6
128static const char in6_addrany[] = {
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
130};
131static const char in6_loopback[] = {
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
133};
134#endif
135
Selim Gurun06e18312012-02-27 15:58:54 -0800136// This should be synchronized to ResponseCode.h
137static const int DnsProxyQueryResult = 222;
138
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139static const struct afd {
140 int a_af;
141 int a_addrlen;
142 int a_socklen;
143 int a_off;
144 const char *a_addrany;
145 const char *a_loopback;
146 int a_scoped;
147} afdl [] = {
148#ifdef INET6
149 {PF_INET6, sizeof(struct in6_addr),
150 sizeof(struct sockaddr_in6),
151 offsetof(struct sockaddr_in6, sin6_addr),
152 in6_addrany, in6_loopback, 1},
153#endif
154 {PF_INET, sizeof(struct in_addr),
155 sizeof(struct sockaddr_in),
156 offsetof(struct sockaddr_in, sin_addr),
157 in_addrany, in_loopback, 0},
158 {0, 0, 0, 0, NULL, NULL, 0},
159};
160
161struct explore {
162 int e_af;
163 int e_socktype;
164 int e_protocol;
165 const char *e_protostr;
166 int e_wild;
167#define WILD_AF(ex) ((ex)->e_wild & 0x01)
168#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
169#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
170};
171
172static const struct explore explore[] = {
173#if 0
174 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
175#endif
176#ifdef INET6
177 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
178 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
179 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
180#endif
181 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
182 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
183 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
184 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
185 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
186 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
187 { -1, 0, 0, NULL, 0 },
188};
189
190#ifdef INET6
191#define PTON_MAX 16
192#else
193#define PTON_MAX 4
194#endif
195
196static const ns_src default_dns_files[] = {
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700197 { NSSRC_FILES, NS_SUCCESS },
198 { NSSRC_DNS, NS_SUCCESS },
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800199 { 0, 0 }
200};
201
202#define MAXPACKET (64*1024)
203
204typedef union {
205 HEADER hdr;
206 u_char buf[MAXPACKET];
207} querybuf;
208
209struct res_target {
210 struct res_target *next;
211 const char *name; /* domain name */
212 int qclass, qtype; /* class and type of query */
213 u_char *answer; /* buffer to put answer */
214 int anslen; /* size of answer buffer */
215 int n; /* result length */
216};
217
218static int str2number(const char *);
219static int explore_fqdn(const struct addrinfo *, const char *,
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500220 const char *, struct addrinfo **, unsigned netid, unsigned mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800221static int explore_null(const struct addrinfo *,
222 const char *, struct addrinfo **);
223static int explore_numeric(const struct addrinfo *, const char *,
224 const char *, struct addrinfo **, const char *);
225static int explore_numeric_scope(const struct addrinfo *, const char *,
226 const char *, struct addrinfo **);
227static int get_canonname(const struct addrinfo *,
228 struct addrinfo *, const char *);
229static struct addrinfo *get_ai(const struct addrinfo *,
230 const struct afd *, const char *);
231static int get_portmatch(const struct addrinfo *, const char *);
232static int get_port(const struct addrinfo *, const char *, int);
233static const struct afd *find_afd(int);
234#ifdef INET6
235static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
236#endif
237
238static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
239 const struct addrinfo *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800240static int _dns_getaddrinfo(void *, void *, va_list);
241static void _sethtent(FILE **);
242static void _endhtent(FILE **);
243static struct addrinfo *_gethtent(FILE **, const char *,
244 const struct addrinfo *);
245static int _files_getaddrinfo(void *, void *, va_list);
246
247static int res_queryN(const char *, struct res_target *, res_state);
248static int res_searchN(const char *, struct res_target *, res_state);
249static int res_querydomainN(const char *, const char *,
250 struct res_target *, res_state);
251
252static const char * const ai_errlist[] = {
253 "Success",
254 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
255 "Temporary failure in name resolution", /* EAI_AGAIN */
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700256 "Invalid value for ai_flags", /* EAI_BADFLAGS */
257 "Non-recoverable failure in name resolution", /* EAI_FAIL */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800258 "ai_family not supported", /* EAI_FAMILY */
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700259 "Memory allocation failure", /* EAI_MEMORY */
260 "No address associated with hostname", /* EAI_NODATA */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800261 "hostname nor servname provided, or not known", /* EAI_NONAME */
262 "servname not supported for ai_socktype", /* EAI_SERVICE */
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700263 "ai_socktype not supported", /* EAI_SOCKTYPE */
264 "System error returned in errno", /* EAI_SYSTEM */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800265 "Invalid value for hints", /* EAI_BADHINTS */
266 "Resolved protocol is unknown", /* EAI_PROTOCOL */
267 "Argument buffer overflow", /* EAI_OVERFLOW */
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700268 "Unknown error", /* EAI_MAX */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269};
270
271/* XXX macros that make external reference is BAD. */
272
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700273#define GET_AI(ai, afd, addr) \
274do { \
275 /* external reference: pai, error, and label free */ \
276 (ai) = get_ai(pai, (afd), (addr)); \
277 if ((ai) == NULL) { \
278 error = EAI_MEMORY; \
279 goto free; \
280 } \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800281} while (/*CONSTCOND*/0)
282
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700283#define GET_PORT(ai, serv) \
284do { \
285 /* external reference: error and label free */ \
286 error = get_port((ai), (serv), 0); \
287 if (error != 0) \
288 goto free; \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800289} while (/*CONSTCOND*/0)
290
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700291#define GET_CANONNAME(ai, str) \
292do { \
293 /* external reference: pai, error and label free */ \
294 error = get_canonname(pai, (ai), (str)); \
295 if (error != 0) \
296 goto free; \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800297} while (/*CONSTCOND*/0)
298
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700299#define ERR(err) \
300do { \
301 /* external reference: error, and label bad */ \
302 error = (err); \
303 goto bad; \
304 /*NOTREACHED*/ \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800305} while (/*CONSTCOND*/0)
306
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700307#define MATCH_FAMILY(x, y, w) \
308 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800309 (y) == PF_UNSPEC)))
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700310#define MATCH(x, y, w) \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800311 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
312
313const char *
314gai_strerror(int ecode)
315{
316 if (ecode < 0 || ecode > EAI_MAX)
317 ecode = EAI_MAX;
318 return ai_errlist[ecode];
319}
320
321void
322freeaddrinfo(struct addrinfo *ai)
323{
324 struct addrinfo *next;
325
326 assert(ai != NULL);
327
328 do {
329 next = ai->ai_next;
330 if (ai->ai_canonname)
331 free(ai->ai_canonname);
332 /* no need to free(ai->ai_addr) */
333 free(ai);
334 ai = next;
335 } while (ai);
336}
337
338static int
339str2number(const char *p)
340{
341 char *ep;
342 unsigned long v;
343
344 assert(p != NULL);
345
346 if (*p == '\0')
347 return -1;
348 ep = NULL;
349 errno = 0;
350 v = strtoul(p, &ep, 10);
351 if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
352 return v;
353 else
354 return -1;
355}
356
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800357/*
358 * Connect a UDP socket to a given unicast address. This will cause no network
359 * traffic, but will fail fast if the system has no or limited reachability to
360 * the destination (e.g., no IPv4 address, no IPv6 default route, ...).
361 */
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700362static int
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500363_test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800364 int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700365 if (s < 0)
366 return 0;
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500367 if (mark != MARK_UNSET && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
368 return 0;
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700369 int ret;
370 do {
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800371 ret = connect(s, addr, addrlen);
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700372 } while (ret < 0 && errno == EINTR);
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800373 int success = (ret == 0);
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700374 do {
375 ret = close(s);
376 } while (ret < 0 && errno == EINTR);
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800377 return success;
378}
379
380/*
381 * The following functions determine whether IPv4 or IPv6 connectivity is
382 * available in order to implement AI_ADDRCONFIG.
383 *
384 * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is
385 * available, but whether addresses of the specified family are "configured
386 * on the local system". However, bionic doesn't currently support getifaddrs,
387 * so checking for connectivity is the next best thing.
388 */
389static int
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500390_have_ipv6(unsigned mark) {
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700391 static const struct sockaddr_in6 sin6_test = {
392 .sin6_family = AF_INET6,
393 .sin6_addr.s6_addr = { // 2000::
394 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
395 };
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500396 sockaddr_union addr = { .in6 = sin6_test };
397 return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6), mark);
Lorenzo Colittiba96e302011-01-14 12:26:05 -0800398}
399
400static int
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500401_have_ipv4(unsigned mark) {
Lorenzo Colittib82532d2011-09-28 19:28:32 -0700402 static const struct sockaddr_in sin_test = {
403 .sin_family = AF_INET,
404 .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8
405 };
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500406 sockaddr_union addr = { .in = sin_test };
407 return _test_connect(PF_INET, &addr.generic, sizeof(addr.in), mark);
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -0700408}
409
Mattias Falkc63e5902011-08-23 14:34:14 +0200410// Returns 0 on success, else returns on error.
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700411static int
412android_getaddrinfo_proxy(
413 const char *hostname, const char *servname,
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500414 const struct addrinfo *hints, struct addrinfo **res, unsigned netid)
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700415{
416 int sock;
417 const int one = 1;
418 struct sockaddr_un proxy_addr;
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700419 FILE* proxy = NULL;
420 int success = 0;
421
422 // Clear this at start, as we use its non-NULLness later (in the
423 // error path) to decide if we have to free up any memory we
424 // allocated in the process (before failing).
425 *res = NULL;
426
Mattias Falkc63e5902011-08-23 14:34:14 +0200427 // Bogus things we can't serialize. Don't use the proxy. These will fail - let them.
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700428 if ((hostname != NULL &&
429 strcspn(hostname, " \n\r\t^'\"") != strlen(hostname)) ||
430 (servname != NULL &&
431 strcspn(servname, " \n\r\t^'\"") != strlen(servname))) {
Mattias Falkc63e5902011-08-23 14:34:14 +0200432 return EAI_NODATA;
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700433 }
434
435 sock = socket(AF_UNIX, SOCK_STREAM, 0);
436 if (sock < 0) {
Mattias Falkc63e5902011-08-23 14:34:14 +0200437 return EAI_NODATA;
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700438 }
439
440 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
441 memset(&proxy_addr, 0, sizeof(proxy_addr));
442 proxy_addr.sun_family = AF_UNIX;
443 strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd",
444 sizeof(proxy_addr.sun_path));
445 if (TEMP_FAILURE_RETRY(connect(sock,
446 (const struct sockaddr*) &proxy_addr,
447 sizeof(proxy_addr))) != 0) {
448 close(sock);
Mattias Falkc63e5902011-08-23 14:34:14 +0200449 return EAI_NODATA;
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700450 }
451
452 // Send the request.
453 proxy = fdopen(sock, "r+");
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500454 if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u",
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700455 hostname == NULL ? "^" : hostname,
456 servname == NULL ? "^" : servname,
457 hints == NULL ? -1 : hints->ai_flags,
458 hints == NULL ? -1 : hints->ai_family,
459 hints == NULL ? -1 : hints->ai_socktype,
Mattias Falkc63e5902011-08-23 14:34:14 +0200460 hints == NULL ? -1 : hints->ai_protocol,
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500461 netid) < 0) {
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700462 goto exit;
463 }
464 // literal NULL byte at end, required by FrameworkListener
465 if (fputc(0, proxy) == EOF ||
466 fflush(proxy) != 0) {
467 goto exit;
468 }
469
Robert Greenwaltc59ba452012-03-09 11:34:27 -0800470 char buf[4];
Selim Gurun06e18312012-02-27 15:58:54 -0800471 // read result code for gethostbyaddr
472 if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) {
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700473 goto exit;
474 }
475
Selim Gurun06e18312012-02-27 15:58:54 -0800476 int result_code = (int)strtol(buf, NULL, 10);
477 // verify the code itself
478 if (result_code != DnsProxyQueryResult ) {
Mattias Falkc63e5902011-08-23 14:34:14 +0200479 fread(buf, 1, sizeof(buf), proxy);
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700480 goto exit;
481 }
482
483 struct addrinfo* ai = NULL;
484 struct addrinfo** nextres = res;
485 while (1) {
486 uint32_t addrinfo_len;
487 if (fread(&addrinfo_len, sizeof(addrinfo_len),
488 1, proxy) != 1) {
489 break;
490 }
491 addrinfo_len = ntohl(addrinfo_len);
492 if (addrinfo_len == 0) {
493 success = 1;
494 break;
495 }
496
497 if (addrinfo_len < sizeof(struct addrinfo)) {
498 break;
499 }
500 struct addrinfo* ai = calloc(1, addrinfo_len +
501 sizeof(struct sockaddr_storage));
502 if (ai == NULL) {
503 break;
504 }
505
506 if (fread(ai, addrinfo_len, 1, proxy) != 1) {
507 // Error; fall through.
508 break;
509 }
510
511 // Zero out the pointer fields we copied which aren't
512 // valid in this address space.
513 ai->ai_addr = NULL;
514 ai->ai_canonname = NULL;
515 ai->ai_next = NULL;
516
517 // struct sockaddr
518 uint32_t addr_len;
519 if (fread(&addr_len, sizeof(addr_len), 1, proxy) != 1) {
520 break;
521 }
522 addr_len = ntohl(addr_len);
523 if (addr_len != 0) {
524 if (addr_len > sizeof(struct sockaddr_storage)) {
525 // Bogus; too big.
526 break;
527 }
528 struct sockaddr* addr = (struct sockaddr*)(ai + 1);
529 if (fread(addr, addr_len, 1, proxy) != 1) {
530 break;
531 }
532 ai->ai_addr = addr;
533 }
534
535 // cannonname
536 uint32_t name_len;
537 if (fread(&name_len, sizeof(name_len), 1, proxy) != 1) {
538 break;
539 }
Mattias Falk0ee092f2011-02-15 08:44:20 +0100540 name_len = ntohl(name_len);
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700541 if (name_len != 0) {
542 ai->ai_canonname = (char*) malloc(name_len);
543 if (fread(ai->ai_canonname, name_len, 1, proxy) != 1) {
544 break;
545 }
546 if (ai->ai_canonname[name_len - 1] != '\0') {
547 // The proxy should be returning this
548 // NULL-terminated.
549 break;
550 }
551 }
552
553 *nextres = ai;
554 nextres = &ai->ai_next;
555 ai = NULL;
556 }
557
558 if (ai != NULL) {
559 // Clean up partially-built addrinfo that we never ended up
560 // attaching to the response.
561 freeaddrinfo(ai);
562 }
563exit:
564 if (proxy != NULL) {
565 fclose(proxy);
566 }
567
568 if (success) {
569 return 0;
570 }
571
Mattias Falkc63e5902011-08-23 14:34:14 +0200572 // Proxy failed;
573 // clean up memory we might've allocated.
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700574 if (*res) {
575 freeaddrinfo(*res);
576 *res = NULL;
577 }
Mattias Falkc63e5902011-08-23 14:34:14 +0200578 return EAI_NODATA;
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700579}
580
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800581int
582getaddrinfo(const char *hostname, const char *servname,
583 const struct addrinfo *hints, struct addrinfo **res)
584{
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500585 return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);
Mattias Falkc63e5902011-08-23 14:34:14 +0200586}
587
588int
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500589android_getaddrinfofornet(const char *hostname, const char *servname,
590 const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
Mattias Falkc63e5902011-08-23 14:34:14 +0200591{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800592 struct addrinfo sentinel;
593 struct addrinfo *cur;
594 int error = 0;
595 struct addrinfo ai;
596 struct addrinfo ai0;
597 struct addrinfo *pai;
598 const struct explore *ex;
Mattias Falkc63e5902011-08-23 14:34:14 +0200599 const char* cache_mode = getenv("ANDROID_DNS_MODE");
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800600
601 /* hostname is allowed to be NULL */
602 /* servname is allowed to be NULL */
603 /* hints is allowed to be NULL */
604 assert(res != NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800605 memset(&sentinel, 0, sizeof(sentinel));
606 cur = &sentinel;
607 pai = &ai;
608 pai->ai_flags = 0;
609 pai->ai_family = PF_UNSPEC;
610 pai->ai_socktype = ANY;
611 pai->ai_protocol = ANY;
612 pai->ai_addrlen = 0;
613 pai->ai_canonname = NULL;
614 pai->ai_addr = NULL;
615 pai->ai_next = NULL;
616
617 if (hostname == NULL && servname == NULL)
618 return EAI_NONAME;
619 if (hints) {
620 /* error check for hints */
621 if (hints->ai_addrlen || hints->ai_canonname ||
622 hints->ai_addr || hints->ai_next)
623 ERR(EAI_BADHINTS); /* xxx */
624 if (hints->ai_flags & ~AI_MASK)
625 ERR(EAI_BADFLAGS);
626 switch (hints->ai_family) {
627 case PF_UNSPEC:
628 case PF_INET:
629#ifdef INET6
630 case PF_INET6:
631#endif
632 break;
633 default:
634 ERR(EAI_FAMILY);
635 }
636 memcpy(pai, hints, sizeof(*pai));
637
638 /*
639 * if both socktype/protocol are specified, check if they
640 * are meaningful combination.
641 */
642 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
643 for (ex = explore; ex->e_af >= 0; ex++) {
644 if (pai->ai_family != ex->e_af)
645 continue;
646 if (ex->e_socktype == ANY)
647 continue;
648 if (ex->e_protocol == ANY)
649 continue;
650 if (pai->ai_socktype == ex->e_socktype
651 && pai->ai_protocol != ex->e_protocol) {
652 ERR(EAI_BADHINTS);
653 }
654 }
655 }
656 }
657
658 /*
659 * check for special cases. (1) numeric servname is disallowed if
660 * socktype/protocol are left unspecified. (2) servname is disallowed
661 * for raw and other inet{,6} sockets.
662 */
663 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
664#ifdef PF_INET6
665 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
666#endif
667 ) {
668 ai0 = *pai; /* backup *pai */
669
670 if (pai->ai_family == PF_UNSPEC) {
671#ifdef PF_INET6
672 pai->ai_family = PF_INET6;
673#else
674 pai->ai_family = PF_INET;
675#endif
676 }
677 error = get_portmatch(pai, servname);
678 if (error)
679 ERR(error);
680
681 *pai = ai0;
682 }
683
684 ai0 = *pai;
685
686 /* NULL hostname, or numeric hostname */
687 for (ex = explore; ex->e_af >= 0; ex++) {
688 *pai = ai0;
689
690 /* PF_UNSPEC entries are prepared for DNS queries only */
691 if (ex->e_af == PF_UNSPEC)
692 continue;
693
694 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
695 continue;
696 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
697 continue;
698 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
699 continue;
700
701 if (pai->ai_family == PF_UNSPEC)
702 pai->ai_family = ex->e_af;
703 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
704 pai->ai_socktype = ex->e_socktype;
705 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
706 pai->ai_protocol = ex->e_protocol;
707
708 if (hostname == NULL)
709 error = explore_null(pai, servname, &cur->ai_next);
710 else
711 error = explore_numeric_scope(pai, hostname, servname,
712 &cur->ai_next);
713
714 if (error)
715 goto free;
716
717 while (cur->ai_next)
718 cur = cur->ai_next;
719 }
720
721 /*
722 * XXX
723 * If numeric representation of AF1 can be interpreted as FQDN
724 * representation of AF2, we need to think again about the code below.
725 */
726 if (sentinel.ai_next)
727 goto good;
728
729 if (hostname == NULL)
730 ERR(EAI_NODATA);
731 if (pai->ai_flags & AI_NUMERICHOST)
732 ERR(EAI_NONAME);
733
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700734 /*
735 * BEGIN ANDROID CHANGES; proxying to the cache
736 */
Mattias Falkc63e5902011-08-23 14:34:14 +0200737 if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
738 // we're not the proxy - pass the request to them
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500739 return android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
Mattias Falkc63e5902011-08-23 14:34:14 +0200740 }
Brad Fitzpatricka1dbf0b2010-10-27 10:36:36 -0700741
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800742 /*
743 * hostname as alphabetical name.
744 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
745 * outer loop by AFs.
746 */
747 for (ex = explore; ex->e_af >= 0; ex++) {
748 *pai = ai0;
749
750 /* require exact match for family field */
751 if (pai->ai_family != ex->e_af)
752 continue;
753
754 if (!MATCH(pai->ai_socktype, ex->e_socktype,
755 WILD_SOCKTYPE(ex))) {
756 continue;
757 }
758 if (!MATCH(pai->ai_protocol, ex->e_protocol,
759 WILD_PROTOCOL(ex))) {
760 continue;
761 }
762
763 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
764 pai->ai_socktype = ex->e_socktype;
765 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
766 pai->ai_protocol = ex->e_protocol;
767
768 error = explore_fqdn(pai, hostname, servname,
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500769 &cur->ai_next, netid, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800770
771 while (cur && cur->ai_next)
772 cur = cur->ai_next;
773 }
774
775 /* XXX */
776 if (sentinel.ai_next)
777 error = 0;
778
779 if (error)
780 goto free;
781 if (error == 0) {
782 if (sentinel.ai_next) {
783 good:
784 *res = sentinel.ai_next;
785 return SUCCESS;
786 } else
787 error = EAI_FAIL;
788 }
789 free:
790 bad:
791 if (sentinel.ai_next)
792 freeaddrinfo(sentinel.ai_next);
793 *res = NULL;
794 return error;
795}
796
797/*
798 * FQDN hostname, DNS lookup
799 */
800static int
801explore_fqdn(const struct addrinfo *pai, const char *hostname,
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500802 const char *servname, struct addrinfo **res, unsigned netid, unsigned mark)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800803{
804 struct addrinfo *result;
805 struct addrinfo *cur;
806 int error = 0;
807 static const ns_dtab dtab[] = {
808 NS_FILES_CB(_files_getaddrinfo, NULL)
809 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
810 NS_NIS_CB(_yp_getaddrinfo, NULL)
811 { 0, 0, 0 }
812 };
813
814 assert(pai != NULL);
815 /* hostname may be NULL */
816 /* servname may be NULL */
817 assert(res != NULL);
818
819 result = NULL;
820
821 /*
822 * if the servname does not match socktype/protocol, ignore it.
823 */
824 if (get_portmatch(pai, servname) != 0)
825 return 0;
826
827 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500828 default_dns_files, hostname, pai, netid, mark)) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800829 case NS_TRYAGAIN:
830 error = EAI_AGAIN;
831 goto free;
832 case NS_UNAVAIL:
833 error = EAI_FAIL;
834 goto free;
835 case NS_NOTFOUND:
836 error = EAI_NODATA;
837 goto free;
838 case NS_SUCCESS:
839 error = 0;
840 for (cur = result; cur; cur = cur->ai_next) {
841 GET_PORT(cur, servname);
842 /* canonname should be filled already */
843 }
844 break;
845 }
846
847 *res = result;
848
849 return 0;
850
851free:
852 if (result)
853 freeaddrinfo(result);
854 return error;
855}
856
857/*
858 * hostname == NULL.
859 * passive socket -> anyaddr (0.0.0.0 or ::)
860 * non-passive socket -> localhost (127.0.0.1 or ::1)
861 */
862static int
863explore_null(const struct addrinfo *pai, const char *servname,
864 struct addrinfo **res)
865{
866 int s;
867 const struct afd *afd;
868 struct addrinfo *cur;
869 struct addrinfo sentinel;
870 int error;
871
872 assert(pai != NULL);
873 /* servname may be NULL */
874 assert(res != NULL);
875
876 *res = NULL;
877 sentinel.ai_next = NULL;
878 cur = &sentinel;
879
880 /*
881 * filter out AFs that are not supported by the kernel
882 * XXX errno?
883 */
884 s = socket(pai->ai_family, SOCK_DGRAM, 0);
885 if (s < 0) {
886 if (errno != EMFILE)
887 return 0;
888 } else
889 close(s);
890
891 /*
892 * if the servname does not match socktype/protocol, ignore it.
893 */
894 if (get_portmatch(pai, servname) != 0)
895 return 0;
896
897 afd = find_afd(pai->ai_family);
898 if (afd == NULL)
899 return 0;
900
901 if (pai->ai_flags & AI_PASSIVE) {
902 GET_AI(cur->ai_next, afd, afd->a_addrany);
903 /* xxx meaningless?
904 * GET_CANONNAME(cur->ai_next, "anyaddr");
905 */
906 GET_PORT(cur->ai_next, servname);
907 } else {
908 GET_AI(cur->ai_next, afd, afd->a_loopback);
909 /* xxx meaningless?
910 * GET_CANONNAME(cur->ai_next, "localhost");
911 */
912 GET_PORT(cur->ai_next, servname);
913 }
914 cur = cur->ai_next;
915
916 *res = sentinel.ai_next;
917 return 0;
918
919free:
920 if (sentinel.ai_next)
921 freeaddrinfo(sentinel.ai_next);
922 return error;
923}
924
925/*
926 * numeric hostname
927 */
928static int
929explore_numeric(const struct addrinfo *pai, const char *hostname,
930 const char *servname, struct addrinfo **res, const char *canonname)
931{
932 const struct afd *afd;
933 struct addrinfo *cur;
934 struct addrinfo sentinel;
935 int error;
936 char pton[PTON_MAX];
937
938 assert(pai != NULL);
939 /* hostname may be NULL */
940 /* servname may be NULL */
941 assert(res != NULL);
942
943 *res = NULL;
944 sentinel.ai_next = NULL;
945 cur = &sentinel;
946
947 /*
948 * if the servname does not match socktype/protocol, ignore it.
949 */
950 if (get_portmatch(pai, servname) != 0)
951 return 0;
952
953 afd = find_afd(pai->ai_family);
954 if (afd == NULL)
955 return 0;
956
957 switch (afd->a_af) {
958#if 0 /*X/Open spec*/
959 case AF_INET:
960 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
961 if (pai->ai_family == afd->a_af ||
962 pai->ai_family == PF_UNSPEC /*?*/) {
963 GET_AI(cur->ai_next, afd, pton);
964 GET_PORT(cur->ai_next, servname);
965 if ((pai->ai_flags & AI_CANONNAME)) {
966 /*
967 * Set the numeric address itself as
968 * the canonical name, based on a
969 * clarification in rfc2553bis-03.
970 */
971 GET_CANONNAME(cur->ai_next, canonname);
972 }
973 while (cur && cur->ai_next)
974 cur = cur->ai_next;
975 } else
976 ERR(EAI_FAMILY); /*xxx*/
977 }
978 break;
979#endif
980 default:
981 if (inet_pton(afd->a_af, hostname, pton) == 1) {
982 if (pai->ai_family == afd->a_af ||
983 pai->ai_family == PF_UNSPEC /*?*/) {
984 GET_AI(cur->ai_next, afd, pton);
985 GET_PORT(cur->ai_next, servname);
986 if ((pai->ai_flags & AI_CANONNAME)) {
987 /*
988 * Set the numeric address itself as
989 * the canonical name, based on a
990 * clarification in rfc2553bis-03.
991 */
992 GET_CANONNAME(cur->ai_next, canonname);
993 }
994 while (cur->ai_next)
995 cur = cur->ai_next;
996 } else
997 ERR(EAI_FAMILY); /*xxx*/
998 }
999 break;
1000 }
1001
1002 *res = sentinel.ai_next;
1003 return 0;
1004
1005free:
1006bad:
1007 if (sentinel.ai_next)
1008 freeaddrinfo(sentinel.ai_next);
1009 return error;
1010}
1011
1012/*
1013 * numeric hostname with scope
1014 */
1015static int
1016explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
1017 const char *servname, struct addrinfo **res)
1018{
1019#if !defined(SCOPE_DELIMITER) || !defined(INET6)
1020 return explore_numeric(pai, hostname, servname, res, hostname);
1021#else
1022 const struct afd *afd;
1023 struct addrinfo *cur;
1024 int error;
1025 char *cp, *hostname2 = NULL, *scope, *addr;
1026 struct sockaddr_in6 *sin6;
1027
1028 assert(pai != NULL);
1029 /* hostname may be NULL */
1030 /* servname may be NULL */
1031 assert(res != NULL);
1032
1033 /*
1034 * if the servname does not match socktype/protocol, ignore it.
1035 */
1036 if (get_portmatch(pai, servname) != 0)
1037 return 0;
1038
1039 afd = find_afd(pai->ai_family);
1040 if (afd == NULL)
1041 return 0;
1042
1043 if (!afd->a_scoped)
1044 return explore_numeric(pai, hostname, servname, res, hostname);
1045
1046 cp = strchr(hostname, SCOPE_DELIMITER);
1047 if (cp == NULL)
1048 return explore_numeric(pai, hostname, servname, res, hostname);
1049
1050 /*
1051 * Handle special case of <scoped_address><delimiter><scope id>
1052 */
1053 hostname2 = strdup(hostname);
1054 if (hostname2 == NULL)
1055 return EAI_MEMORY;
1056 /* terminate at the delimiter */
1057 hostname2[cp - hostname] = '\0';
1058 addr = hostname2;
1059 scope = cp + 1;
1060
1061 error = explore_numeric(pai, addr, servname, res, hostname);
1062 if (error == 0) {
1063 u_int32_t scopeid;
1064
1065 for (cur = *res; cur; cur = cur->ai_next) {
1066 if (cur->ai_family != AF_INET6)
1067 continue;
1068 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
1069 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
1070 free(hostname2);
1071 return(EAI_NODATA); /* XXX: is return OK? */
1072 }
1073 sin6->sin6_scope_id = scopeid;
1074 }
1075 }
1076
1077 free(hostname2);
1078
1079 return error;
1080#endif
1081}
1082
1083static int
1084get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
1085{
1086
1087 assert(pai != NULL);
1088 assert(ai != NULL);
1089 assert(str != NULL);
1090
1091 if ((pai->ai_flags & AI_CANONNAME) != 0) {
1092 ai->ai_canonname = strdup(str);
1093 if (ai->ai_canonname == NULL)
1094 return EAI_MEMORY;
1095 }
1096 return 0;
1097}
1098
1099static struct addrinfo *
1100get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
1101{
1102 char *p;
1103 struct addrinfo *ai;
1104
1105 assert(pai != NULL);
1106 assert(afd != NULL);
1107 assert(addr != NULL);
1108
1109 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
1110 + (afd->a_socklen));
1111 if (ai == NULL)
1112 return NULL;
1113
1114 memcpy(ai, pai, sizeof(struct addrinfo));
1115 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
1116 memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
1117
1118#ifdef HAVE_SA_LEN
1119 ai->ai_addr->sa_len = afd->a_socklen;
1120#endif
1121
1122 ai->ai_addrlen = afd->a_socklen;
1123#if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__)
1124 ai->__ai_pad0 = 0;
1125#endif
1126 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1127 p = (char *)(void *)(ai->ai_addr);
1128 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
1129 return ai;
1130}
1131
1132static int
1133get_portmatch(const struct addrinfo *ai, const char *servname)
1134{
1135
1136 assert(ai != NULL);
1137 /* servname may be NULL */
1138
1139 return get_port(ai, servname, 1);
1140}
1141
1142static int
1143get_port(const struct addrinfo *ai, const char *servname, int matchonly)
1144{
1145 const char *proto;
1146 struct servent *sp;
1147 int port;
1148 int allownumeric;
1149
1150 assert(ai != NULL);
1151 /* servname may be NULL */
1152
1153 if (servname == NULL)
1154 return 0;
1155 switch (ai->ai_family) {
1156 case AF_INET:
1157#ifdef AF_INET6
1158 case AF_INET6:
1159#endif
1160 break;
1161 default:
1162 return 0;
1163 }
1164
1165 switch (ai->ai_socktype) {
1166 case SOCK_RAW:
1167 return EAI_SERVICE;
1168 case SOCK_DGRAM:
1169 case SOCK_STREAM:
1170 allownumeric = 1;
1171 break;
1172 case ANY:
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001173#if 1 /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */
David 'Digit' Turner5e563702009-05-05 15:50:24 +02001174 allownumeric = 1;
1175#else
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001176 allownumeric = 0;
David 'Digit' Turner5e563702009-05-05 15:50:24 +02001177#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001178 break;
1179 default:
1180 return EAI_SOCKTYPE;
1181 }
1182
1183 port = str2number(servname);
1184 if (port >= 0) {
1185 if (!allownumeric)
1186 return EAI_SERVICE;
1187 if (port < 0 || port > 65535)
1188 return EAI_SERVICE;
1189 port = htons(port);
1190 } else {
1191 if (ai->ai_flags & AI_NUMERICSERV)
1192 return EAI_NONAME;
1193
1194 switch (ai->ai_socktype) {
1195 case SOCK_DGRAM:
1196 proto = "udp";
1197 break;
1198 case SOCK_STREAM:
1199 proto = "tcp";
1200 break;
1201 default:
1202 proto = NULL;
1203 break;
1204 }
1205
1206 if ((sp = getservbyname(servname, proto)) == NULL)
1207 return EAI_SERVICE;
1208 port = sp->s_port;
1209 }
1210
1211 if (!matchonly) {
1212 switch (ai->ai_family) {
1213 case AF_INET:
1214 ((struct sockaddr_in *)(void *)
1215 ai->ai_addr)->sin_port = port;
1216 break;
1217#ifdef INET6
1218 case AF_INET6:
1219 ((struct sockaddr_in6 *)(void *)
1220 ai->ai_addr)->sin6_port = port;
1221 break;
1222#endif
1223 }
1224 }
1225
1226 return 0;
1227}
1228
1229static const struct afd *
1230find_afd(int af)
1231{
1232 const struct afd *afd;
1233
1234 if (af == PF_UNSPEC)
1235 return NULL;
1236 for (afd = afdl; afd->a_af; afd++) {
1237 if (afd->a_af == af)
1238 return afd;
1239 }
1240 return NULL;
1241}
1242
1243#ifdef INET6
1244/* convert a string to a scope identifier. XXX: IPv6 specific */
1245static int
1246ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1247{
1248 u_long lscopeid;
1249 struct in6_addr *a6;
1250 char *ep;
1251
1252 assert(scope != NULL);
1253 assert(sin6 != NULL);
1254 assert(scopeid != NULL);
1255
1256 a6 = &sin6->sin6_addr;
1257
1258 /* empty scopeid portion is invalid */
1259 if (*scope == '\0')
1260 return -1;
1261
1262 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1263 /*
1264 * We currently assume a one-to-one mapping between links
1265 * and interfaces, so we simply use interface indices for
1266 * like-local scopes.
1267 */
1268 *scopeid = if_nametoindex(scope);
1269 if (*scopeid == 0)
1270 goto trynumeric;
1271 return 0;
1272 }
1273
1274 /* still unclear about literal, allow numeric only - placeholder */
1275 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1276 goto trynumeric;
1277 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1278 goto trynumeric;
1279 else
1280 goto trynumeric; /* global */
1281
1282 /* try to convert to a numeric id as a last resort */
1283 trynumeric:
1284 errno = 0;
1285 lscopeid = strtoul(scope, &ep, 10);
1286 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1287 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1288 return 0;
1289 else
1290 return -1;
1291}
1292#endif
1293
1294/* code duplicate with gethnamaddr.c */
1295
1296static const char AskedForGot[] =
1297 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1298
1299static struct addrinfo *
1300getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1301 const struct addrinfo *pai)
1302{
1303 struct addrinfo sentinel, *cur;
1304 struct addrinfo ai;
1305 const struct afd *afd;
1306 char *canonname;
1307 const HEADER *hp;
1308 const u_char *cp;
1309 int n;
1310 const u_char *eom;
1311 char *bp, *ep;
1312 int type, class, ancount, qdcount;
1313 int haveanswer, had_error;
1314 char tbuf[MAXDNAME];
1315 int (*name_ok) (const char *);
1316 char hostbuf[8*1024];
1317
1318 assert(answer != NULL);
1319 assert(qname != NULL);
1320 assert(pai != NULL);
1321
1322 memset(&sentinel, 0, sizeof(sentinel));
1323 cur = &sentinel;
1324
1325 canonname = NULL;
1326 eom = answer->buf + anslen;
1327 switch (qtype) {
1328 case T_A:
1329 case T_AAAA:
1330 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1331 name_ok = res_hnok;
1332 break;
1333 default:
1334 return NULL; /* XXX should be abort(); */
1335 }
1336 /*
1337 * find first satisfactory answer
1338 */
1339 hp = &answer->hdr;
1340 ancount = ntohs(hp->ancount);
1341 qdcount = ntohs(hp->qdcount);
1342 bp = hostbuf;
1343 ep = hostbuf + sizeof hostbuf;
1344 cp = answer->buf + HFIXEDSZ;
1345 if (qdcount != 1) {
1346 h_errno = NO_RECOVERY;
1347 return (NULL);
1348 }
1349 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1350 if ((n < 0) || !(*name_ok)(bp)) {
1351 h_errno = NO_RECOVERY;
1352 return (NULL);
1353 }
1354 cp += n + QFIXEDSZ;
1355 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1356 /* res_send() has already verified that the query name is the
1357 * same as the one we sent; this just gets the expanded name
1358 * (i.e., with the succeeding search-domain tacked on).
1359 */
1360 n = strlen(bp) + 1; /* for the \0 */
1361 if (n >= MAXHOSTNAMELEN) {
1362 h_errno = NO_RECOVERY;
1363 return (NULL);
1364 }
1365 canonname = bp;
1366 bp += n;
1367 /* The qname can be abbreviated, but h_name is now absolute. */
1368 qname = canonname;
1369 }
1370 haveanswer = 0;
1371 had_error = 0;
1372 while (ancount-- > 0 && cp < eom && !had_error) {
1373 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1374 if ((n < 0) || !(*name_ok)(bp)) {
1375 had_error++;
1376 continue;
1377 }
1378 cp += n; /* name */
1379 type = _getshort(cp);
Lorenzo Colittib82532d2011-09-28 19:28:32 -07001380 cp += INT16SZ; /* type */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001381 class = _getshort(cp);
Lorenzo Colittib82532d2011-09-28 19:28:32 -07001382 cp += INT16SZ + INT32SZ; /* class, TTL */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001383 n = _getshort(cp);
1384 cp += INT16SZ; /* len */
1385 if (class != C_IN) {
1386 /* XXX - debug? syslog? */
1387 cp += n;
1388 continue; /* XXX - had_error++ ? */
1389 }
1390 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1391 type == T_CNAME) {
1392 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1393 if ((n < 0) || !(*name_ok)(tbuf)) {
1394 had_error++;
1395 continue;
1396 }
1397 cp += n;
1398 /* Get canonical name. */
1399 n = strlen(tbuf) + 1; /* for the \0 */
1400 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1401 had_error++;
1402 continue;
1403 }
1404 strlcpy(bp, tbuf, (size_t)(ep - bp));
1405 canonname = bp;
1406 bp += n;
1407 continue;
1408 }
1409 if (qtype == T_ANY) {
1410 if (!(type == T_A || type == T_AAAA)) {
1411 cp += n;
1412 continue;
1413 }
1414 } else if (type != qtype) {
1415 if (type != T_KEY && type != T_SIG)
1416 syslog(LOG_NOTICE|LOG_AUTH,
1417 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1418 qname, p_class(C_IN), p_type(qtype),
1419 p_type(type));
1420 cp += n;
1421 continue; /* XXX - had_error++ ? */
1422 }
1423 switch (type) {
1424 case T_A:
1425 case T_AAAA:
1426 if (strcasecmp(canonname, bp) != 0) {
1427 syslog(LOG_NOTICE|LOG_AUTH,
1428 AskedForGot, canonname, bp);
1429 cp += n;
1430 continue; /* XXX - had_error++ ? */
1431 }
1432 if (type == T_A && n != INADDRSZ) {
1433 cp += n;
1434 continue;
1435 }
1436 if (type == T_AAAA && n != IN6ADDRSZ) {
1437 cp += n;
1438 continue;
1439 }
1440 if (type == T_AAAA) {
1441 struct in6_addr in6;
1442 memcpy(&in6, cp, IN6ADDRSZ);
1443 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1444 cp += n;
1445 continue;
1446 }
1447 }
1448 if (!haveanswer) {
1449 int nn;
1450
1451 canonname = bp;
1452 nn = strlen(bp) + 1; /* for the \0 */
1453 bp += nn;
1454 }
1455
1456 /* don't overwrite pai */
1457 ai = *pai;
1458 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1459 afd = find_afd(ai.ai_family);
1460 if (afd == NULL) {
1461 cp += n;
1462 continue;
1463 }
1464 cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1465 if (cur->ai_next == NULL)
1466 had_error++;
1467 while (cur && cur->ai_next)
1468 cur = cur->ai_next;
1469 cp += n;
1470 break;
1471 default:
1472 abort();
1473 }
1474 if (!had_error)
1475 haveanswer++;
1476 }
1477 if (haveanswer) {
1478 if (!canonname)
1479 (void)get_canonname(pai, sentinel.ai_next, qname);
1480 else
1481 (void)get_canonname(pai, sentinel.ai_next, canonname);
1482 h_errno = NETDB_SUCCESS;
1483 return sentinel.ai_next;
1484 }
1485
1486 h_errno = NO_RECOVERY;
1487 return NULL;
1488}
1489
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001490struct addrinfo_sort_elem {
1491 struct addrinfo *ai;
1492 int has_src_addr;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001493 sockaddr_union src_addr;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001494 int original_order;
1495};
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001496
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001497/*ARGSUSED*/
1498static int
1499_get_scope(const struct sockaddr *addr)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001500{
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001501 if (addr->sa_family == AF_INET6) {
1502 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
1503 if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) {
1504 return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
1505 } else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
1506 IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
1507 /*
1508 * RFC 4291 section 2.5.3 says loopback is to be treated as having
1509 * link-local scope.
1510 */
1511 return IPV6_ADDR_SCOPE_LINKLOCAL;
1512 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
1513 return IPV6_ADDR_SCOPE_SITELOCAL;
1514 } else {
1515 return IPV6_ADDR_SCOPE_GLOBAL;
1516 }
1517 } else if (addr->sa_family == AF_INET) {
1518 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
1519 unsigned long int na = ntohl(addr4->sin_addr.s_addr);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001520
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001521 if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */
1522 (na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */
1523 return IPV6_ADDR_SCOPE_LINKLOCAL;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001524 } else {
Steinar H. Gundersond1624ad2010-12-20 11:15:33 +01001525 /*
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001526 * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses
1527 * and shared addresses (100.64.0.0/10), are assigned global scope.
Steinar H. Gundersond1624ad2010-12-20 11:15:33 +01001528 */
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001529 return IPV6_ADDR_SCOPE_GLOBAL;
1530 }
1531 } else {
1532 /*
1533 * This should never happen.
1534 * Return a scope with low priority as a last resort.
1535 */
1536 return IPV6_ADDR_SCOPE_NODELOCAL;
1537 }
1538}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001539
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001540/* These macros are modelled after the ones in <netinet/in6.h>. */
1541
1542/* RFC 4380, section 2.6 */
1543#define IN6_IS_ADDR_TEREDO(a) \
1544 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
1545
1546/* RFC 3056, section 2. */
1547#define IN6_IS_ADDR_6TO4(a) \
1548 (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
1549
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001550/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
1551#define IN6_IS_ADDR_6BONE(a) \
1552 (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
1553
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001554/*
1555 * Get the label for a given IPv4/IPv6 address.
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001556 * RFC 6724, section 2.1.
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001557 */
1558
1559/*ARGSUSED*/
1560static int
1561_get_label(const struct sockaddr *addr)
1562{
1563 if (addr->sa_family == AF_INET) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001564 return 4;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001565 } else if (addr->sa_family == AF_INET6) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001566 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001567 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
1568 return 0;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001569 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001570 return 4;
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001571 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
1572 return 2;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001573 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
1574 return 5;
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001575 } else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
1576 return 13;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001577 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001578 return 3;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001579 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
1580 return 11;
1581 } else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
1582 return 12;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001583 } else {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001584 /* All other IPv6 addresses, including global unicast addresses. */
1585 return 1;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001586 }
1587 } else {
1588 /*
1589 * This should never happen.
1590 * Return a semi-random label as a last resort.
1591 */
1592 return 1;
1593 }
1594}
1595
1596/*
1597 * Get the precedence for a given IPv4/IPv6 address.
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001598 * RFC 6724, section 2.1.
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001599 */
1600
1601/*ARGSUSED*/
1602static int
1603_get_precedence(const struct sockaddr *addr)
1604{
1605 if (addr->sa_family == AF_INET) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001606 return 35;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001607 } else if (addr->sa_family == AF_INET6) {
1608 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
1609 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
1610 return 50;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001611 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001612 return 35;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001613 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001614 return 30;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001615 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001616 return 5;
1617 } else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
1618 return 3;
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001619 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
Lorenzo Colittib82532d2011-09-28 19:28:32 -07001620 IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
1621 IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001622 return 1;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001623 } else {
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001624 /* All other IPv6 addresses, including global unicast addresses. */
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001625 return 40;
1626 }
1627 } else {
Steinar H. Gunderson2e23e292010-12-20 11:48:07 +01001628 return 1;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001629 }
1630}
1631
1632/*
1633 * Find number of matching initial bits between the two addresses a1 and a2.
1634 */
1635
1636/*ARGSUSED*/
1637static int
1638_common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2)
1639{
1640 const char *p1 = (const char *)a1;
1641 const char *p2 = (const char *)a2;
1642 unsigned i;
1643
1644 for (i = 0; i < sizeof(*a1); ++i) {
1645 int x, j;
1646
1647 if (p1[i] == p2[i]) {
1648 continue;
1649 }
1650 x = p1[i] ^ p2[i];
1651 for (j = 0; j < CHAR_BIT; ++j) {
1652 if (x & (1 << (CHAR_BIT - 1))) {
1653 return i * CHAR_BIT + j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001654 }
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001655 x <<= 1;
1656 }
1657 }
1658 return sizeof(*a1) * CHAR_BIT;
1659}
1660
1661/*
1662 * Compare two source/destination address pairs.
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001663 * RFC 6724, section 6.
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001664 */
1665
1666/*ARGSUSED*/
1667static int
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001668_rfc6724_compare(const void *ptr1, const void* ptr2)
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001669{
1670 const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
1671 const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
1672 int scope_src1, scope_dst1, scope_match1;
1673 int scope_src2, scope_dst2, scope_match2;
1674 int label_src1, label_dst1, label_match1;
1675 int label_src2, label_dst2, label_match2;
1676 int precedence1, precedence2;
1677 int prefixlen1, prefixlen2;
1678
1679 /* Rule 1: Avoid unusable destinations. */
1680 if (a1->has_src_addr != a2->has_src_addr) {
1681 return a2->has_src_addr - a1->has_src_addr;
1682 }
1683
1684 /* Rule 2: Prefer matching scope. */
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001685 scope_src1 = _get_scope(&a1->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001686 scope_dst1 = _get_scope(a1->ai->ai_addr);
1687 scope_match1 = (scope_src1 == scope_dst1);
1688
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001689 scope_src2 = _get_scope(&a2->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001690 scope_dst2 = _get_scope(a2->ai->ai_addr);
1691 scope_match2 = (scope_src2 == scope_dst2);
1692
1693 if (scope_match1 != scope_match2) {
1694 return scope_match2 - scope_match1;
1695 }
1696
1697 /*
1698 * Rule 3: Avoid deprecated addresses.
1699 * TODO(sesse): We don't currently have a good way of finding this.
1700 */
1701
1702 /*
1703 * Rule 4: Prefer home addresses.
1704 * TODO(sesse): We don't currently have a good way of finding this.
1705 */
1706
1707 /* Rule 5: Prefer matching label. */
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001708 label_src1 = _get_label(&a1->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001709 label_dst1 = _get_label(a1->ai->ai_addr);
1710 label_match1 = (label_src1 == label_dst1);
1711
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001712 label_src2 = _get_label(&a2->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001713 label_dst2 = _get_label(a2->ai->ai_addr);
1714 label_match2 = (label_src2 == label_dst2);
1715
1716 if (label_match1 != label_match2) {
1717 return label_match2 - label_match1;
1718 }
1719
1720 /* Rule 6: Prefer higher precedence. */
1721 precedence1 = _get_precedence(a1->ai->ai_addr);
1722 precedence2 = _get_precedence(a2->ai->ai_addr);
1723 if (precedence1 != precedence2) {
1724 return precedence2 - precedence1;
1725 }
1726
1727 /*
1728 * Rule 7: Prefer native transport.
1729 * TODO(sesse): We don't currently have a good way of finding this.
1730 */
1731
1732 /* Rule 8: Prefer smaller scope. */
1733 if (scope_dst1 != scope_dst2) {
1734 return scope_dst1 - scope_dst2;
1735 }
1736
1737 /*
1738 * Rule 9: Use longest matching prefix.
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001739 * We implement this for IPv6 only, as the rules in RFC 6724 don't seem
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001740 * to work very well directly applied to IPv4. (glibc uses information from
1741 * the routing table for a custom IPv4 implementation here.)
1742 */
1743 if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
1744 a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001745 const struct sockaddr_in6 *a1_src = &a1->src_addr.in6;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001746 const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001747 const struct sockaddr_in6 *a2_src = &a2->src_addr.in6;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001748 const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr;
1749 prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
Kenny Root7e0bfb52010-03-24 18:06:20 -07001750 prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001751 if (prefixlen1 != prefixlen2) {
1752 return prefixlen2 - prefixlen1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001753 }
1754 }
1755
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001756 /*
1757 * Rule 10: Leave the order unchanged.
1758 * We need this since qsort() is not necessarily stable.
1759 */
1760 return a1->original_order - a2->original_order;
1761}
1762
1763/*
1764 * Find the source address that will be used if trying to connect to the given
1765 * address. src_addr must be large enough to hold a struct sockaddr_in6.
1766 *
1767 * Returns 1 if a source address was found, 0 if the address is unreachable,
1768 * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
1769 * undefined.
1770 */
1771
1772/*ARGSUSED*/
1773static int
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001774_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark)
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001775{
1776 int sock;
1777 int ret;
1778 socklen_t len;
1779
1780 switch (addr->sa_family) {
1781 case AF_INET:
1782 len = sizeof(struct sockaddr_in);
1783 break;
1784 case AF_INET6:
1785 len = sizeof(struct sockaddr_in6);
1786 break;
1787 default:
1788 /* No known usable source address for non-INET families. */
1789 return 0;
1790 }
1791
1792 sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
1793 if (sock == -1) {
1794 if (errno == EAFNOSUPPORT) {
1795 return 0;
1796 } else {
1797 return -1;
1798 }
1799 }
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001800 if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
1801 return 0;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001802 do {
1803 ret = connect(sock, addr, len);
1804 } while (ret == -1 && errno == EINTR);
1805
1806 if (ret == -1) {
1807 close(sock);
1808 return 0;
1809 }
1810
1811 if (getsockname(sock, src_addr, &len) == -1) {
1812 close(sock);
1813 return -1;
1814 }
1815 close(sock);
1816 return 1;
1817}
1818
1819/*
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001820 * Sort the linked list starting at sentinel->ai_next in RFC6724 order.
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001821 * Will leave the list unchanged if an error occurs.
1822 */
1823
1824/*ARGSUSED*/
1825static void
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001826_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark)
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001827{
1828 struct addrinfo *cur;
1829 int nelem = 0, i;
1830 struct addrinfo_sort_elem *elems;
1831
1832 cur = list_sentinel->ai_next;
1833 while (cur) {
1834 ++nelem;
1835 cur = cur->ai_next;
1836 }
1837
1838 elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem));
1839 if (elems == NULL) {
1840 goto error;
1841 }
1842
1843 /*
1844 * Convert the linked list to an array that also contains the candidate
1845 * source address for each destination address.
1846 */
1847 for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) {
1848 int has_src_addr;
1849 assert(cur != NULL);
1850 elems[i].ai = cur;
1851 elems[i].original_order = i;
1852
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001853 has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001854 if (has_src_addr == -1) {
1855 goto error;
1856 }
1857 elems[i].has_src_addr = has_src_addr;
1858 }
1859
1860 /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */
Lorenzo Colitti378b0e12013-03-30 12:24:19 +09001861 qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc6724_compare);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001862
1863 list_sentinel->ai_next = elems[0].ai;
1864 for (i = 0; i < nelem - 1; ++i) {
1865 elems[i].ai->ai_next = elems[i + 1].ai;
1866 }
1867 elems[nelem - 1].ai->ai_next = NULL;
1868
1869error:
1870 free(elems);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001871}
1872
1873/*ARGSUSED*/
1874static int
1875_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1876{
1877 struct addrinfo *ai;
1878 querybuf *buf, *buf2;
1879 const char *name;
1880 const struct addrinfo *pai;
1881 struct addrinfo sentinel, *cur;
1882 struct res_target q, q2;
1883 res_state res;
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001884 unsigned netid, mark;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001885
1886 name = va_arg(ap, char *);
1887 pai = va_arg(ap, const struct addrinfo *);
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001888 netid = va_arg(ap, unsigned);
1889 mark = va_arg(ap, unsigned);
David 'Digit' Turner5e563702009-05-05 15:50:24 +02001890 //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001891
1892 memset(&q, 0, sizeof(q));
1893 memset(&q2, 0, sizeof(q2));
1894 memset(&sentinel, 0, sizeof(sentinel));
1895 cur = &sentinel;
1896
1897 buf = malloc(sizeof(*buf));
1898 if (buf == NULL) {
1899 h_errno = NETDB_INTERNAL;
1900 return NS_NOTFOUND;
1901 }
1902 buf2 = malloc(sizeof(*buf2));
1903 if (buf2 == NULL) {
1904 free(buf);
1905 h_errno = NETDB_INTERNAL;
1906 return NS_NOTFOUND;
1907 }
1908
1909 switch (pai->ai_family) {
1910 case AF_UNSPEC:
1911 /* prefer IPv6 */
1912 q.name = name;
1913 q.qclass = C_IN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001914 q.answer = buf->buf;
1915 q.anslen = sizeof(buf->buf);
Lorenzo Colittiba96e302011-01-14 12:26:05 -08001916 int query_ipv6 = 1, query_ipv4 = 1;
1917 if (pai->ai_flags & AI_ADDRCONFIG) {
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001918 query_ipv6 = _have_ipv6(mark);
1919 query_ipv4 = _have_ipv4(mark);
Lorenzo Colittiba96e302011-01-14 12:26:05 -08001920 }
1921 if (query_ipv6) {
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -07001922 q.qtype = T_AAAA;
Lorenzo Colittiba96e302011-01-14 12:26:05 -08001923 if (query_ipv4) {
1924 q.next = &q2;
1925 q2.name = name;
1926 q2.qclass = C_IN;
1927 q2.qtype = T_A;
1928 q2.answer = buf2->buf;
1929 q2.anslen = sizeof(buf2->buf);
1930 }
1931 } else if (query_ipv4) {
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -07001932 q.qtype = T_A;
Lorenzo Colittiba96e302011-01-14 12:26:05 -08001933 } else {
1934 free(buf);
1935 free(buf2);
1936 return NS_NOTFOUND;
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -07001937 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001938 break;
1939 case AF_INET:
1940 q.name = name;
1941 q.qclass = C_IN;
1942 q.qtype = T_A;
1943 q.answer = buf->buf;
1944 q.anslen = sizeof(buf->buf);
1945 break;
1946 case AF_INET6:
1947 q.name = name;
1948 q.qclass = C_IN;
1949 q.qtype = T_AAAA;
1950 q.answer = buf->buf;
1951 q.anslen = sizeof(buf->buf);
1952 break;
1953 default:
1954 free(buf);
1955 free(buf2);
1956 return NS_UNAVAIL;
1957 }
1958
1959 res = __res_get_state();
1960 if (res == NULL) {
1961 free(buf);
1962 free(buf2);
1963 return NS_NOTFOUND;
1964 }
1965
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001966 /* this just sets our netid val in the thread private data so we don't have to
Mattias Falkc63e5902011-08-23 14:34:14 +02001967 * modify the api's all the way down to res_send.c's res_nsend. We could
1968 * fully populate the thread private data here, but if we get down there
1969 * and have a cache hit that would be wasted, so we do the rest there on miss
1970 */
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001971 res_setnetid(res, netid);
Chad Brubakerc39214e2013-06-20 10:36:56 -07001972 res_setmark(res, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001973 if (res_searchN(name, &q, res) < 0) {
1974 __res_put_state(res);
1975 free(buf);
1976 free(buf2);
1977 return NS_NOTFOUND;
1978 }
1979 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1980 if (ai) {
1981 cur->ai_next = ai;
1982 while (cur && cur->ai_next)
1983 cur = cur->ai_next;
1984 }
1985 if (q.next) {
1986 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1987 if (ai)
1988 cur->ai_next = ai;
1989 }
1990 free(buf);
1991 free(buf2);
1992 if (sentinel.ai_next == NULL) {
1993 __res_put_state(res);
1994 switch (h_errno) {
1995 case HOST_NOT_FOUND:
1996 return NS_NOTFOUND;
1997 case TRY_AGAIN:
1998 return NS_TRYAGAIN;
1999 default:
2000 return NS_UNAVAIL;
2001 }
2002 }
2003
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05002004 _rfc6724_sort(&sentinel, netid);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002005
2006 __res_put_state(res);
2007
2008 *((struct addrinfo **)rv) = sentinel.ai_next;
2009 return NS_SUCCESS;
2010}
2011
2012static void
2013_sethtent(FILE **hostf)
2014{
2015
2016 if (!*hostf)
2017 *hostf = fopen(_PATH_HOSTS, "r" );
2018 else
2019 rewind(*hostf);
2020}
2021
2022static void
2023_endhtent(FILE **hostf)
2024{
2025
2026 if (*hostf) {
2027 (void) fclose(*hostf);
2028 *hostf = NULL;
2029 }
2030}
2031
2032static struct addrinfo *
2033_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
2034{
2035 char *p;
2036 char *cp, *tname, *cname;
2037 struct addrinfo hints, *res0, *res;
2038 int error;
2039 const char *addr;
2040 char hostbuf[8*1024];
2041
2042// fprintf(stderr, "_gethtent() name = '%s'\n", name);
2043 assert(name != NULL);
2044 assert(pai != NULL);
2045
2046 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
2047 return (NULL);
2048 again:
2049 if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
2050 return (NULL);
2051 if (*p == '#')
2052 goto again;
2053 if (!(cp = strpbrk(p, "#\n")))
2054 goto again;
2055 *cp = '\0';
2056 if (!(cp = strpbrk(p, " \t")))
2057 goto again;
2058 *cp++ = '\0';
2059 addr = p;
2060 /* if this is not something we're looking for, skip it. */
2061 cname = NULL;
2062 while (cp && *cp) {
2063 if (*cp == ' ' || *cp == '\t') {
2064 cp++;
2065 continue;
2066 }
2067 if (!cname)
2068 cname = cp;
2069 tname = cp;
2070 if ((cp = strpbrk(cp, " \t")) != NULL)
2071 *cp++ = '\0';
2072// fprintf(stderr, "\ttname = '%s'", tname);
2073 if (strcasecmp(name, tname) == 0)
2074 goto found;
2075 }
2076 goto again;
2077
2078found:
2079 hints = *pai;
2080 hints.ai_flags = AI_NUMERICHOST;
2081 error = getaddrinfo(addr, NULL, &hints, &res0);
2082 if (error)
2083 goto again;
2084 for (res = res0; res; res = res->ai_next) {
2085 /* cover it up */
2086 res->ai_flags = pai->ai_flags;
2087
2088 if (pai->ai_flags & AI_CANONNAME) {
2089 if (get_canonname(pai, res, cname) != 0) {
2090 freeaddrinfo(res0);
2091 goto again;
2092 }
2093 }
2094 }
2095 return res0;
2096}
2097
2098/*ARGSUSED*/
2099static int
2100_files_getaddrinfo(void *rv, void *cb_data, va_list ap)
2101{
2102 const char *name;
2103 const struct addrinfo *pai;
2104 struct addrinfo sentinel, *cur;
2105 struct addrinfo *p;
2106 FILE *hostf = NULL;
2107
2108 name = va_arg(ap, char *);
2109 pai = va_arg(ap, struct addrinfo *);
2110
2111// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
2112 memset(&sentinel, 0, sizeof(sentinel));
2113 cur = &sentinel;
2114
2115 _sethtent(&hostf);
2116 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
2117 cur->ai_next = p;
2118 while (cur && cur->ai_next)
2119 cur = cur->ai_next;
2120 }
2121 _endhtent(&hostf);
2122
2123 *((struct addrinfo **)rv) = sentinel.ai_next;
2124 if (sentinel.ai_next == NULL)
2125 return NS_NOTFOUND;
2126 return NS_SUCCESS;
2127}
2128
2129/* resolver logic */
2130
2131/*
2132 * Formulate a normal query, send, and await answer.
2133 * Returned answer is placed in supplied buffer "answer".
2134 * Perform preliminary check of answer, returning success only
2135 * if no error is indicated and the answer count is nonzero.
2136 * Return the size of the response on success, -1 on error.
2137 * Error number is left in h_errno.
2138 *
2139 * Caller must parse answer and determine whether it answers the question.
2140 */
2141static int
2142res_queryN(const char *name, /* domain name */ struct res_target *target,
2143 res_state res)
2144{
2145 u_char buf[MAXPACKET];
2146 HEADER *hp;
2147 int n;
2148 struct res_target *t;
2149 int rcode;
2150 int ancount;
2151
2152 assert(name != NULL);
2153 /* XXX: target may be NULL??? */
2154
2155 rcode = NOERROR;
2156 ancount = 0;
2157
2158 for (t = target; t; t = t->next) {
2159 int class, type;
2160 u_char *answer;
2161 int anslen;
2162
2163 hp = (HEADER *)(void *)t->answer;
2164 hp->rcode = NOERROR; /* default */
2165
2166 /* make it easier... */
2167 class = t->qclass;
2168 type = t->qtype;
2169 answer = t->answer;
2170 anslen = t->anslen;
2171#ifdef DEBUG
2172 if (res->options & RES_DEBUG)
2173 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
2174#endif
2175
2176 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
2177 buf, sizeof(buf));
2178#ifdef RES_USE_EDNS0
2179 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
2180 n = res_nopt(res, n, buf, sizeof(buf), anslen);
2181#endif
2182 if (n <= 0) {
2183#ifdef DEBUG
2184 if (res->options & RES_DEBUG)
2185 printf(";; res_nquery: mkquery failed\n");
2186#endif
2187 h_errno = NO_RECOVERY;
2188 return n;
2189 }
2190 n = res_nsend(res, buf, n, answer, anslen);
2191#if 0
2192 if (n < 0) {
2193#ifdef DEBUG
2194 if (res->options & RES_DEBUG)
2195 printf(";; res_query: send error\n");
2196#endif
2197 h_errno = TRY_AGAIN;
2198 return n;
2199 }
2200#endif
2201
2202 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
2203 rcode = hp->rcode; /* record most recent error */
2204#ifdef DEBUG
2205 if (res->options & RES_DEBUG)
2206 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
2207 ntohs(hp->ancount));
2208#endif
2209 continue;
2210 }
2211
2212 ancount += ntohs(hp->ancount);
2213
2214 t->n = n;
2215 }
2216
2217 if (ancount == 0) {
2218 switch (rcode) {
2219 case NXDOMAIN:
2220 h_errno = HOST_NOT_FOUND;
2221 break;
2222 case SERVFAIL:
2223 h_errno = TRY_AGAIN;
2224 break;
2225 case NOERROR:
2226 h_errno = NO_DATA;
2227 break;
2228 case FORMERR:
2229 case NOTIMP:
2230 case REFUSED:
2231 default:
2232 h_errno = NO_RECOVERY;
2233 break;
2234 }
2235 return -1;
2236 }
2237 return ancount;
2238}
2239
2240/*
2241 * Formulate a normal query, send, and retrieve answer in supplied buffer.
2242 * Return the size of the response on success, -1 on error.
2243 * If enabled, implement search rules until answer or unrecoverable failure
2244 * is detected. Error code, if any, is left in h_errno.
2245 */
2246static int
2247res_searchN(const char *name, struct res_target *target, res_state res)
2248{
2249 const char *cp, * const *domain;
2250 HEADER *hp;
2251 u_int dots;
2252 int trailing_dot, ret, saved_herrno;
2253 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
2254
2255 assert(name != NULL);
2256 assert(target != NULL);
2257
2258 hp = (HEADER *)(void *)target->answer; /*XXX*/
2259
2260 errno = 0;
2261 h_errno = HOST_NOT_FOUND; /* default, if we never query */
2262 dots = 0;
2263 for (cp = name; *cp; cp++)
2264 dots += (*cp == '.');
2265 trailing_dot = 0;
2266 if (cp > name && *--cp == '.')
2267 trailing_dot++;
2268
2269
David 'Digit' Turner5e563702009-05-05 15:50:24 +02002270 //fprintf(stderr, "res_searchN() name = '%s'\n", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002271
2272 /*
2273 * if there aren't any dots, it could be a user-level alias
2274 */
2275 if (!dots && (cp = __hostalias(name)) != NULL) {
2276 ret = res_queryN(cp, target, res);
2277 return ret;
2278 }
2279
2280 /*
2281 * If there are dots in the name already, let's just give it a try
2282 * 'as is'. The threshold can be set with the "ndots" option.
2283 */
2284 saved_herrno = -1;
2285 if (dots >= res->ndots) {
2286 ret = res_querydomainN(name, NULL, target, res);
2287 if (ret > 0)
2288 return (ret);
2289 saved_herrno = h_errno;
2290 tried_as_is++;
2291 }
2292
2293 /*
2294 * We do at least one level of search if
2295 * - there is no dot and RES_DEFNAME is set, or
2296 * - there is at least one dot, there is no trailing dot,
2297 * and RES_DNSRCH is set.
2298 */
2299 if ((!dots && (res->options & RES_DEFNAMES)) ||
2300 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
2301 int done = 0;
2302
Robert Greenwalte0805a92013-07-31 16:53:46 -07002303 /* Unfortunately we need to set stuff up before
2304 * the domain stuff is tried. Will have a better
2305 * fix after thread pools are used.
2306 */
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05002307 _resolv_populate_res_for_net(res);
Robert Greenwalte0805a92013-07-31 16:53:46 -07002308
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002309 for (domain = (const char * const *)res->dnsrch;
2310 *domain && !done;
2311 domain++) {
2312
2313 ret = res_querydomainN(name, *domain, target, res);
2314 if (ret > 0)
2315 return ret;
2316
2317 /*
2318 * If no server present, give up.
2319 * If name isn't found in this domain,
2320 * keep trying higher domains in the search list
2321 * (if that's enabled).
2322 * On a NO_DATA error, keep trying, otherwise
2323 * a wildcard entry of another type could keep us
2324 * from finding this entry higher in the domain.
2325 * If we get some other error (negative answer or
2326 * server failure), then stop searching up,
2327 * but try the input name below in case it's
2328 * fully-qualified.
2329 */
2330 if (errno == ECONNREFUSED) {
2331 h_errno = TRY_AGAIN;
2332 return -1;
2333 }
2334
2335 switch (h_errno) {
2336 case NO_DATA:
2337 got_nodata++;
2338 /* FALLTHROUGH */
2339 case HOST_NOT_FOUND:
2340 /* keep trying */
2341 break;
2342 case TRY_AGAIN:
2343 if (hp->rcode == SERVFAIL) {
2344 /* try next search element, if any */
2345 got_servfail++;
2346 break;
2347 }
2348 /* FALLTHROUGH */
2349 default:
2350 /* anything else implies that we're done */
2351 done++;
2352 }
2353 /*
2354 * if we got here for some reason other than DNSRCH,
2355 * we only wanted one iteration of the loop, so stop.
2356 */
2357 if (!(res->options & RES_DNSRCH))
Lorenzo Colittib82532d2011-09-28 19:28:32 -07002358 done++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002359 }
2360 }
2361
2362 /*
2363 * if we have not already tried the name "as is", do that now.
2364 * note that we do this regardless of how many dots were in the
2365 * name or whether it ends with a dot.
2366 */
2367 if (!tried_as_is) {
2368 ret = res_querydomainN(name, NULL, target, res);
2369 if (ret > 0)
2370 return ret;
2371 }
2372
2373 /*
2374 * if we got here, we didn't satisfy the search.
2375 * if we did an initial full query, return that query's h_errno
2376 * (note that we wouldn't be here if that query had succeeded).
2377 * else if we ever got a nodata, send that back as the reason.
2378 * else send back meaningless h_errno, that being the one from
2379 * the last DNSRCH we did.
2380 */
2381 if (saved_herrno != -1)
2382 h_errno = saved_herrno;
2383 else if (got_nodata)
2384 h_errno = NO_DATA;
2385 else if (got_servfail)
2386 h_errno = TRY_AGAIN;
2387 return -1;
2388}
2389
2390/*
2391 * Perform a call on res_query on the concatenation of name and domain,
2392 * removing a trailing dot from name if domain is NULL.
2393 */
2394static int
2395res_querydomainN(const char *name, const char *domain,
2396 struct res_target *target, res_state res)
2397{
2398 char nbuf[MAXDNAME];
2399 const char *longname = nbuf;
2400 size_t n, d;
2401
2402 assert(name != NULL);
2403 /* XXX: target may be NULL??? */
2404
2405#ifdef DEBUG
2406 if (res->options & RES_DEBUG)
2407 printf(";; res_querydomain(%s, %s)\n",
2408 name, domain?domain:"<Nil>");
2409#endif
2410 if (domain == NULL) {
2411 /*
2412 * Check for trailing '.';
2413 * copy without '.' if present.
2414 */
2415 n = strlen(name);
2416 if (n + 1 > sizeof(nbuf)) {
2417 h_errno = NO_RECOVERY;
2418 return -1;
2419 }
2420 if (n > 0 && name[--n] == '.') {
2421 strncpy(nbuf, name, n);
2422 nbuf[n] = '\0';
2423 } else
2424 longname = name;
2425 } else {
2426 n = strlen(name);
2427 d = strlen(domain);
2428 if (n + 1 + d + 1 > sizeof(nbuf)) {
2429 h_errno = NO_RECOVERY;
2430 return -1;
2431 }
2432 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2433 }
2434 return res_queryN(longname, target, res);
2435}