• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *	 http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "lookup.h"
17 #include "stdio_impl.h"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <netinet/in.h>
23 
24 #include "hilog_adapter.h"
25 
26 #if 1
27 #define SIGCHAIN_LOG_DOMAIN 0xD003F00
28 #define SIGCHAIN_LOG_TAG "ressolvconf"
29 #define GETADDRINFO_PRINT_DEBUG(...) ((void)HiLogAdapterPrint(LOG_CORE, LOG_INFO, \
30 	SIGCHAIN_LOG_DOMAIN, SIGCHAIN_LOG_TAG, __VA_ARGS__))
31 #else
32 #define GETADDRINFO_PRINT_DEBUG(...)
33 #endif
34 
35 #define DNS_RESOLV_CONF_PATH "/etc/resolv.conf"
36 
37 #if OHOS_DNS_PROXY_BY_NETSYS | OHOS_FWMARK_CLIENT_BY_NETSYS
38 #include "atomic.h"
39 
40 #include <dlfcn.h>
41 
open_dns_lib(void)42 static void *open_dns_lib(void)
43 {
44 	static void *dns_lib_handle = NULL;
45 	if (dns_lib_handle != NULL) {
46 		a_barrier();
47 		return dns_lib_handle;
48 	}
49 
50 	void *lib = dlopen(DNS_SO_PATH, RTLD_LAZY);
51 	if (lib == NULL) {
52 		DNS_CONFIG_PRINT("%s: dlopen %s failed: %s",
53 			__func__, DNS_SO_PATH, dlerror());
54 		return NULL;
55 	}
56 
57 	void *old_lib = a_cas_p(&dns_lib_handle, NULL, lib);
58 	if (old_lib == NULL) {
59 		DNS_CONFIG_PRINT("%s: %s loaded", __func__, DNS_SO_PATH);
60 		return lib;
61 	} else {
62 		/* Another thread has already loaded the library,
63 		 * dlclose is invoked to make refcount correct */
64 		DNS_CONFIG_PRINT("%s: %s has been loaded by another thread",
65 			__func__, DNS_SO_PATH);
66 		if (dlclose(lib)) {
67 			DNS_CONFIG_PRINT("%s: dlclose %s failed: %s",
68 				__func__, DNS_SO_PATH, dlerror());
69 		}
70 		return old_lib;
71 	}
72 }
73 
load_from_dns_lib(const char * symbol)74 static void *load_from_dns_lib(const char *symbol)
75 {
76 	void *lib_handle = open_dns_lib();
77 	if (lib_handle == NULL) {
78 		return NULL;
79 	}
80 
81 	void *sym_addr = dlsym(lib_handle, symbol);
82 	if (sym_addr == NULL) {
83 		DNS_CONFIG_PRINT("%s: loading symbol %s with dlsym failed: %s",
84 			__func__, symbol, dlerror());
85 	}
86 	return sym_addr;
87 }
88 
resolve_dns_sym(void ** holder,const char * symbol)89 void resolve_dns_sym(void **holder, const char *symbol)
90 {
91 	if (*holder != NULL) {
92 		a_barrier();
93 		return;
94 	}
95 
96 	void *ptr = load_from_dns_lib(symbol);
97 	if (ptr == NULL) {
98 		return;
99 	}
100 
101 	void *old_ptr = a_cas_p(holder, NULL, ptr);
102 	if (old_ptr != NULL) {
103 		DNS_CONFIG_PRINT("%s: %s has been found by another thread",
104 			__func__, symbol);
105 	} else {
106 		DNS_CONFIG_PRINT("%s: %s found", __func__, symbol);
107 	}
108 }
109 
load_config_getter(void)110 static GetConfig load_config_getter(void)
111 {
112 	static GetConfig config_getter = NULL;
113 	resolve_dns_sym((void **) &config_getter, OHOS_GET_CONFIG_FUNC_NAME);
114 	return config_getter;
115 }
116 
117 #endif
118 
__get_resolv_conf(struct resolvconf * conf,char * search,size_t search_sz)119 int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
120 {
121        return get_resolv_conf_ext(conf, search, search_sz, 0);
122 }
123 
get_resolv_conf_ext(struct resolvconf * conf,char * search,size_t search_sz,int netid)124 int get_resolv_conf_ext(struct resolvconf *conf, char *search, size_t search_sz, int netid)
125 {
126 	char line[256];
127 	unsigned char _buf[256];
128 	FILE *f, _f;
129 	int nns = 0;
130 
131 	conf->ndots = 1;
132 	conf->timeout = 5;
133 	conf->attempts = 2;
134 	if (search) *search = 0;
135 
136 #if OHOS_DNS_PROXY_BY_NETSYS
137 	GetConfig func = load_config_getter();
138 	if (!func) {
139 		DNS_CONFIG_PRINT("%s: loading %s failed, use %s as a fallback",
140 			__func__, OHOS_GET_CONFIG_FUNC_NAME, DNS_RESOLV_CONF_PATH);
141 		goto etc_resolv_conf;
142 	}
143 
144 	struct resolv_config config = {0};
145 	int ret = func(netid, &config);
146 	if (ret < 0) {
147 		DNS_CONFIG_PRINT("__get_resolv_conf OHOS_GET_CONFIG_FUNC_NAME err %d\n", ret);
148 		return EAI_NONAME;
149 	}
150 	int32_t timeout_second = config.timeout_ms / 1000;
151 
152 netsys_conf:
153 	if (timeout_second > 0) {
154 		if (timeout_second >= 60) {
155 			conf->timeout = 60;
156 		} else {
157 			conf->timeout = timeout_second;
158 		}
159 	}
160 	if (config.retry_count > 0) {
161 		if (config.retry_count >= 10) {
162 			conf->attempts = 10;
163 		} else {
164 			conf->attempts = config.retry_count;
165 		}
166 	}
167 	for (int i = 0; i < MAX_SERVER_NUM; ++i) {
168 		if (config.nameservers[i] == NULL || config.nameservers[i][0] == 0 || nns >= MAXNS) {
169 			continue;
170 		}
171 		if (__lookup_ipliteral(conf->ns + nns, config.nameservers[i], AF_UNSPEC) > 0) {
172 			nns++;
173 		}
174 	}
175 
176         if (nns != 0) {
177             goto get_conf_ok;
178         }
179 
180 etc_resolv_conf:
181 #endif
182 	f = __fopen_rb_ca(DNS_RESOLV_CONF_PATH, &_f, _buf, sizeof _buf);
183 	if (!f) switch (errno) {
184 	case ENOENT:
185 	case ENOTDIR:
186 	case EACCES:
187 		goto no_resolv_conf;
188 	default:
189 		return -1;
190 	}
191 
192 	while (fgets(line, sizeof line, f)) {
193 		char *p, *z;
194 		if (!strchr(line, '\n') && !feof(f)) {
195 			/* Ignore lines that get truncated rather than
196 			 * potentially misinterpreting them. */
197 			int c;
198 			do c = getc(f);
199 			while (c != '\n' && c != EOF);
200 			continue;
201 		}
202 		if (!strncmp(line, "options", 7) && isspace(line[7])) {
203 			p = strstr(line, "ndots:");
204 			if (p && isdigit(p[6])) {
205 				p += 6;
206 				unsigned long x = strtoul(p, &z, 10);
207 				if (z != p) conf->ndots = x > 15 ? 15 : x;
208 			}
209 			p = strstr(line, "attempts:");
210 			if (p && isdigit(p[9])) {
211 				p += 9;
212 				unsigned long x = strtoul(p, &z, 10);
213 				if (z != p) conf->attempts = x > 10 ? 10 : x;
214 			}
215 			p = strstr(line, "timeout:");
216 			if (p && (isdigit(p[8]) || p[8]=='.')) {
217 				p += 8;
218 				unsigned long x = strtoul(p, &z, 10);
219 				if (z != p) conf->timeout = x > 60 ? 60 : x;
220 			}
221 			continue;
222 		}
223 		if (!strncmp(line, "nameserver", 10) && isspace(line[10])) {
224 			if (nns >= MAXNS) continue;
225 			for (p=line+11; isspace(*p); p++);
226 			for (z=p; *z && !isspace(*z); z++);
227 			*z=0;
228 			if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0)
229 				nns++;
230 			continue;
231 		}
232 
233 		if (!search) continue;
234 		if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6))
235 		    || !isspace(line[6]))
236 			continue;
237 		for (p=line+7; isspace(*p); p++);
238 		size_t l = strlen(p);
239 		/* This can never happen anyway with chosen buffer sizes. */
240 		if (l >= search_sz) continue;
241 		memcpy(search, p, l+1);
242 	}
243 
244 	__fclose_ca(f);
245 
246 no_resolv_conf:
247 	if (!nns) {
248 		__lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC);
249 		nns = 1;
250 	}
251 
252 get_conf_ok:
253 	conf->nns = nns;
254 
255 	return 0;
256 }
257 
res_bind_socket(int fd,int netid)258 int res_bind_socket(int fd, int netid)
259 {
260 	int ret = -1;
261 	void* libhandler;
262 
263 	GETADDRINFO_PRINT_DEBUG("res_bind_socket netid:%{public}d \n", netid);
264 
265 #ifdef OHOS_FWMARK_CLIENT_BY_NETSYS
266 	libhandler = dlopen(FWMARKCLIENT_SO_PATH, RTLD_LAZY);
267 	if (libhandler == NULL) {
268 		GETADDRINFO_PRINT_DEBUG("dns_get_addr_info_from_netsys_cache dlopen err %s\n", dlerror());
269 		return -1;
270 	}
271 
272 	BindSocket_Ext func = dlsym(libhandler, OHOS_BIND_SOCKET_FUNC_NAME);
273 	if (func == NULL) {
274 		GETADDRINFO_PRINT_DEBUG("dns_get_addr_info_from_netsys_cache dlsym err %s\n", dlerror());
275 		dlclose(libhandler);
276 		return -1;
277 	} else {
278 		ret = func(fd, netid);
279 		GETADDRINFO_PRINT_DEBUG("res_bind_socket ret %{public}d \n", ret);
280 		dlclose(libhandler);
281 	}
282 #endif
283 	return ret;
284 }
285 
286