1 /*
2 * Copyright (c) 2017 Linaro Limited
3 * Copyright (c) 2020 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /* libc headers */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12
13 /* Zephyr headers */
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(net_sock_addr, CONFIG_NET_SOCKETS_LOG_LEVEL);
16
17 #include <zephyr/kernel.h>
18 #include <zephyr/net/net_ip.h>
19 #include <zephyr/net/socket.h>
20 #include <zephyr/net/socket_offload.h>
21 #include <zephyr/internal/syscall_handler.h>
22
23 #if defined(CONFIG_DNS_RESOLVER) || defined(CONFIG_NET_IP)
24 #define ANY_RESOLVER
25
26 #if defined(CONFIG_DNS_RESOLVER_AI_MAX_ENTRIES)
27 #define AI_ARR_MAX CONFIG_DNS_RESOLVER_AI_MAX_ENTRIES
28 #else
29 #define AI_ARR_MAX 1
30 #endif /* defined(CONFIG_DNS_RESOLVER_AI_MAX_ENTRIES) */
31
32 /* Initialize static fields of addrinfo structure. A macro to let it work
33 * with any sockaddr_* type.
34 */
35 #define INIT_ADDRINFO(addrinfo, sockaddr) { \
36 (addrinfo)->ai_addr = &(addrinfo)->_ai_addr; \
37 (addrinfo)->ai_addrlen = sizeof(*(sockaddr)); \
38 (addrinfo)->ai_canonname = (addrinfo)->_ai_canonname; \
39 (addrinfo)->_ai_canonname[0] = '\0'; \
40 (addrinfo)->ai_next = NULL; \
41 }
42
43 #endif
44
45 #if defined(CONFIG_DNS_RESOLVER)
46
47 struct getaddrinfo_state {
48 const struct zsock_addrinfo *hints;
49 struct k_sem sem;
50 int status;
51 uint16_t idx;
52 uint16_t port;
53 uint16_t dns_id;
54 struct zsock_addrinfo *ai_arr;
55 };
56
dns_resolve_cb(enum dns_resolve_status status,struct dns_addrinfo * info,void * user_data)57 static void dns_resolve_cb(enum dns_resolve_status status,
58 struct dns_addrinfo *info, void *user_data)
59 {
60 struct getaddrinfo_state *state = user_data;
61 struct zsock_addrinfo *ai;
62 int socktype = SOCK_STREAM;
63
64 NET_DBG("dns status: %d", status);
65
66 if (info == NULL) {
67 if (status == DNS_EAI_ALLDONE) {
68 status = 0;
69 }
70 state->status = status;
71 k_sem_give(&state->sem);
72 return;
73 }
74
75 if (state->idx >= AI_ARR_MAX) {
76 NET_DBG("getaddrinfo entries overflow");
77 return;
78 }
79
80 ai = &state->ai_arr[state->idx];
81 if (state->idx > 0) {
82 state->ai_arr[state->idx - 1].ai_next = ai;
83 }
84
85 memcpy(&ai->_ai_addr, &info->ai_addr, info->ai_addrlen);
86 net_sin(&ai->_ai_addr)->sin_port = state->port;
87 ai->ai_addr = &ai->_ai_addr;
88 ai->ai_addrlen = info->ai_addrlen;
89 memcpy(&ai->_ai_canonname, &info->ai_canonname,
90 sizeof(ai->_ai_canonname));
91 ai->ai_canonname = ai->_ai_canonname;
92 ai->ai_family = info->ai_family;
93
94 if (state->hints) {
95 if (state->hints->ai_socktype) {
96 socktype = state->hints->ai_socktype;
97 }
98 }
99
100 ai->ai_socktype = socktype;
101 ai->ai_protocol = (socktype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
102
103 state->idx++;
104 }
105
recalc_timeout(k_timepoint_t end,k_timeout_t timeout)106 static k_timeout_t recalc_timeout(k_timepoint_t end, k_timeout_t timeout)
107 {
108 k_timepoint_t new_timepoint;
109
110 timeout.ticks <<= 1;
111
112 new_timepoint = sys_timepoint_calc(timeout);
113
114 if (sys_timepoint_cmp(end, new_timepoint) < 0) {
115 timeout = sys_timepoint_timeout(end);
116 }
117
118 return timeout;
119 }
120
exec_query(const char * host,int family,struct getaddrinfo_state * ai_state)121 static int exec_query(const char *host, int family,
122 struct getaddrinfo_state *ai_state)
123 {
124 enum dns_query_type qtype = DNS_QUERY_TYPE_A;
125 k_timepoint_t end = sys_timepoint_calc(K_MSEC(CONFIG_NET_SOCKETS_DNS_TIMEOUT));
126 k_timeout_t timeout = K_MSEC(MIN(CONFIG_NET_SOCKETS_DNS_TIMEOUT,
127 CONFIG_NET_SOCKETS_DNS_BACKOFF_INTERVAL));
128 int timeout_ms;
129 int st, ret;
130
131 if (family == AF_INET6) {
132 qtype = DNS_QUERY_TYPE_AAAA;
133 }
134
135 again:
136 timeout_ms = k_ticks_to_ms_ceil32(timeout.ticks);
137
138 NET_DBG("Timeout %d", timeout_ms);
139
140 ret = dns_get_addr_info(host, qtype, &ai_state->dns_id,
141 dns_resolve_cb, ai_state, timeout_ms);
142 if (ret == 0) {
143 /* If the DNS query for reason fails so that the
144 * dns_resolve_cb() would not be called, then we want the
145 * semaphore to timeout so that we will not hang forever.
146 * So make the sem timeout longer than the DNS timeout so that
147 * we do not need to start to cancel any pending DNS queries.
148 */
149 ret = k_sem_take(&ai_state->sem, K_MSEC(timeout_ms + 100));
150 if (ret == -EAGAIN) {
151 if (!sys_timepoint_expired(end)) {
152 timeout = recalc_timeout(end, timeout);
153 goto again;
154 }
155
156 (void)dns_cancel_addr_info(ai_state->dns_id);
157 st = DNS_EAI_AGAIN;
158 } else {
159 if (ai_state->status == DNS_EAI_CANCELED) {
160 if (!sys_timepoint_expired(end)) {
161 timeout = recalc_timeout(end, timeout);
162 goto again;
163 }
164 }
165
166 st = ai_state->status;
167 }
168 } else if (ret == -EPFNOSUPPORT) {
169 /* If we are returned -EPFNOSUPPORT then that will indicate
170 * wrong address family type queried. Check that and return
171 * DNS_EAI_ADDRFAMILY.
172 */
173 st = DNS_EAI_ADDRFAMILY;
174 } else {
175 errno = -ret;
176 st = DNS_EAI_SYSTEM;
177 }
178
179 return st;
180 }
181
getaddrinfo_null_host(int port,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)182 static int getaddrinfo_null_host(int port, const struct zsock_addrinfo *hints,
183 struct zsock_addrinfo *res)
184 {
185 if (!hints || !(hints->ai_flags & AI_PASSIVE)) {
186 return DNS_EAI_FAIL;
187 }
188
189 /* For AF_UNSPEC, should we default to IPv6 or IPv4? */
190 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
191 struct sockaddr_in *addr = net_sin(&res->_ai_addr);
192 addr->sin_addr.s_addr = INADDR_ANY;
193 addr->sin_port = htons(port);
194 addr->sin_family = AF_INET;
195 INIT_ADDRINFO(res, addr);
196 res->ai_family = AF_INET;
197 } else if (hints->ai_family == AF_INET6) {
198 struct sockaddr_in6 *addr6 = net_sin6(&res->_ai_addr);
199 addr6->sin6_addr = in6addr_any;
200 addr6->sin6_port = htons(port);
201 addr6->sin6_family = AF_INET6;
202 INIT_ADDRINFO(res, addr6);
203 res->ai_family = AF_INET6;
204 } else {
205 return DNS_EAI_FAIL;
206 }
207
208 if (hints->ai_socktype == SOCK_DGRAM) {
209 res->ai_socktype = SOCK_DGRAM;
210 res->ai_protocol = IPPROTO_UDP;
211 } else {
212 res->ai_socktype = SOCK_STREAM;
213 res->ai_protocol = IPPROTO_TCP;
214 }
215 return 0;
216 }
217
z_impl_z_zsock_getaddrinfo_internal(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)218 int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
219 const struct zsock_addrinfo *hints,
220 struct zsock_addrinfo *res)
221 {
222 int family = AF_UNSPEC;
223 int ai_flags = 0;
224 long int port = 0;
225 int st1 = DNS_EAI_ADDRFAMILY, st2 = DNS_EAI_ADDRFAMILY;
226 struct sockaddr *ai_addr;
227 struct getaddrinfo_state ai_state;
228
229 if (hints) {
230 family = hints->ai_family;
231 ai_flags = hints->ai_flags;
232
233 if ((family != AF_UNSPEC) && (family != AF_INET) && (family != AF_INET6)) {
234 return DNS_EAI_ADDRFAMILY;
235 }
236 }
237
238 if (ai_flags & AI_NUMERICHOST) {
239 /* Asked to resolve host as numeric, but it wasn't possible
240 * to do that.
241 */
242 return DNS_EAI_FAIL;
243 }
244
245 if (service) {
246 port = strtol(service, NULL, 10);
247 if (port < 1 || port > 65535) {
248 return DNS_EAI_NONAME;
249 }
250 }
251
252 if (host == NULL) {
253 /* Per POSIX, both can't be NULL. */
254 if (service == NULL) {
255 errno = EINVAL;
256 return DNS_EAI_SYSTEM;
257 }
258
259 return getaddrinfo_null_host(port, hints, res);
260 }
261
262 ai_state.hints = hints;
263 ai_state.idx = 0U;
264 ai_state.port = htons(port);
265 ai_state.ai_arr = res;
266 ai_state.dns_id = 0;
267 k_sem_init(&ai_state.sem, 0, K_SEM_MAX_LIMIT);
268
269 /* If family is AF_UNSPEC, then we query IPv4 address first
270 * if IPv4 is enabled in the config.
271 */
272 if ((family != AF_INET6) && IS_ENABLED(CONFIG_NET_IPV4)) {
273 st1 = exec_query(host, AF_INET, &ai_state);
274 if (st1 == DNS_EAI_AGAIN) {
275 return st1;
276 }
277 }
278
279 /* If family is AF_UNSPEC, the IPv4 query has been already done
280 * so we can do IPv6 query next if IPv6 is enabled in the config.
281 */
282 if ((family != AF_INET) && IS_ENABLED(CONFIG_NET_IPV6)) {
283 st2 = exec_query(host, AF_INET6, &ai_state);
284 if (st2 == DNS_EAI_AGAIN) {
285 return st2;
286 }
287 }
288
289 for (uint16_t idx = 0; idx < ai_state.idx; idx++) {
290 ai_addr = &ai_state.ai_arr[idx]._ai_addr;
291 net_sin(ai_addr)->sin_port = htons(port);
292 }
293
294 /* If both attempts failed, it's error */
295 if (st1 && st2) {
296 if (st1 != DNS_EAI_ADDRFAMILY) {
297 return st1;
298 }
299 return st2;
300 }
301
302 /* Mark entry as last */
303 ai_state.ai_arr[ai_state.idx - 1].ai_next = NULL;
304
305 return 0;
306 }
307
308 #ifdef CONFIG_USERSPACE
z_vrfy_z_zsock_getaddrinfo_internal(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)309 static inline int z_vrfy_z_zsock_getaddrinfo_internal(const char *host,
310 const char *service,
311 const struct zsock_addrinfo *hints,
312 struct zsock_addrinfo *res)
313 {
314 struct zsock_addrinfo hints_copy;
315 char *host_copy = NULL, *service_copy = NULL;
316 uint32_t ret;
317
318 if (hints) {
319 K_OOPS(k_usermode_from_copy(&hints_copy, (void *)hints,
320 sizeof(hints_copy)));
321 }
322 K_OOPS(K_SYSCALL_MEMORY_ARRAY_WRITE(res, AI_ARR_MAX, sizeof(struct zsock_addrinfo)));
323
324 if (service) {
325 service_copy = k_usermode_string_alloc_copy((char *)service, 64);
326 if (!service_copy) {
327 ret = DNS_EAI_MEMORY;
328 goto out;
329 }
330 }
331
332 if (host) {
333 host_copy = k_usermode_string_alloc_copy((char *)host, 64);
334 if (!host_copy) {
335 ret = DNS_EAI_MEMORY;
336 goto out;
337 }
338 }
339
340 ret = z_impl_z_zsock_getaddrinfo_internal(host_copy, service_copy,
341 hints ? &hints_copy : NULL,
342 (struct zsock_addrinfo *)res);
343 out:
344 k_free(service_copy);
345 k_free(host_copy);
346
347 return ret;
348 }
349 #include <zephyr/syscalls/z_zsock_getaddrinfo_internal_mrsh.c>
350 #endif /* CONFIG_USERSPACE */
351
352 #endif /* defined(CONFIG_DNS_RESOLVER) */
353
354 #if defined(CONFIG_NET_IP)
try_resolve_literal_addr(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)355 static int try_resolve_literal_addr(const char *host, const char *service,
356 const struct zsock_addrinfo *hints,
357 struct zsock_addrinfo *res)
358 {
359 int family = AF_UNSPEC;
360 int resolved_family = AF_UNSPEC;
361 long port = 0;
362 bool result;
363 int socktype = SOCK_STREAM;
364 int protocol = IPPROTO_TCP;
365
366 if (!host) {
367 return DNS_EAI_NONAME;
368 }
369
370 if (hints) {
371 family = hints->ai_family;
372 if (hints->ai_socktype == SOCK_DGRAM) {
373 socktype = SOCK_DGRAM;
374 protocol = IPPROTO_UDP;
375 }
376 }
377
378 result = net_ipaddr_parse(host, strlen(host), &res->_ai_addr);
379
380 if (!result) {
381 return DNS_EAI_NONAME;
382 }
383
384 resolved_family = res->_ai_addr.sa_family;
385
386 if ((family != AF_UNSPEC) && (resolved_family != family)) {
387 return DNS_EAI_NONAME;
388 }
389
390 if (service) {
391 port = strtol(service, NULL, 10);
392 if (port < 1 || port > 65535) {
393 return DNS_EAI_NONAME;
394 }
395 }
396
397 res->ai_family = resolved_family;
398 res->ai_socktype = socktype;
399 res->ai_protocol = protocol;
400
401 switch (resolved_family) {
402 case AF_INET:
403 {
404 struct sockaddr_in *addr =
405 (struct sockaddr_in *)&res->_ai_addr;
406
407 INIT_ADDRINFO(res, addr);
408 addr->sin_port = htons(port);
409 addr->sin_family = AF_INET;
410 break;
411 }
412
413 case AF_INET6:
414 {
415 struct sockaddr_in6 *addr =
416 (struct sockaddr_in6 *)&res->_ai_addr;
417
418 INIT_ADDRINFO(res, addr);
419 addr->sin6_port = htons(port);
420 addr->sin6_family = AF_INET6;
421 break;
422 }
423
424 default:
425 return DNS_EAI_NONAME;
426 }
427
428 return 0;
429 }
430 #endif /* CONFIG_NET_IP */
431
zsock_getaddrinfo(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo ** res)432 int zsock_getaddrinfo(const char *host, const char *service,
433 const struct zsock_addrinfo *hints,
434 struct zsock_addrinfo **res)
435 {
436 if (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD)) {
437 return socket_offload_getaddrinfo(host, service, hints, res);
438 }
439
440 int ret = DNS_EAI_FAIL;
441
442 #if defined(ANY_RESOLVER)
443 *res = calloc(AI_ARR_MAX, sizeof(struct zsock_addrinfo));
444 if (!(*res)) {
445 return DNS_EAI_MEMORY;
446 }
447 #endif
448
449 #if defined(CONFIG_NET_IP)
450 /* Resolve literal address even if DNS is not available */
451 if (ret) {
452 ret = try_resolve_literal_addr(host, service, hints, *res);
453 }
454 #endif
455
456 #if defined(CONFIG_DNS_RESOLVER)
457 if (ret) {
458 ret = z_zsock_getaddrinfo_internal(host, service, hints, *res);
459 }
460 #endif
461
462 #if defined(ANY_RESOLVER)
463 if (ret) {
464 free(*res);
465 *res = NULL;
466 }
467 #endif
468
469 return ret;
470 }
471
zsock_freeaddrinfo(struct zsock_addrinfo * ai)472 void zsock_freeaddrinfo(struct zsock_addrinfo *ai)
473 {
474 if (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD)) {
475 return socket_offload_freeaddrinfo(ai);
476 }
477
478 free(ai);
479 }
480
481 #define ERR(e) case DNS_ ## e: return #e
zsock_gai_strerror(int errcode)482 const char *zsock_gai_strerror(int errcode)
483 {
484 switch (errcode) {
485 ERR(EAI_BADFLAGS);
486 ERR(EAI_NONAME);
487 ERR(EAI_AGAIN);
488 ERR(EAI_FAIL);
489 ERR(EAI_NODATA);
490 ERR(EAI_MEMORY);
491 ERR(EAI_SYSTEM);
492 ERR(EAI_SERVICE);
493
494 default:
495 return "EAI_UNKNOWN";
496 }
497 }
498 #undef ERR
499