1#include <stdlib.h>
2#include <sys/socket.h>
3#include <sys/time.h>
4#include <netinet/in.h>
5#include <netdb.h>
6#include <string.h>
7#include <pthread.h>
8#include <unistd.h>
9#include <endian.h>
10#include <errno.h>
11#include "lookup.h"
12
13#define COST_FOR_MS 1000
14#define COST_FOR_NANOSEC 1000000
15#define DNS_QUERY_SUCCESS 0
16#define DNS_QUERY_COMMOM_FAIL (-1)
17#define GETADDRINFO_PRINT_DEBUG(...)
18
19int reportdnsresult(int netid, char* name, int usedtime, int queryret, struct addrinfo *res, struct queryparam *param)
20{
21#if OHOS_DNS_PROXY_BY_NETSYS
22	if (dns_post_result_to_netsys_cache(netid, name, usedtime, queryret, res, param) == 0) {
23		GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext reportdnsresult fail\n");
24	}
25#endif
26	return 0;
27}
28
29static custom_dns_resolver g_customdnsresolvehook;
30static pthread_key_t g_recursiveKey;
31static int* g_recursive;
32
33int setdnsresolvehook(custom_dns_resolver hookfunc)
34{
35	int ret = -1;
36	if (g_customdnsresolvehook) {
37		return ret;
38	}
39	if (hookfunc) {
40		g_customdnsresolvehook = hookfunc;
41		pthread_key_create(&g_recursiveKey, NULL);
42		ret = 0;
43	}
44	return ret;
45}
46
47int removednsresolvehook()
48{
49	g_customdnsresolvehook = NULL;
50	if (g_recursive) {
51		free(g_recursive);
52		g_recursive = NULL;
53	}
54	if (g_recursiveKey) {
55		pthread_key_delete(g_recursiveKey);
56		g_recursiveKey = NULL;
57	}
58	return 0;
59}
60
61int getaddrinfo_hook(const char* host, const char* serv, const struct addrinfo* hints,
62    struct addrinfo** res)
63{
64    if (g_customdnsresolvehook) {
65        int ret = g_customdnsresolvehook(host, serv, hints, res);
66        if (ret == 0) {
67            return ret;
68        }
69    }
70    return predefined_host_lookup_ip(host, serv, hints, res);
71}
72
73int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
74{
75	struct queryparam param = {0, 0, 0, 0, NULL};
76	return getaddrinfo_ext(host, serv, hint, res, &param);
77}
78
79int getaddrinfo_ext(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint,
80					struct addrinfo **restrict res, struct queryparam *restrict param)
81{
82	int netid = 0;
83	int type = 0;
84	int usedtime = 0;
85	struct timeval timeStart, timeEnd;
86
87	if (!host && !serv) return EAI_NONAME;
88	if (!param) {
89		netid = 0;
90		type = 0;
91	} else {
92		netid = param->qp_netid;
93		type = param->qp_type;
94	}
95
96	if (g_customdnsresolvehook) {
97		g_recursive = pthread_getspecific(g_recursiveKey);
98		if (g_recursive == NULL) {
99			int *newRecursive = malloc(sizeof(int));
100			*newRecursive = 0;
101			pthread_setspecific(g_recursiveKey, newRecursive);
102			g_recursive = newRecursive;
103		}
104		if (*g_recursive == 0) {
105			++(*g_recursive);
106			int ret = g_customdnsresolvehook(host, serv, hint, res);
107			--(*g_recursive);
108			return ret;
109		}
110	}
111
112#if OHOS_DNS_PROXY_BY_NETSYS
113	GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext netid:%{public}d type:%{public}d \n", netid, type);
114	if (type == QEURY_TYPE_NORMAL && predefined_host_is_contain_host(host) == 0) {
115		if (dns_get_addr_info_from_netsys_cache2(netid, host, serv, hint, res) == 0) {
116			GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext get from netsys cache OK\n");
117			reportdnsresult(netid, host, 0, DNS_QUERY_SUCCESS, *res, param);
118			return 0;
119		}
120	}
121#endif
122
123	struct service ports[MAXSERVS];
124	struct address addrs[MAXADDRS];
125	char canon[256], *outcanon;
126	int nservs, naddrs, nais, canon_len, i, j, k;
127	int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
128	struct aibuf *out;
129
130	if (hint) {
131		family = hint->ai_family;
132		flags = hint->ai_flags;
133		proto = hint->ai_protocol;
134		socktype = hint->ai_socktype;
135
136		const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
137			AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
138		if ((flags & mask) != flags) {
139#ifndef __LITEOS__
140			MUSL_LOGE("%{public}s: %{public}d: bad hint ai_flag: %{public}d", __func__, __LINE__, flags);
141#endif
142			return EAI_BADFLAGS;
143		}
144
145		switch (family) {
146		case AF_INET:
147		case AF_INET6:
148		case AF_UNSPEC:
149			break;
150		default:
151#ifndef __LITEOS__
152			MUSL_LOGE("%{public}s: %{public}d: wrong family in hint: %{public}d", __func__, __LINE__, family);
153#endif
154			return EAI_FAMILY;
155		}
156	}
157
158	if (flags & AI_ADDRCONFIG) {
159		/* Define the "an address is configured" condition for address
160		 * families via ability to create a socket for the family plus
161		 * routability of the loopback address for the family. */
162		static const struct sockaddr_in lo4 = {
163			.sin_family = AF_INET, .sin_port = 65535,
164			.sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN
165				? 0x7f000001 : 0x0100007f
166		};
167		static const struct sockaddr_in6 lo6 = {
168			.sin6_family = AF_INET6, .sin6_port = 65535,
169			.sin6_addr = IN6ADDR_LOOPBACK_INIT
170		};
171		int tf[2] = { AF_INET, AF_INET6 };
172		const void *ta[2] = { &lo4, &lo6 };
173		socklen_t tl[2] = { sizeof lo4, sizeof lo6 };
174		for (i = 0; i < 2; i++) {
175			if (family == tf[1 - i]) continue;
176			int s = socket(tf[i], SOCK_CLOEXEC | SOCK_DGRAM,
177				IPPROTO_UDP);
178#ifndef __LITEOS__
179			if (s < 0) {
180				MUSL_LOGE("%{public}s: %{public}d: create socket failed for family: %{public}d, errno: %{public}d",
181					__func__, __LINE__, tf[i], errno);
182			}
183#endif
184			if (s >= 0) {
185				int cs;
186				pthread_setcancelstate(
187					PTHREAD_CANCEL_DISABLE, &cs);
188				int r = connect(s, ta[i], tl[i]);
189				int saved_errno = errno;
190				pthread_setcancelstate(cs, 0);
191				close(s);
192				if (!r) continue;
193				errno = saved_errno;
194			}
195			switch (errno) {
196			case EADDRNOTAVAIL:
197			case EAFNOSUPPORT:
198			case EHOSTUNREACH:
199			case ENETDOWN:
200			case ENETUNREACH:
201				break;
202			default:
203#ifndef __LITEOS__
204				MUSL_LOGE("%{public}s: %{public}d: connect to local address failed: %{public}d",
205					__func__, __LINE__, errno);
206#endif
207				return EAI_SYSTEM;
208			}
209			if (family == tf[i]) {
210#ifndef __LITEOS__
211				MUSL_LOGE("%{public}s: %{public}d: family mismatch: %{public}d", __func__, __LINE__, EAI_NONAME);
212#endif
213                return EAI_NONAME;
214			}
215			family = tf[1 - i];
216		}
217	}
218
219	int timeStartRet = gettimeofday(&timeStart, NULL);
220	nservs = __lookup_serv(ports, serv, proto, socktype, flags);
221	if (nservs < 0) return nservs;
222
223	naddrs = lookup_name_ext(addrs, canon, host, family, flags, netid);
224	int timeEndRet = gettimeofday(&timeEnd, NULL);
225	int t_cost = 0;
226	if (timeStartRet == 0 && timeEndRet == 0) {
227		t_cost = COST_FOR_NANOSEC * (timeEnd.tv_sec - timeStart.tv_sec) + (timeEnd.tv_usec - timeStart.tv_usec);
228		t_cost /= COST_FOR_MS;
229	}
230	if (naddrs < 0) {
231		reportdnsresult(netid, host, t_cost, naddrs, NULL, param);
232#ifndef __LITEOS__
233		MUSL_LOGE("%{public}s: %{public}d: reportdnsresult: %{public}d in process %{public}d",
234			__func__, __LINE__, naddrs, getpid());
235#endif
236		return naddrs;
237	}
238
239	nais = nservs * naddrs;
240	canon_len = strlen(canon);
241	out = calloc(1, nais * sizeof(*out) + canon_len + 1);
242	if (!out) return EAI_MEMORY;
243
244	if (canon_len) {
245		outcanon = (void *)&out[nais];
246		memcpy(outcanon, canon, canon_len + 1);
247	} else {
248		outcanon = 0;
249	}
250
251	for (k = i = 0; i < naddrs; i++) for (j = 0; j < nservs; j++, k++) {
252		out[k].slot = k;
253		out[k].ai = (struct addrinfo) {
254			.ai_family = addrs[i].family,
255			.ai_socktype = ports[j].socktype,
256			.ai_protocol = ports[j].proto,
257			.ai_addrlen = addrs[i].family == AF_INET
258				? sizeof(struct sockaddr_in)
259				: sizeof(struct sockaddr_in6),
260			.ai_addr = (void *)&out[k].sa,
261			.ai_canonname = outcanon };
262		if (k) out[k-1].ai.ai_next = &out[k].ai;
263		switch (addrs[i].family) {
264		case AF_INET:
265			out[k].sa.sin.sin_family = AF_INET;
266			out[k].sa.sin.sin_port = htons(ports[j].port);
267			memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
268			break;
269		case AF_INET6:
270			out[k].sa.sin6.sin6_family = AF_INET6;
271			out[k].sa.sin6.sin6_port = htons(ports[j].port);
272			out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;
273			memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
274			break;
275		}
276	}
277	out[0].ref = nais;
278	*res = &out->ai;
279
280	reportdnsresult(netid, host, t_cost, DNS_QUERY_SUCCESS, *res, param);
281	int cnt = predefined_host_is_contain_host(host);
282#if OHOS_DNS_PROXY_BY_NETSYS
283	if (type == QEURY_TYPE_NORMAL && cnt == 0) {
284		dns_set_addr_info_to_netsys_cache2(netid, host, serv, hint, *res);
285	}
286#endif
287	return 0;
288}
289