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