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