• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <dlfcn.h>
18 #define BREAK 0
19 #define CONTINUE 1
20 #if OHOS_PERMISSION_INTERNET
21 uint8_t is_allow_internet(void);
22 #endif
23 #define FIXED_HOSTS_MAX_LENGTH 2
24 #define FIXED_HOSTS_STR_MAX_LENGTH 23
25 
26 char fixed_hosts[][FIXED_HOSTS_STR_MAX_LENGTH] = {
27 	"127.0.0.1  localhost\r\n\0",
28 	"::1  ip6-localhost\r\n\0"
29 };
30 
is_valid_hostname(const char * host)31 static int is_valid_hostname(const char *host)
32 {
33 	const unsigned char *s;
34 	if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0;
35 	for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
36 	return !*s;
37 }
38 
name_from_null(struct address buf[static2],const char * name,int family,int flags)39 static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
40 {
41 	int cnt = 0;
42 	if (name) return 0;
43 	if (flags & AI_PASSIVE) {
44 		if (family != AF_INET6)
45 			buf[cnt++] = (struct address){ .family = AF_INET };
46 		if (family != AF_INET)
47 			buf[cnt++] = (struct address){ .family = AF_INET6 };
48 	} else {
49 		if (family != AF_INET6)
50 			buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
51 		if (family != AF_INET)
52 			buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
53 	}
54 	return cnt;
55 }
56 
name_from_numeric(struct address buf[static1],const char * name,int family)57 static int name_from_numeric(struct address buf[static 1], const char *name, int family)
58 {
59 	return __lookup_ipliteral(buf, name, family);
60 }
61 
get_hosts_str(char * line,int length,FILE * f,int * i)62 static inline int get_hosts_str(char *line, int length, FILE *f, int *i)
63 {
64 	if (f) {
65 		char *ret = fgets(line, length, f);
66 		if (ret) {
67 			size_t len = strlen(line);
68 			if (len > 0 && line[len - 1] != '\n' && len < length - 1) {
69 				line[len] = '\n';
70 				line[len + 1] = '\0';
71 			}
72 		}
73 		return ret;
74 	}
75 	if (*i < FIXED_HOSTS_MAX_LENGTH) {
76 		memcpy(line, fixed_hosts[*i], strlen(fixed_hosts[*i]));
77 		(*i)++;
78 		return 1;
79 	}
80 	return NULL;
81 }
82 
name_from_hosts(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family)83 static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
84 {
85 	char line[512];
86 	size_t l = strlen(name);
87 	int cnt = 0, badfam = 0, have_canon = 0;
88 	unsigned char _buf[1032];
89 	FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
90 	int i = 0;
91 	while (i < FIXED_HOSTS_MAX_LENGTH && get_hosts_str(line, sizeof line, f, &i) && cnt < MAXADDRS) {
92 		char *p, *z;
93 
94 		if ((p=strchr(line, '#'))) *p++='\n', *p=0;
95 		for(p=line+1; (p=strstr(p, name)) &&
96 			(!isspace(p[-1]) || !isspace(p[l])); p++);
97 		if (!p) continue;
98 
99 		/* Isolate IP address to parse */
100 		for (p=line; *p && !isspace(*p); p++);
101 		*p++ = 0;
102 		switch (name_from_numeric(buf+cnt, line, family)) {
103 		case 1:
104 			cnt++;
105 			break;
106 		case 0:
107 			continue;
108 		default:
109 			badfam = DNS_FAIL_REASON_PARAM_INVALID;
110 			break;
111 		}
112 
113 		if (have_canon) continue;
114 
115 		/* Extract first name as canonical name */
116 		for (; *p && isspace(*p); p++);
117 		for (z=p; *z && !isspace(*z); z++);
118 		*z = 0;
119 		if (is_valid_hostname(p)) {
120 			have_canon = 1;
121 			memcpy(canon, p, z-p+1);
122 		}
123 	}
124 	if (f) {
125 		__fclose_ca(f);
126 	}
127 	return cnt ? cnt : badfam;
128 }
129 
130 struct dpc_ctx {
131 	struct address *addrs;
132 	char *canon;
133 	int cnt;
134 	int rrtype;
135 };
136 
137 #define RR_A 1
138 #define RR_CNAME 5
139 #define RR_AAAA 28
140 #define MAX_QUERY_SIZE 5
141 #define VALID_ANSWER 1
142 #define MIN_ANSWER_TYPE 1
143 #define MAX_ANSWER_TYPE 2
144 #define MAX_NAME_LENGTH 256
145 #define ABUF_SIZE 4800
146 
dns_parse_callback(void * c,int rr,const void * data,int len,const void * packet,int plen)147 static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
148 {
149 	char tmp[256];
150 	int family;
151 	struct dpc_ctx *ctx = c;
152 	if (rr == RR_CNAME) {
153 		if (__dn_expand(packet, (const unsigned char *)packet + plen,
154 		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
155 			strcpy(ctx->canon, tmp);
156 		return 0;
157 	}
158 	if (ctx->cnt >= MAXADDRS) return 0;
159 	if (rr != ctx->rrtype) return 0;
160 	switch (rr) {
161 	case RR_A:
162 		if (len != 4) return -1;
163 		family = AF_INET;
164 		break;
165 	case RR_AAAA:
166 		if (len != 16) return -1;
167 		family = AF_INET6;
168 		break;
169 	}
170 	ctx->addrs[ctx->cnt].family = family;
171 	ctx->addrs[ctx->cnt].scopeid = 0;
172 	memcpy(ctx->addrs[ctx->cnt++].addr, data, len);
173 	return 0;
174 }
175 
176 #if OHOS_DNS_PROXY_BY_NETSYS
load_ipv6_judger(void)177 static JudgeIpv6 load_ipv6_judger(void)
178 {
179 	static JudgeIpv6 ipv6_judger = NULL;
180 	resolve_dns_sym((void **) &ipv6_judger, OHOS_JUDGE_IPV6_FUNC_NAME);
181 	return ipv6_judger;
182 }
183 #endif
184 
IsIpv6Enable(int netid)185 static int IsIpv6Enable(int netid)
186 {
187     int ret = 0;
188 #if OHOS_DNS_PROXY_BY_NETSYS
189     JudgeIpv6 func = load_ipv6_judger();
190 	if (!func) {
191 		return -1;
192 	}
193 
194 	ret = func(netid);
195 	if (ret < 0) {
196 		return -1;
197 	}
198 #endif
199     return ret;
200 }
201 
IsAnswerValid(const unsigned char * answer,int alen)202 static int IsAnswerValid(const unsigned char *answer, int alen)
203 {
204 	if (alen < 4 || (answer[3] & 15) == 2) {
205 		return EAI_AGAIN;
206 	}
207 	if ((answer[3] & 15) == 3) return 0;
208 	if ((answer[3] & 15) != 0) {
209 		return EAI_FAIL;
210 	}
211 	return VALID_ANSWER;
212 }
213 
name_from_dns(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family,const struct resolvconf * conf,int netid)214 static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf, int netid)
215 {
216 	unsigned char qbuf[2][280], abuf[2][ABUF_SIZE];
217 	const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
218 	unsigned char *ap[2] = { abuf[0], abuf[1] };
219 	int qlens[2], alens[2], qtypes[2];
220 	int queryNum = 2;
221 	int dns_errno = 0;
222 	struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
223 	static const struct { int af; int rr; } afrr_ipv6_enable[2] = {
224 		{ .af = AF_INET, .rr = RR_AAAA },
225 		{ .af = AF_INET6, .rr = RR_A },
226 	};
227 	static const struct { int af; int rr; } afrr_ipv4_only[1] = {
228 		{ .af = AF_INET6, .rr = RR_A },
229 	};
230 	struct {int af; int rr;} *afrr = afrr_ipv6_enable;
231 
232 	if (!IsIpv6Enable(netid) || (family == AF_INET)) {
233 		if (family == AF_INET6) {
234 #ifndef __LITEOS__
235 			MUSL_LOGE("%{public}s: %{public}d: Network scenario mismatch: %{public}d", __func__, __LINE__, EAI_SYSTEM);
236 #endif
237 			return DNS_FAIL_REASON_LACK_V6_SUPPORT;
238 		}
239 		queryNum = 1;
240 		afrr = afrr_ipv4_only;
241 	} else {
242 		queryNum = 2;
243 		afrr = afrr_ipv6_enable;
244 	}
245 
246 	int cname_count = 0;
247 	const char *queryName = name;
248 	int checkBuf[MAX_ANSWER_TYPE] = {VALID_ANSWER, VALID_ANSWER};
249 	while (strnlen(queryName, MAX_NAME_LENGTH) != 0 && cname_count < MAX_QUERY_SIZE) {
250 		int i, nq = 0;
251 		for (i = 0; i < queryNum; i++) {
252 			if (family != afrr[i].af) {
253 				qlens[nq] = __res_mkquery(0, queryName, 1, afrr[i].rr,
254 					0, 0, 0, qbuf[nq], sizeof *qbuf);
255 				if (qlens[nq] == -1) {
256 #ifndef __LITEOS__
257 					MUSL_LOGE("%{public}s: %{public}d: Illegal querys: %{public}d", __func__, __LINE__, EAI_NONAME);
258 #endif
259 					return 0;
260 				}
261 				qtypes[nq] = afrr[i].rr;
262 				qbuf[nq][3] = 0; /* don't need AD flag */
263 				/* Ensure query IDs are distinct. */
264 				if (nq && qbuf[nq][0] == qbuf[0][0])
265 					qbuf[nq][0]++;
266 				nq++;
267 			}
268 		}
269 
270 		int res = res_msend_rc_ext(netid, nq, qp, qlens, ap, alens, sizeof *abuf, conf, &dns_errno);
271 		if (res < 0) return res;
272 
273 		for (i=0; i<nq; i++) {
274 			checkBuf[i] = IsAnswerValid(abuf[i], alens[i]);
275 		}
276 		if (checkBuf[MIN_ANSWER_TYPE - 1] != VALID_ANSWER &&
277 		   (nq < MAX_ANSWER_TYPE || checkBuf[MAX_ANSWER_TYPE - 1] != VALID_ANSWER)) {
278 #ifndef __LITEOS__
279 			MUSL_LOGE("%{public}s: %{public}d: Illegal answers, errno id: %{public}d",
280 				__func__, __LINE__, checkBuf[MIN_ANSWER_TYPE - 1]);
281 #endif
282 			int ret = checkBuf[MIN_ANSWER_TYPE - 1];
283 			if (ret != EAI_AGAIN) {
284 				return ret;
285 			}
286             switch (dns_errno) {
287                 case 0:
288                     return DNS_FAIL_REASON_SERVER_NO_RESULT;
289                 case ENETUNREACH:
290                     return DNS_FAIL_REASON_ROUTE_CONFIG_ERR;
291                 case EPERM:
292                     return DNS_FAIL_REASON_FIREWALL_INTERCEPTION;
293                 case FALLBACK_TCP_QUERY:
294                     return DNS_FAIL_REASON_TCP_QUERY_FAILED;
295                 default:
296                     return DNS_FAIL_REASON_CORE_ERRNO_BASE - dns_errno;
297             }
298 		}
299 
300 		for (i=nq-1; i>=0; i--) {
301 			ctx.rrtype = qtypes[i];
302 			if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i];
303 			__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
304 		}
305 		if (ctx.cnt) return ctx.cnt;
306 		queryName = ctx.canon;
307 		cname_count++;
308 	}
309 #ifndef __LITEOS__
310 	MUSL_LOGE("%{public}s: %{public}d: failed to parse dns : %{public}d", __func__, __LINE__, cname_count);
311 #endif
312 	return DNS_FAIL_REASON_FAIL_TO_PARSE_DNS;
313 }
314 
name_from_dns_search(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family,int netid)315 static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int netid)
316 {
317 #if OHOS_PERMISSION_INTERNET
318 	if (is_allow_internet() == 0) {
319 		errno = EPERM;
320 #ifndef __LITEOS__
321 		MUSL_LOGE("%{public}s: %{public}d: internet is not allowed", __func__, __LINE__);
322 #endif
323 		return -1;
324 	}
325 #endif
326 
327 	char search[256];
328 	struct resolvconf conf;
329 	size_t l, dots;
330 	char *p, *z;
331 
332 	int res = get_resolv_conf_ext(&conf, search, sizeof search, netid);
333 	if (res < 0) {
334 		return DNS_FAIL_REASON_GET_RESOLV_CONF_FAILED;
335 	}
336 	/* Count dots, suppress search when >=ndots or name ends in
337 	 * a dot, which is an explicit request for global scope. */
338 	for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++;
339 	if (dots >= conf.ndots || name[l-1]=='.') *search = 0;
340 
341 	/* Strip final dot for canon, fail if multiple trailing dots. */
342 	if (name[l-1]=='.') l--;
343 	if (!l || name[l-1]=='.') {
344 #ifndef __LITEOS__
345 		MUSL_LOGE("%{public}s: %{public}d: fail when multiple trailing dots: %{public}d", __func__, __LINE__, EAI_NONAME);
346 #endif
347 		return DNS_FAIL_REASON_HOST_NAME_ILLEGAL;
348 	}
349 
350 	/* This can never happen; the caller already checked length. */
351 	if (l >= 256) return DNS_FAIL_REASON_HOST_NAME_ILLEGAL;
352 
353 	/* Name with search domain appended is setup in canon[]. This both
354 	 * provides the desired default canonical name (if the requested
355 	 * name is not a CNAME record) and serves as a buffer for passing
356 	 * the full requested name to name_from_dns. */
357 	memcpy(canon, name, l);
358 	canon[l] = '.';
359 
360 	for (p=search; *p; p=z) {
361 		for (; isspace(*p); p++);
362 		for (z=p; *z && !isspace(*z); z++);
363 		if (z==p) break;
364 		if (z-p < 256 - l - 1) {
365 			memcpy(canon+l+1, p, z-p);
366 			canon[z-p+1+l] = 0;
367 			int cnt = name_from_dns(buf, canon, canon, family, &conf, netid);
368 			if (cnt) return cnt;
369 		}
370 	}
371 
372 	canon[l] = 0;
373 	return name_from_dns(buf, canon, name, family, &conf, netid);
374 }
375 
376 static const struct policy {
377 	unsigned char addr[16];
378 	unsigned char len, mask;
379 	unsigned char prec, label;
380 } defpolicy[] = {
381 	{ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 },
382 	{ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 },
383 	{ "\x20\2", 1, 0xff, 30, 2 },
384 	{ "\x20\1", 3, 0xff, 5, 5 },
385 	{ "\xfc", 0, 0xfe, 3, 13 },
386 #if 0
387 	/* These are deprecated and/or returned to the address
388 	 * pool, so despite the RFC, treating them as special
389 	 * is probably wrong. */
390 	{ "", 11, 0xff, 1, 3 },
391 	{ "\xfe\xc0", 1, 0xc0, 1, 11 },
392 	{ "\x3f\xfe", 1, 0xff, 1, 12 },
393 #endif
394 	/* Last rule must match all addresses to stop loop. */
395 	{ "", 0, 0, 40, 1 },
396 };
397 
policyof(const struct in6_addr * a)398 static const struct policy *policyof(const struct in6_addr *a)
399 {
400 	int i;
401 	for (i=0; ; i++) {
402 		if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len))
403 			continue;
404 		if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask)
405 		    != defpolicy[i].addr[defpolicy[i].len])
406 			continue;
407 		return defpolicy+i;
408 	}
409 }
410 
labelof(const struct in6_addr * a)411 static int labelof(const struct in6_addr *a)
412 {
413 	return policyof(a)->label;
414 }
415 
scopeof(const struct in6_addr * a)416 static int scopeof(const struct in6_addr *a)
417 {
418 	if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15;
419 	if (IN6_IS_ADDR_LINKLOCAL(a)) return 2;
420 	if (IN6_IS_ADDR_LOOPBACK(a)) return 2;
421 	if (IN6_IS_ADDR_SITELOCAL(a)) return 5;
422 	return 14;
423 }
424 
prefixmatch(const struct in6_addr * s,const struct in6_addr * d)425 static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d)
426 {
427 	/* FIXME: The common prefix length should be limited to no greater
428 	 * than the nominal length of the prefix portion of the source
429 	 * address. However the definition of the source prefix length is
430 	 * not clear and thus this limiting is not yet implemented. */
431 	unsigned i;
432 	for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++);
433 	return i;
434 }
435 
436 #define DAS_USABLE              0x40000000
437 #define DAS_MATCHINGSCOPE       0x20000000
438 #define DAS_MATCHINGLABEL       0x10000000
439 #define DAS_PREC_SHIFT          20
440 #define DAS_SCOPE_SHIFT         16
441 #define DAS_PREFIX_SHIFT        8
442 #define DAS_ORDER_SHIFT         0
443 
addrcmp(const void * _a,const void * _b)444 static int addrcmp(const void *_a, const void *_b)
445 {
446 	const struct address *a = _a, *b = _b;
447 	return b->sortkey - a->sortkey;
448 }
449 
lookup_name_ext(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family,int flags,int netid)450 int lookup_name_ext(struct address buf[static MAXADDRS], char canon[static 256], const char *name,
451 					int family, int flags, int netid)
452 {
453 	int cnt = 0, i, j;
454 
455 #if OHOS_DNS_PROXY_BY_NETSYS
456 	DNS_CONFIG_PRINT("lookup_name_ext \n");
457 #endif
458 
459 	*canon = 0;
460 	if (name) {
461 		/* reject empty name and check len so it fits into temp bufs */
462 		size_t l = strnlen(name, 255);
463 		if (l-1 >= 254) {
464 #ifndef __LITEOS__
465 			MUSL_LOGE("%{public}s: %{public}d: Illegal name length: %{public}zu", __func__, __LINE__, l);
466 #endif
467 			return DNS_FAIL_REASON_HOST_NAME_ILLEGAL;
468 		}
469 		memcpy(canon, name, l+1);
470 	}
471 
472 	/* Procedurally, a request for v6 addresses with the v4-mapped
473 	 * flag set is like a request for unspecified family, followed
474 	 * by filtering of the results. */
475 	if (flags & AI_V4MAPPED) {
476 		if (family == AF_INET6) family = AF_UNSPEC;
477 		else flags -= AI_V4MAPPED;
478 	}
479 
480 	/* Try each backend until there's at least one result. */
481 	cnt = name_from_null(buf, name, family, flags);
482 	if (!cnt) cnt = name_from_numeric(buf, name, family);
483 #ifndef __LITEOS__
484 	if (!cnt && (flags & AI_NUMERICHOST)) {
485 		cnt = DNS_FAIL_REASON_PARAM_INVALID;
486 		MUSL_LOGE("%{public}s: %{public}d: flag is AI_NUMERICHOST but host is Illegal", __func__, __LINE__);
487 	}
488 #endif
489 	if (cnt < 0) {
490 		cnt = DNS_FAIL_REASON_PARAM_INVALID;
491 	}
492 	if (!cnt && !(flags & AI_NUMERICHOST)) {
493 		cnt = predefined_host_name_from_hosts(buf, canon, name, family);
494 		if (!cnt) cnt = name_from_hosts(buf, canon, name, family);
495 		if (!cnt) cnt = name_from_dns_search(buf, canon, name, family, netid);
496 	}
497 	if (cnt<=0) return cnt ? cnt : DNS_FAIL_REASON_SERVER_NO_SUCH_NAME;
498 
499 	/* Filter/transform results for v4-mapped lookup, if requested. */
500 	if (flags & AI_V4MAPPED) {
501 		if (!(flags & AI_ALL)) {
502 			/* If any v6 results exist, remove v4 results. */
503 			for (i=0; i<cnt && buf[i].family != AF_INET6; i++);
504 			if (i<cnt) {
505 				for (j=0; i<cnt; i++) {
506 					if (buf[i].family == AF_INET6)
507 						buf[j++] = buf[i];
508 				}
509 				cnt = i = j;
510 			}
511 		}
512 		/* Translate any remaining v4 results to v6 */
513 		for (i=0; i<cnt; i++) {
514 			if (buf[i].family != AF_INET) continue;
515 			memcpy(buf[i].addr+12, buf[i].addr, 4);
516 			memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
517 			buf[i].family = AF_INET6;
518 		}
519 	}
520 
521 	/* No further processing is needed if there are fewer than 2
522 	 * results or if there are only IPv4 results. */
523 	if (cnt<2 || family==AF_INET) return cnt;
524 	for (i=0; i<cnt; i++) if (buf[i].family != AF_INET) break;
525 	if (i==cnt) return cnt;
526 
527 	int cs;
528 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
529 
530 	/* The following implements a subset of RFC 3484/6724 destination
531 	 * address selection by generating a single 31-bit sort key for
532 	 * each address. Rules 3, 4, and 7 are omitted for having
533 	 * excessive runtime and code size cost and dubious benefit.
534 	 * So far the label/precedence table cannot be customized. */
535 	for (i=0; i<cnt; i++) {
536 		int family = buf[i].family;
537 		int key = 0;
538 		struct sockaddr_in6 sa6 = { 0 }, da6 = {
539 			.sin6_family = AF_INET6,
540 			.sin6_scope_id = buf[i].scopeid,
541 			.sin6_port = 65535
542 		};
543 		struct sockaddr_in sa4 = { 0 }, da4 = {
544 			.sin_family = AF_INET,
545 			.sin_port = 65535
546 		};
547 		void *sa, *da;
548 		socklen_t salen, dalen;
549 		if (family == AF_INET6) {
550 			memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16);
551 			da = &da6; dalen = sizeof da6;
552 			sa = &sa6; salen = sizeof sa6;
553 		} else {
554 			memcpy(sa6.sin6_addr.s6_addr,
555 				"\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
556 			memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
557 			memcpy(da6.sin6_addr.s6_addr,
558 				"\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
559 			memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
560 			memcpy(&da4.sin_addr, buf[i].addr, 4);
561 			da = &da4; dalen = sizeof da4;
562 			sa = &sa4; salen = sizeof sa4;
563 		}
564 		const struct policy *dpolicy = policyof(&da6.sin6_addr);
565 		int dscope = scopeof(&da6.sin6_addr);
566 		int dlabel = dpolicy->label;
567 		int dprec = dpolicy->prec;
568 		int prefixlen = 0;
569 		int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP);
570 		if (fd >= 0) {
571 			if (!connect(fd, da, dalen)) {
572 				key |= DAS_USABLE;
573 				if (!getsockname(fd, sa, &salen)) {
574 					if (family == AF_INET) memcpy(
575 						sa6.sin6_addr.s6_addr+12,
576 						&sa4.sin_addr, 4);
577 					if (dscope == scopeof(&sa6.sin6_addr))
578 						key |= DAS_MATCHINGSCOPE;
579 					if (dlabel == labelof(&sa6.sin6_addr))
580 						key |= DAS_MATCHINGLABEL;
581 					prefixlen = prefixmatch(&sa6.sin6_addr,
582 						&da6.sin6_addr);
583 				}
584 			}
585 			close(fd);
586 		}
587 		key |= dprec << DAS_PREC_SHIFT;
588 		key |= (15-dscope) << DAS_SCOPE_SHIFT;
589 		key |= prefixlen << DAS_PREFIX_SHIFT;
590 		key |= (MAXADDRS-i) << DAS_ORDER_SHIFT;
591 		buf[i].sortkey = key;
592 	}
593 	qsort(buf, cnt, sizeof *buf, addrcmp);
594 
595 	pthread_setcancelstate(cs, 0);
596 
597 	return cnt;
598 }
599 
__lookup_name(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family,int flags)600 int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags)
601 {
602 	return lookup_name_ext(buf, canon, name, family, flags, 0);
603 }
604 
605 typedef struct _linknode {
606     struct _linknode *_next;
607     void *_data;
608 }linknode;
609 
610 typedef struct _linkList {
611     linknode *_phead;
612     int _count;
613 }linkList;
614 
615 static linkList *create_linklist(void);
616 static int destory_linklist(linkList *plist);
617 static int linklist_size(linkList *plist);
618 static linknode *get_linknode(linkList *plist, int index);
619 static int linklist_append_last(linkList *plist, void *pdata);
620 static int linklist_delete(linkList *plist, int index);
621 static int linklist_delete_first(linkList *plist);
622 static int linklist_delete_last(linkList *plist);
623 
624 typedef struct {
625 	char*    host;
626 	char*    ip;
627 }host_ip_pair;
628 
629 static const char GROUP_SEPARATOR[] = "|";
630 static const char SEPARATOR[]       = ",";
631 
632 static linkList   *host_ips_list_ = NULL;
633 
strsep(char ** s,const char * ct)634 static char *strsep(char **s, const char *ct)
635 {
636 	char *sbegin = *s;
637 	char *end;
638 	if (sbegin == NULL) {
639 		return NULL;
640 	}
641 	end = strpbrk(sbegin, ct);
642 	if (end) {
643 		*end++ = '\0';
644 	}
645 	*s = end;
646 	return sbegin;
647 }
648 
predefined_host_clear_all_hosts(void)649 int predefined_host_clear_all_hosts(void)
650 {
651 	if (host_ips_list_ != NULL) {
652 		linknode *pnode = host_ips_list_->_phead;
653 		while (pnode != NULL) {
654 			free(pnode->_data);
655 			pnode->_data = NULL;
656 			pnode = pnode->_next;
657 		}
658 
659 		destory_linklist(host_ips_list_);
660 		free(host_ips_list_);
661 		host_ips_list_ = NULL;
662 		return 0;
663 	}
664 	return -1;
665 }
666 
predefined_host_remove_host(const char * host)667 int predefined_host_remove_host(const char *host)
668 {
669 	int remove_cnt = 0;
670 	if (host_ips_list_ != NULL) {
671 		linknode     *pnode = NULL;
672 		host_ip_pair *pinfo = NULL;
673 		int cnt = linklist_size(host_ips_list_);
674 
675 		for (int i = cnt - 1; i >= 0; i--) {
676 			pnode = get_linknode(host_ips_list_, i);
677 			if (pnode != NULL) {
678 				pinfo = (host_ip_pair*)pnode->_data;
679 				if (strcmp(pinfo->host, host) == 0) {
680 					free(pinfo);
681 					linklist_delete(host_ips_list_, i);
682 					remove_cnt++;
683 				}
684 			}
685 		}
686 	}
687 
688 	return remove_cnt == 0 ? -1 : 0;
689 }
690 
_predefined_host_is_contain_host_ip(const char * host,const char * ip,int is_check_ip)691 static int _predefined_host_is_contain_host_ip(const char* host, const char* ip, int is_check_ip)
692 {
693 	if (host_ips_list_ != NULL) {
694 		linknode *pnode = host_ips_list_->_phead;
695 
696 		while (pnode != NULL) {
697 			host_ip_pair *pinfo = (host_ip_pair*)pnode->_data;
698 			if (strcmp(pinfo->host, host) == 0) {
699 				if (is_check_ip) {
700 					if (strcmp(pinfo->ip, ip) == 0) {
701 						return 1;
702 					}
703 				} else {
704 					return 1;
705 				}
706 			}
707 			pnode = pnode->_next;
708 		}
709 	}
710 	return 0;
711 }
712 
predefined_host_is_contain_host(const char * host)713 int predefined_host_is_contain_host(const char *host)
714 {
715 	return _predefined_host_is_contain_host_ip(host, NULL, 0);
716 }
717 
_predefined_host_add_record(char * host,char * ip)718 static int _predefined_host_add_record(char* host, char* ip)
719 {
720 	int head_len        = sizeof(host_ip_pair);
721 	int host_len        = strlen(host);
722 	int ip_len          = strlen(ip);
723 	int total           = host_len + 1 + ip_len + 1 + head_len;
724 	char *pdata         = calloc(1, total);
725 	host_ip_pair *pinfo = (host_ip_pair*)pdata;
726 
727 	if (pdata == NULL) {
728 		return EAI_NONAME;
729 	}
730 
731 	char*  i_host = (char*)(pdata + head_len);
732 	char*  i_ip   = (char*)(pdata + head_len + host_len + 1);
733 
734 	memcpy(i_host, host, host_len + 1);
735 	memcpy(i_ip, ip, ip_len + 1);
736 
737 	pinfo->host = i_host;
738 	pinfo->ip   = i_ip;
739 
740 	linklist_append_last(host_ips_list_, pdata);
741 	return 0;
742 }
743 
_predefined_host_parse_host_ips(char * params)744 static int _predefined_host_parse_host_ips(char* params)
745 {
746 	char* cmd  = NULL;
747 	int   ret  = 0;
748 	int   cnt  = 0;
749 
750 	while ((cmd = strsep(&params, GROUP_SEPARATOR)) != NULL) {
751 		char* host = strsep(&cmd, SEPARATOR);
752 		char* ip = NULL;
753 
754 		while ((ip = strsep(&cmd, SEPARATOR)) != NULL) {
755 			cnt++;
756 			if (!_predefined_host_is_contain_host_ip(host, ip, 1)) {
757 				ret = _predefined_host_add_record(host, ip);
758 				if (ret != 0) {
759 					return ret;
760 				}
761 			}
762 		}
763 	}
764 
765 	return cnt > 0 ? 0 : -1;
766 }
767 
predefined_host_lookup_ip(const char * host,const char * serv,const struct addrinfo * hint,struct addrinfo ** res)768 int predefined_host_lookup_ip(const char* host, const char* serv,
769     const struct addrinfo* hint, struct addrinfo** res)
770 {
771 	int status = -1;
772     if (host_ips_list_ == NULL) {
773 		return -1;
774 	}
775     linknode *pnode = host_ips_list_->_phead;
776     while (pnode != NULL) {
777         host_ip_pair *pinfo = (host_ip_pair*)pnode->_data;
778         if (strcmp(pinfo->host, host) == 0) {
779             status = getaddrinfo(pinfo->ip, NULL, hint, res);
780             if (status == 0) {
781                 return status;
782             }
783         }
784         pnode = pnode->_next;
785     }
786     return status;
787 }
788 
predefined_host_set_hosts(const char * host_ips)789 int predefined_host_set_hosts(const char* host_ips)
790 {
791 	if (host_ips == NULL) {
792 	    return EAI_NONAME;
793 	}
794 
795 	int len = strlen(host_ips);
796 	if (len == 0) {
797 		return EAI_NONAME;
798 	}
799 
800 	if (host_ips_list_ == NULL) {
801 		host_ips_list_ = create_linklist();
802 		if (host_ips_list_ == NULL) {
803 			return EAI_MEMORY;
804 		}
805 	}
806 
807 	char *host_ips_str = calloc(1, len + 1);
808 	if (host_ips_str == NULL) {
809 		return EAI_MEMORY;
810 	}
811 
812 	memcpy(host_ips_str, host_ips, len + 1);
813 
814 	int ret = _predefined_host_parse_host_ips(host_ips_str);
815 
816 	free(host_ips_str);
817 
818 	return ret;
819 }
820 
predefined_host_set_host(const char * host,const char * ip)821 int predefined_host_set_host(const char* host, const char* ip)
822 {
823 	if (host == NULL || strlen(host) == 0 || ip == NULL || strlen(ip) == 0) {
824 		return -1;
825 	}
826 
827 	if (host_ips_list_ == NULL) {
828 		host_ips_list_ = create_linklist();
829 		if (host_ips_list_ == NULL) {
830 			return EAI_NONAME;
831 		}
832 	}
833 
834 	if (_predefined_host_is_contain_host_ip(host, ip, 1)) {
835 		return 0;
836 	}
837 
838 	return _predefined_host_add_record((char *)host, (char *)ip);
839 }
840 
predefined_host_name_from_hosts(struct address buf[static MAXADDRS],char canon[static256],const char * name,int family)841 int predefined_host_name_from_hosts(
842 		struct address buf[static MAXADDRS],
843 		char canon[static 256], const char *name, int family)
844 {
845 	int size = 256;
846 	int cnt = 0;
847 	if (host_ips_list_ != NULL) {
848 		linknode *pnode = host_ips_list_->_phead;
849 
850 		while (pnode != NULL && cnt < MAXADDRS) {
851 			host_ip_pair *pinfo = (host_ip_pair*)pnode->_data;
852 			if (strcmp(pinfo->host, name) == 0) {
853 				if (__lookup_ipliteral(buf+cnt, pinfo->ip, family) == 1) {
854 					cnt++;
855 				}
856 			}
857 			pnode = pnode->_next;
858 		}
859 	}
860 
861 	if (cnt > 0) {
862 		strncpy(canon, name, size - 1);
863 		canon[size - 1] = '\0';
864 	}
865 	return cnt;
866 }
867 
free_linknodedata(linknode * pnode)868 static inline void free_linknodedata(linknode *pnode)
869 {
870 	if (NULL != pnode) {
871 		free(pnode);
872 	}
873 }
874 
create_linknode(void * data)875 static linknode *create_linknode(void *data)
876 {
877 	linknode *pnode = (linknode *)calloc(1, sizeof(linknode));
878 	if (NULL == pnode) {
879 		return NULL;
880 	}
881 	pnode->_data = data;
882 	pnode->_next = NULL;
883 
884 	return pnode;
885 }
886 
create_linklist(void)887 static linkList *create_linklist(void)
888 {
889 	linkList *plist = (linkList *)calloc(1, sizeof(linkList));
890 	if (NULL == plist) {
891 		return NULL;
892 	}
893 	plist->_phead = NULL;
894 	plist->_count = 0;
895 
896 	return plist;
897 }
898 
destory_linklist(linkList * plist)899 static int destory_linklist(linkList *plist)
900 {
901 	if (NULL == plist) {
902 		return -1;
903 	}
904 
905 	linknode *pnode = plist->_phead;
906 	linknode *ptmp = NULL;
907 	while (pnode != NULL) {
908 		ptmp = pnode;
909 		pnode = pnode->_next;
910 		free_linknodedata(ptmp);
911 	}
912 
913 	plist->_phead = NULL;
914 	plist->_count = 0;
915 
916 	return 0;
917 }
918 
linklist_size(linkList * plist)919 static int linklist_size(linkList *plist)
920 {
921 	if (NULL == plist) {
922 		return 0;
923 	}
924 
925 	return plist->_count;
926 }
927 
get_linknode(linkList * plist,int index)928 static linknode *get_linknode(linkList *plist, int index)
929 {
930 	if (index < 0 || index >= plist->_count) {
931 		return NULL;
932 	}
933 
934 	int i = 0;
935 	linknode *pnode = plist->_phead;
936 	if (NULL == pnode) {
937 		return NULL;
938 	}
939 	while ((i++) < index && NULL != pnode) {
940 		pnode = pnode->_next;
941 	}
942 
943 	return pnode;
944 }
945 
linklist_append_last(linkList * plist,void * pdata)946 static int linklist_append_last(linkList *plist, void *pdata)
947 {
948 	if (NULL == plist) {
949 		return -1;
950 	}
951 
952 	linknode *pnode = create_linknode(pdata);
953 	if (NULL == pnode) {
954 		return -1;
955 	}
956 
957 	if (NULL == plist->_phead) {
958 		plist->_phead = pnode;
959 		plist->_count++;
960 	} else {
961 		linknode *plastnode = get_linknode(plist, plist->_count - 1);
962 		if (NULL == plastnode) {
963 			return -1;
964 		}
965 		plastnode->_next = pnode;
966 		plist->_count++;
967 	}
968 
969 	return 0;
970 }
971 
linklist_delete(linkList * plist,int index)972 static int linklist_delete(linkList *plist, int index)
973 {
974 	if (NULL == plist || NULL == plist->_phead || plist->_count <= 0) {
975 		return -1;
976 	}
977 
978 	if (index == 0) {
979 		return linklist_delete_first(plist);
980 	} else if (index == (plist->_count - 1)) {
981 		return linklist_delete_last(plist);
982 	} else {
983 		linknode *pindex = get_linknode(plist, index);
984 		if (NULL == pindex) {
985 			return -1;
986 		}
987 		linknode *preindex = get_linknode(plist, index - 1);
988 		if (NULL == preindex) {
989 			return -1;
990 		}
991 
992 		preindex->_next = pindex->_next;
993 
994 		free_linknodedata(pindex);
995 		plist->_count--;
996 	}
997 
998 	return 0;
999 }
1000 
linklist_delete_first(linkList * plist)1001 static int linklist_delete_first(linkList *plist)
1002 {
1003 	if (NULL == plist || NULL == plist->_phead || plist->_count <= 0) {
1004 		return -1;
1005 	}
1006 
1007 	linknode *phead = plist->_phead;
1008 	plist->_phead = plist->_phead->_next;
1009 
1010 	free_linknodedata(phead);
1011 	plist->_count--;
1012 
1013 	return 0;
1014 }
1015 
linklist_delete_last(linkList * plist)1016 static int linklist_delete_last(linkList *plist)
1017 {
1018 	if (NULL == plist || NULL == plist->_phead || plist->_count <= 0) {
1019 		return -1;
1020 	}
1021 
1022 	linknode *plastsecondnode = get_linknode(plist, plist->_count - 2);
1023 	if (NULL != plastsecondnode) {
1024 		linknode *plastnode = plastsecondnode->_next;
1025 		plastsecondnode->_next = NULL;
1026 
1027 		free_linknodedata(plastnode);
1028 		plist->_count--;
1029 	} else {
1030 		linknode *plastnode = get_linknode(plist, plist->_count - 1);
1031 		plist->_phead = NULL;
1032 		plist->_count = 0;
1033 
1034 		free_linknodedata(plastnode);
1035 	}
1036 
1037 	return 0;
1038 }
1039