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