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