| 1 | #include <sys/socket.h> |
| 2 | #include <netinet/in.h> |
| 3 | #include <netdb.h> |
| 4 | #include <net/if.h> |
| 5 | #include <arpa/inet.h> |
| 6 | #include <ctype.h> |
| 7 | #include <stdlib.h> |
| 8 | #include <string.h> |
| 9 | #include <fcntl.h> |
| 10 | #include <unistd.h> |
| 11 | #include <pthread.h> |
| 12 | #include <errno.h> |
| 13 | #include <resolv.h> |
| 14 | #include "lookup.h" |
| 15 | #include "stdio_impl.h" |
| 16 | #include "syscall.h" |
| 17 | |
| 18 | static int is_valid_hostname(const char *host) |
| 19 | { |
| 20 | 	const unsigned char *s; |
| 21 | 	if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; |
| 22 | 	for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); |
| 23 | 	return !*s; |
| 24 | } |
| 25 | |
| 26 | static int name_from_null(struct address buf[static 2], const char *name, int family, int flags) |
| 27 | { |
| 28 | 	int cnt = 0; |
| 29 | 	if (name) return 0; |
| 30 | 	if (flags & AI_PASSIVE) { |
| 31 | 		if (family != AF_INET6) |
| 32 | 			buf[cnt++] = (struct address){ .family = AF_INET }; |
| 33 | 		if (family != AF_INET) |
| 34 | 			buf[cnt++] = (struct address){ .family = AF_INET6 }; |
| 35 | 	} else { |
| 36 | 		if (family != AF_INET6) |
| 37 | 			buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } }; |
| 38 | 		if (family != AF_INET) |
| 39 | 			buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; |
| 40 | 	} |
| 41 | 	return cnt; |
| 42 | } |
| 43 | |
| 44 | static int name_from_numeric(struct address buf[static 1], const char *name, int family) |
| 45 | { |
| 46 | 	return __lookup_ipliteral(buf, name, family); |
| 47 | } |
| 48 | |
| 49 | static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) |
| 50 | { |
| 51 | 	char line[512]; |
| 52 | 	size_t l = strlen(name); |
| 53 | 	int cnt = 0, badfam = 0, have_canon = 0; |
| 54 | 	unsigned char _buf[1032]; |
| 55 | 	FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); |
| 56 | 	if (!f) switch (errno) { |
| 57 | 	case ENOENT: |
| 58 | 	case ENOTDIR: |
| 59 | 	case EACCES: |
| 60 | 		return 0; |
| 61 | 	default: |
| 62 | 		return EAI_SYSTEM; |
| 63 | 	} |
| 64 | 	while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { |
| 65 | 		char *p, *z; |
| 66 | |
| 67 | 		if ((p=strchr(line, '#'))) *p++='\n', *p=0; |
| 68 | 		for(p=line+1; (p=strstr(p, name)) && |
| 69 | 			(!isspace(p[-1]) || !isspace(p[l])); p++); |
| 70 | 		if (!p) continue; |
| 71 | |
| 72 | 		/* Isolate IP address to parse */ |
| 73 | 		for (p=line; *p && !isspace(*p); p++); |
| 74 | 		*p++ = 0; |
| 75 | 		switch (name_from_numeric(buf+cnt, line, family)) { |
| 76 | 		case 1: |
| 77 | 			cnt++; |
| 78 | 			break; |
| 79 | 		case 0: |
| 80 | 			continue; |
| 81 | 		default: |
| 82 | 			badfam = EAI_NODATA; |
| 83 | 			break; |
| 84 | 		} |
| 85 | |
| 86 | 		if (have_canon) continue; |
| 87 | |
| 88 | 		/* Extract first name as canonical name */ |
| 89 | 		for (; *p && isspace(*p); p++); |
| 90 | 		for (z=p; *z && !isspace(*z); z++); |
| 91 | 		*z = 0; |
| 92 | 		if (is_valid_hostname(p)) { |
| 93 | 			have_canon = 1; |
| 94 | 			memcpy(canon, p, z-p+1); |
| 95 | 		} |
| 96 | 	} |
| 97 | 	__fclose_ca(f); |
| 98 | 	return cnt ? cnt : badfam; |
| 99 | } |
| 100 | |
| 101 | struct dpc_ctx { |
| 102 | 	struct address *addrs; |
| 103 | 	char *canon; |
| 104 | 	int cnt; |
| 105 | 	int rrtype; |
| 106 | }; |
| 107 | |
| 108 | #define RR_A 1 |
| 109 | #define RR_CNAME 5 |
| 110 | #define RR_AAAA 28 |
| 111 | |
| 112 | #define ABUF_SIZE 4800 |
| 113 | |
| 114 | static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen) |
| 115 | { |
| 116 | 	char tmp[256]; |
| 117 | 	int family; |
| 118 | 	struct dpc_ctx *ctx = c; |
| 119 | 	if (rr == RR_CNAME) { |
| 120 | 		if (__dn_expand(packet, (const unsigned char *)packet + plen, |
| 121 | 		 data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) |
| 122 | 			strcpy(ctx->canon, tmp); |
| 123 | 		return 0; |
| 124 | 	} |
| 125 | 	if (ctx->cnt >= MAXADDRS) return 0; |
| 126 | 	if (rr != ctx->rrtype) return 0; |
| 127 | 	switch (rr) { |
| 128 | 	case RR_A: |
| 129 | 		if (len != 4) return -1; |
| 130 | 		family = AF_INET; |
| 131 | 		break; |
| 132 | 	case RR_AAAA: |
| 133 | 		if (len != 16) return -1; |
| 134 | 		family = AF_INET6; |
| 135 | 		break; |
| 136 | 	} |
| 137 | 	ctx->addrs[ctx->cnt].family = family; |
| 138 | 	ctx->addrs[ctx->cnt].scopeid = 0; |
| 139 | 	memcpy(ctx->addrs[ctx->cnt++].addr, data, len); |
| 140 | 	return 0; |
| 141 | } |
| 142 | |
| 143 | static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf) |
| 144 | { |
| 145 | 	unsigned char qbuf[2][280], abuf[2][ABUF_SIZE]; |
| 146 | 	const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; |
| 147 | 	unsigned char *ap[2] = { abuf[0], abuf[1] }; |
| 148 | 	int qlens[2], alens[2], qtypes[2]; |
| 149 | 	int i, nq = 0; |
| 150 | 	struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; |
| 151 | 	static const struct { int af; int rr; } afrr[2] = { |
| 152 | 		{ .af = AF_INET6, .rr = RR_A }, |
| 153 | 		{ .af = AF_INET, .rr = RR_AAAA }, |
| 154 | 	}; |
| 155 | |
| 156 | 	for (i=0; i<2; i++) { |
| 157 | 		if (family != afrr[i].af) { |
| 158 | 			qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr, |
| 159 | 				0, 0, 0, qbuf[nq], sizeof *qbuf); |
| 160 | 			if (qlens[nq] == -1) |
| 161 | 				return 0; |
| 162 | 			qtypes[nq] = afrr[i].rr; |
| 163 | 			qbuf[nq][3] = 0; /* don't need AD flag */ |
| 164 | 			/* Ensure query IDs are distinct. */ |
| 165 | 			if (nq && qbuf[nq][0] == qbuf[0][0]) |
| 166 | 				qbuf[nq][0]++; |
| 167 | 			nq++; |
| 168 | 		} |
| 169 | 	} |
| 170 | |
| 171 | 	if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) |
| 172 | 		return EAI_SYSTEM; |
| 173 | |
| 174 | 	for (i=0; i<nq; i++) { |
| 175 | 		if (alens[i] < 4 || (abuf[i][3] & 15) == 2) return EAI_AGAIN; |
| 176 | 		if ((abuf[i][3] & 15) == 3) return 0; |
| 177 | 		if ((abuf[i][3] & 15) != 0) return EAI_FAIL; |
| 178 | 	} |
| 179 | |
| 180 | 	for (i=nq-1; i>=0; i--) { |
| 181 | 		ctx.rrtype = qtypes[i]; |
| 182 | 		if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i]; |
| 183 | 		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); |
| 184 | 	} |
| 185 | |
| 186 | 	if (ctx.cnt) return ctx.cnt; |
| 187 | 	return EAI_NODATA; |
| 188 | } |
| 189 | |
| 190 | static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) |
| 191 | { |
| 192 | 	char search[256]; |
| 193 | 	struct resolvconf conf; |
| 194 | 	size_t l, dots; |
| 195 | 	char *p, *z; |
| 196 | |
| 197 | 	if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; |
| 198 | |
| 199 | 	/* Count dots, suppress search when >=ndots or name ends in |
| 200 | 	 * a dot, which is an explicit request for global scope. */ |
| 201 | 	for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; |
| 202 | 	if (dots >= conf.ndots || name[l-1]=='.') *search = 0; |
| 203 | |
| 204 | 	/* Strip final dot for canon, fail if multiple trailing dots. */ |
| 205 | 	if (name[l-1]=='.') l--; |
| 206 | 	if (!l || name[l-1]=='.') return EAI_NONAME; |
| 207 | |
| 208 | 	/* This can never happen; the caller already checked length. */ |
| 209 | 	if (l >= 256) return EAI_NONAME; |
| 210 | |
| 211 | 	/* Name with search domain appended is setup in canon[]. This both |
| 212 | 	 * provides the desired default canonical name (if the requested |
| 213 | 	 * name is not a CNAME record) and serves as a buffer for passing |
| 214 | 	 * the full requested name to name_from_dns. */ |
| 215 | 	memcpy(canon, name, l); |
| 216 | 	canon[l] = '.'; |
| 217 | |
| 218 | 	for (p=search; *p; p=z) { |
| 219 | 		for (; isspace(*p); p++); |
| 220 | 		for (z=p; *z && !isspace(*z); z++); |
| 221 | 		if (z==p) break; |
| 222 | 		if (z-p < 256 - l - 1) { |
| 223 | 			memcpy(canon+l+1, p, z-p); |
| 224 | 			canon[z-p+1+l] = 0; |
| 225 | 			int cnt = name_from_dns(buf, canon, canon, family, &conf); |
| 226 | 			if (cnt) return cnt; |
| 227 | 		} |
| 228 | 	} |
| 229 | |
| 230 | 	canon[l] = 0; |
| 231 | 	return name_from_dns(buf, canon, name, family, &conf); |
| 232 | } |
| 233 | |
| 234 | static const struct policy { |
| 235 | 	unsigned char addr[16]; |
| 236 | 	unsigned char len, mask; |
| 237 | 	unsigned char prec, label; |
| 238 | } defpolicy[] = { |
| 239 | 	{ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, |
| 240 | 	{ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, |
| 241 | 	{ "\x20\2", 1, 0xff, 30, 2 }, |
| 242 | 	{ "\x20\1", 3, 0xff, 5, 5 }, |
| 243 | 	{ "\xfc", 0, 0xfe, 3, 13 }, |
| 244 | #if 0 |
| 245 | 	/* These are deprecated and/or returned to the address |
| 246 | 	 * pool, so despite the RFC, treating them as special |
| 247 | 	 * is probably wrong. */ |
| 248 | 	{ "", 11, 0xff, 1, 3 }, |
| 249 | 	{ "\xfe\xc0", 1, 0xc0, 1, 11 }, |
| 250 | 	{ "\x3f\xfe", 1, 0xff, 1, 12 }, |
| 251 | #endif |
| 252 | 	/* Last rule must match all addresses to stop loop. */ |
| 253 | 	{ "", 0, 0, 40, 1 }, |
| 254 | }; |
| 255 | |
| 256 | static const struct policy *policyof(const struct in6_addr *a) |
| 257 | { |
| 258 | 	int i; |
| 259 | 	for (i=0; ; i++) { |
| 260 | 		if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) |
| 261 | 			continue; |
| 262 | 		if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) |
| 263 | 		 != defpolicy[i].addr[defpolicy[i].len]) |
| 264 | 			continue; |
| 265 | 		return defpolicy+i; |
| 266 | 	} |
| 267 | } |
| 268 | |
| 269 | static int labelof(const struct in6_addr *a) |
| 270 | { |
| 271 | 	return policyof(a)->label; |
| 272 | } |
| 273 | |
| 274 | static int scopeof(const struct in6_addr *a) |
| 275 | { |
| 276 | 	if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; |
| 277 | 	if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; |
| 278 | 	if (IN6_IS_ADDR_LOOPBACK(a)) return 2; |
| 279 | 	if (IN6_IS_ADDR_SITELOCAL(a)) return 5; |
| 280 | 	return 14; |
| 281 | } |
| 282 | |
| 283 | static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d) |
| 284 | { |
| 285 | 	/* FIXME: The common prefix length should be limited to no greater |
| 286 | 	 * than the nominal length of the prefix portion of the source |
| 287 | 	 * address. However the definition of the source prefix length is |
| 288 | 	 * not clear and thus this limiting is not yet implemented. */ |
| 289 | 	unsigned i; |
| 290 | 	for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++); |
| 291 | 	return i; |
| 292 | } |
| 293 | |
| 294 | #define DAS_USABLE 0x40000000 |
| 295 | #define DAS_MATCHINGSCOPE 0x20000000 |
| 296 | #define DAS_MATCHINGLABEL 0x10000000 |
| 297 | #define DAS_PREC_SHIFT 20 |
| 298 | #define DAS_SCOPE_SHIFT 16 |
| 299 | #define DAS_PREFIX_SHIFT 8 |
| 300 | #define DAS_ORDER_SHIFT 0 |
| 301 | |
| 302 | static int addrcmp(const void *_a, const void *_b) |
| 303 | { |
| 304 | 	const struct address *a = _a, *b = _b; |
| 305 | 	return b->sortkey - a->sortkey; |
| 306 | } |
| 307 | |
| 308 | int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags) |
| 309 | { |
| 310 | 	int cnt = 0, i, j; |
| 311 | |
| 312 | 	*canon = 0; |
| 313 | 	if (name) { |
| 314 | 		/* reject empty name and check len so it fits into temp bufs */ |
| 315 | 		size_t l = strnlen(name, 255); |
| 316 | 		if (l-1 >= 254) |
| 317 | 			return EAI_NONAME; |
| 318 | 		memcpy(canon, name, l+1); |
| 319 | 	} |
| 320 | |
| 321 | 	/* Procedurally, a request for v6 addresses with the v4-mapped |
| 322 | 	 * flag set is like a request for unspecified family, followed |
| 323 | 	 * by filtering of the results. */ |
| 324 | 	if (flags & AI_V4MAPPED) { |
| 325 | 		if (family == AF_INET6) family = AF_UNSPEC; |
| 326 | 		else flags -= AI_V4MAPPED; |
| 327 | 	} |
| 328 | |
| 329 | 	/* Try each backend until there's at least one result. */ |
| 330 | 	cnt = name_from_null(buf, name, family, flags); |
| 331 | 	if (!cnt) cnt = name_from_numeric(buf, name, family); |
| 332 | 	if (!cnt && !(flags & AI_NUMERICHOST)) { |
| 333 | 		cnt = name_from_hosts(buf, canon, name, family); |
| 334 | 		if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); |
| 335 | 	} |
| 336 | 	if (cnt<=0) return cnt ? cnt : EAI_NONAME; |
| 337 | |
| 338 | 	/* Filter/transform results for v4-mapped lookup, if requested. */ |
| 339 | 	if (flags & AI_V4MAPPED) { |
| 340 | 		if (!(flags & AI_ALL)) { |
| 341 | 			/* If any v6 results exist, remove v4 results. */ |
| 342 | 			for (i=0; i<cnt && buf[i].family != AF_INET6; i++); |
| 343 | 			if (i<cnt) { |
| 344 | 				for (j=0; i<cnt; i++) { |
| 345 | 					if (buf[i].family == AF_INET6) |
| 346 | 						buf[j++] = buf[i]; |
| 347 | 				} |
| 348 | 				cnt = i = j; |
| 349 | 			} |
| 350 | 		} |
| 351 | 		/* Translate any remaining v4 results to v6 */ |
| 352 | 		for (i=0; i<cnt; i++) { |
| 353 | 			if (buf[i].family != AF_INET) continue; |
| 354 | 			memcpy(buf[i].addr+12, buf[i].addr, 4); |
| 355 | 			memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
| 356 | 			buf[i].family = AF_INET6; |
| 357 | 		} |
| 358 | 	} |
| 359 | |
| 360 | 	/* No further processing is needed if there are fewer than 2 |
| 361 | 	 * results or if there are only IPv4 results. */ |
| 362 | 	if (cnt<2 || family==AF_INET) return cnt; |
| 363 | 	for (i=0; i<cnt; i++) if (buf[i].family != AF_INET) break; |
| 364 | 	if (i==cnt) return cnt; |
| 365 | |
| 366 | 	int cs; |
| 367 | 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
| 368 | |
| 369 | 	/* The following implements a subset of RFC 3484/6724 destination |
| 370 | 	 * address selection by generating a single 31-bit sort key for |
| 371 | 	 * each address. Rules 3, 4, and 7 are omitted for having |
| 372 | 	 * excessive runtime and code size cost and dubious benefit. |
| 373 | 	 * So far the label/precedence table cannot be customized. */ |
| 374 | 	for (i=0; i<cnt; i++) { |
| 375 | 		int family = buf[i].family; |
| 376 | 		int key = 0; |
| 377 | 		struct sockaddr_in6 sa6 = { 0 }, da6 = { |
| 378 | 			.sin6_family = AF_INET6, |
| 379 | 			.sin6_scope_id = buf[i].scopeid, |
| 380 | 			.sin6_port = 65535 |
| 381 | 		}; |
| 382 | 		struct sockaddr_in sa4 = { 0 }, da4 = { |
| 383 | 			.sin_family = AF_INET, |
| 384 | 			.sin_port = 65535 |
| 385 | 		}; |
| 386 | 		void *sa, *da; |
| 387 | 		socklen_t salen, dalen; |
| 388 | 		if (family == AF_INET6) { |
| 389 | 			memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16); |
| 390 | 			da = &da6; dalen = sizeof da6; |
| 391 | 			sa = &sa6; salen = sizeof sa6; |
| 392 | 		} else { |
| 393 | 			memcpy(sa6.sin6_addr.s6_addr, |
| 394 | 				"\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
| 395 | 			memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); |
| 396 | 			memcpy(da6.sin6_addr.s6_addr, |
| 397 | 				"\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); |
| 398 | 			memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); |
| 399 | 			memcpy(&da4.sin_addr, buf[i].addr, 4); |
| 400 | 			da = &da4; dalen = sizeof da4; |
| 401 | 			sa = &sa4; salen = sizeof sa4; |
| 402 | 		} |
| 403 | 		const struct policy *dpolicy = policyof(&da6.sin6_addr); |
| 404 | 		int dscope = scopeof(&da6.sin6_addr); |
| 405 | 		int dlabel = dpolicy->label; |
| 406 | 		int dprec = dpolicy->prec; |
| 407 | 		int prefixlen = 0; |
| 408 | 		int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP); |
| 409 | 		if (fd >= 0) { |
| 410 | 			if (!connect(fd, da, dalen)) { |
| 411 | 				key |= DAS_USABLE; |
| 412 | 				if (!getsockname(fd, sa, &salen)) { |
| 413 | 					if (family == AF_INET) memcpy( |
| 414 | 						sa6.sin6_addr.s6_addr+12, |
| 415 | 						&sa4.sin_addr, 4); |
| 416 | 					if (dscope == scopeof(&sa6.sin6_addr)) |
| 417 | 						key |= DAS_MATCHINGSCOPE; |
| 418 | 					if (dlabel == labelof(&sa6.sin6_addr)) |
| 419 | 						key |= DAS_MATCHINGLABEL; |
| 420 | 					prefixlen = prefixmatch(&sa6.sin6_addr, |
| 421 | 						&da6.sin6_addr); |
| 422 | 				} |
| 423 | 			} |
| 424 | 			close(fd); |
| 425 | 		} |
| 426 | 		key |= dprec << DAS_PREC_SHIFT; |
| 427 | 		key |= (15-dscope) << DAS_SCOPE_SHIFT; |
| 428 | 		key |= prefixlen << DAS_PREFIX_SHIFT; |
| 429 | 		key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; |
| 430 | 		buf[i].sortkey = key; |
| 431 | 	} |
| 432 | 	qsort(buf, cnt, sizeof *buf, addrcmp); |
| 433 | |
| 434 | 	pthread_setcancelstate(cs, 0); |
| 435 | |
| 436 | 	return cnt; |
| 437 | } |