1570af302Sopenharmony_ci#include <sys/socket.h>
2570af302Sopenharmony_ci#include <netinet/in.h>
3570af302Sopenharmony_ci#include <netdb.h>
4570af302Sopenharmony_ci#include <net/if.h>
5570af302Sopenharmony_ci#include <arpa/inet.h>
6570af302Sopenharmony_ci#include <limits.h>
7570af302Sopenharmony_ci#include <stdlib.h>
8570af302Sopenharmony_ci#include <string.h>
9570af302Sopenharmony_ci#include <ctype.h>
10570af302Sopenharmony_ci#include "lookup.h"
11570af302Sopenharmony_ci
12570af302Sopenharmony_ciint __lookup_ipliteral(struct address buf[static 1], const char *name, int family)
13570af302Sopenharmony_ci{
14570af302Sopenharmony_ci	struct in_addr a4;
15570af302Sopenharmony_ci	struct in6_addr a6;
16570af302Sopenharmony_ci	if (__inet_aton(name, &a4) > 0) {
17570af302Sopenharmony_ci		 /* wrong family */
18570af302Sopenharmony_ci		if (family == AF_INET6) {
19570af302Sopenharmony_ci#ifndef __LITEOS__
20570af302Sopenharmony_ci			MUSL_LOGE("%{public}s: %{public}d: wrong family AF_INET6: %{public}d", __func__, __LINE__, EAI_NONAME);
21570af302Sopenharmony_ci#endif
22570af302Sopenharmony_ci			return EAI_NONAME;
23570af302Sopenharmony_ci		}
24570af302Sopenharmony_ci		memcpy(&buf[0].addr, &a4, sizeof a4);
25570af302Sopenharmony_ci		buf[0].family = AF_INET;
26570af302Sopenharmony_ci		buf[0].scopeid = 0;
27570af302Sopenharmony_ci		return 1;
28570af302Sopenharmony_ci	}
29570af302Sopenharmony_ci
30570af302Sopenharmony_ci	char tmp[64];
31570af302Sopenharmony_ci	char *p = strchr(name, '%'), *z;
32570af302Sopenharmony_ci	unsigned long long scopeid = 0;
33570af302Sopenharmony_ci	if (p && p-name < 64) {
34570af302Sopenharmony_ci		memcpy(tmp, name, p-name);
35570af302Sopenharmony_ci		tmp[p-name] = 0;
36570af302Sopenharmony_ci		name = tmp;
37570af302Sopenharmony_ci	}
38570af302Sopenharmony_ci
39570af302Sopenharmony_ci	if (inet_pton(AF_INET6, name, &a6) <= 0)
40570af302Sopenharmony_ci		return 0;
41570af302Sopenharmony_ci	if (family == AF_INET) /* wrong family */ {
42570af302Sopenharmony_ci#ifndef __LITEOS__
43570af302Sopenharmony_ci		MUSL_LOGE("%{public}s: %{public}d: wrong family AF_INET: %{public}d", __func__, __LINE__, EAI_NONAME);
44570af302Sopenharmony_ci#endif
45570af302Sopenharmony_ci		return EAI_NONAME;
46570af302Sopenharmony_ci	}
47570af302Sopenharmony_ci
48570af302Sopenharmony_ci	memcpy(&buf[0].addr, &a6, sizeof a6);
49570af302Sopenharmony_ci	buf[0].family = AF_INET6;
50570af302Sopenharmony_ci	if (p) {
51570af302Sopenharmony_ci		if (isdigit(*++p)) scopeid = strtoull(p, &z, 10);
52570af302Sopenharmony_ci		else z = p-1;
53570af302Sopenharmony_ci		if (*z) {
54570af302Sopenharmony_ci			if (!IN6_IS_ADDR_LINKLOCAL(&a6) &&
55570af302Sopenharmony_ci			    !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) {
56570af302Sopenharmony_ci#ifndef __LITEOS__
57570af302Sopenharmony_ci				MUSL_LOGE("%{public}s: %{public}d: illegal ipv6 address: %{public}d", __func__, __LINE__, EAI_NONAME);
58570af302Sopenharmony_ci#endif
59570af302Sopenharmony_ci				return EAI_NONAME;
60570af302Sopenharmony_ci			}
61570af302Sopenharmony_ci			scopeid = if_nametoindex(p);
62570af302Sopenharmony_ci			if (!scopeid) {
63570af302Sopenharmony_ci#ifndef __LITEOS__
64570af302Sopenharmony_ci				MUSL_LOGE("%{public}s: %{public}d: scopeid is zero: %{public}d", __func__, __LINE__, EAI_NONAME);
65570af302Sopenharmony_ci#endif
66570af302Sopenharmony_ci				return EAI_NONAME;
67570af302Sopenharmony_ci			}
68570af302Sopenharmony_ci		}
69570af302Sopenharmony_ci		if (scopeid > UINT_MAX) {
70570af302Sopenharmony_ci#ifndef __LITEOS__
71570af302Sopenharmony_ci			MUSL_LOGE("%{public}s: %{public}d: scopeid is over than UINT_MAX: %{public}d", __func__, __LINE__, EAI_NONAME);
72570af302Sopenharmony_ci#endif
73570af302Sopenharmony_ci			return EAI_NONAME;
74570af302Sopenharmony_ci		}
75570af302Sopenharmony_ci	}
76570af302Sopenharmony_ci	buf[0].scopeid = scopeid;
77570af302Sopenharmony_ci	return 1;
78570af302Sopenharmony_ci}
79