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/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
exec_query(const char * host,int family,struct getaddrinfo_state * ai_state)106 static int exec_query(const char *host, int family,
107 struct getaddrinfo_state *ai_state)
108 {
109 enum dns_query_type qtype = DNS_QUERY_TYPE_A;
110 int st, ret;
111
112 if (family == AF_INET6) {
113 qtype = DNS_QUERY_TYPE_AAAA;
114 }
115
116 ret = dns_get_addr_info(host, qtype, &ai_state->dns_id,
117 dns_resolve_cb, ai_state,
118 CONFIG_NET_SOCKETS_DNS_TIMEOUT);
119 if (ret == 0) {
120 /* If the DNS query for reason fails so that the
121 * dns_resolve_cb() would not be called, then we want the
122 * semaphore to timeout so that we will not hang forever.
123 * So make the sem timeout longer than the DNS timeout so that
124 * we do not need to start to cancel any pending DNS queries.
125 */
126 ret = k_sem_take(&ai_state->sem, K_MSEC(CONFIG_NET_SOCKETS_DNS_TIMEOUT + 100));
127 if (ret == -EAGAIN) {
128 (void)dns_cancel_addr_info(ai_state->dns_id);
129 st = DNS_EAI_AGAIN;
130 } else {
131 st = ai_state->status;
132 }
133 } else if (ret == -EPFNOSUPPORT) {
134 /* If we are returned -EPFNOSUPPORT then that will indicate
135 * wrong address family type queried. Check that and return
136 * DNS_EAI_ADDRFAMILY.
137 */
138 st = DNS_EAI_ADDRFAMILY;
139 } else {
140 errno = -ret;
141 st = DNS_EAI_SYSTEM;
142 }
143
144 return st;
145 }
146
getaddrinfo_null_host(int port,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)147 static int getaddrinfo_null_host(int port, const struct zsock_addrinfo *hints,
148 struct zsock_addrinfo *res)
149 {
150 if (!hints || !(hints->ai_flags & AI_PASSIVE)) {
151 return DNS_EAI_FAIL;
152 }
153
154 /* For AF_UNSPEC, should we default to IPv6 or IPv4? */
155 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
156 struct sockaddr_in *addr = net_sin(&res->_ai_addr);
157 addr->sin_addr.s_addr = INADDR_ANY;
158 addr->sin_port = htons(port);
159 addr->sin_family = AF_INET;
160 INIT_ADDRINFO(res, addr);
161 res->ai_family = AF_INET;
162 } else if (hints->ai_family == AF_INET6) {
163 struct sockaddr_in6 *addr6 = net_sin6(&res->_ai_addr);
164 addr6->sin6_addr = in6addr_any;
165 addr6->sin6_port = htons(port);
166 addr6->sin6_family = AF_INET6;
167 INIT_ADDRINFO(res, addr6);
168 res->ai_family = AF_INET6;
169 } else {
170 return DNS_EAI_FAIL;
171 }
172
173 if (hints->ai_socktype == SOCK_DGRAM) {
174 res->ai_socktype = SOCK_DGRAM;
175 res->ai_protocol = IPPROTO_UDP;
176 } else {
177 res->ai_socktype = SOCK_STREAM;
178 res->ai_protocol = IPPROTO_TCP;
179 }
180 return 0;
181 }
182
z_impl_z_zsock_getaddrinfo_internal(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)183 int z_impl_z_zsock_getaddrinfo_internal(const char *host, const char *service,
184 const struct zsock_addrinfo *hints,
185 struct zsock_addrinfo *res)
186 {
187 int family = AF_UNSPEC;
188 int ai_flags = 0;
189 long int port = 0;
190 int st1 = DNS_EAI_ADDRFAMILY, st2 = DNS_EAI_ADDRFAMILY;
191 struct sockaddr *ai_addr;
192 struct getaddrinfo_state ai_state;
193
194 if (hints) {
195 family = hints->ai_family;
196 ai_flags = hints->ai_flags;
197
198 if ((family != AF_UNSPEC) && (family != AF_INET) && (family != AF_INET6)) {
199 return DNS_EAI_ADDRFAMILY;
200 }
201 }
202
203 if (ai_flags & AI_NUMERICHOST) {
204 /* Asked to resolve host as numeric, but it wasn't possible
205 * to do that.
206 */
207 return DNS_EAI_FAIL;
208 }
209
210 if (service) {
211 port = strtol(service, NULL, 10);
212 if (port < 1 || port > 65535) {
213 return DNS_EAI_NONAME;
214 }
215 }
216
217 if (host == NULL) {
218 /* Per POSIX, both can't be NULL. */
219 if (service == NULL) {
220 errno = EINVAL;
221 return DNS_EAI_SYSTEM;
222 }
223
224 return getaddrinfo_null_host(port, hints, res);
225 }
226
227 ai_state.hints = hints;
228 ai_state.idx = 0U;
229 ai_state.port = htons(port);
230 ai_state.ai_arr = res;
231 ai_state.dns_id = 0;
232 k_sem_init(&ai_state.sem, 0, K_SEM_MAX_LIMIT);
233
234 /* If family is AF_UNSPEC, then we query IPv4 address first
235 * if IPv4 is enabled in the config.
236 */
237 if ((family != AF_INET6) && IS_ENABLED(CONFIG_NET_IPV4)) {
238 st1 = exec_query(host, AF_INET, &ai_state);
239 if (st1 == DNS_EAI_AGAIN) {
240 return st1;
241 }
242 }
243
244 /* If family is AF_UNSPEC, the IPv4 query has been already done
245 * so we can do IPv6 query next if IPv6 is enabled in the config.
246 */
247 if ((family != AF_INET) && IS_ENABLED(CONFIG_NET_IPV6)) {
248 st2 = exec_query(host, AF_INET6, &ai_state);
249 if (st2 == DNS_EAI_AGAIN) {
250 return st2;
251 }
252 }
253
254 for (uint16_t idx = 0; idx < ai_state.idx; idx++) {
255 ai_addr = &ai_state.ai_arr[idx]._ai_addr;
256 net_sin(ai_addr)->sin_port = htons(port);
257 }
258
259 /* If both attempts failed, it's error */
260 if (st1 && st2) {
261 if (st1 != DNS_EAI_ADDRFAMILY) {
262 return st1;
263 }
264 return st2;
265 }
266
267 /* Mark entry as last */
268 ai_state.ai_arr[ai_state.idx - 1].ai_next = NULL;
269
270 return 0;
271 }
272
273 #ifdef CONFIG_USERSPACE
z_vrfy_z_zsock_getaddrinfo_internal(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)274 static inline int z_vrfy_z_zsock_getaddrinfo_internal(const char *host,
275 const char *service,
276 const struct zsock_addrinfo *hints,
277 struct zsock_addrinfo *res)
278 {
279 struct zsock_addrinfo hints_copy;
280 char *host_copy = NULL, *service_copy = NULL;
281 uint32_t ret;
282
283 if (hints) {
284 Z_OOPS(z_user_from_copy(&hints_copy, (void *)hints,
285 sizeof(hints_copy)));
286 }
287 Z_OOPS(Z_SYSCALL_MEMORY_ARRAY_WRITE(res, AI_ARR_MAX, sizeof(struct zsock_addrinfo)));
288
289 if (service) {
290 service_copy = z_user_string_alloc_copy((char *)service, 64);
291 if (!service_copy) {
292 ret = DNS_EAI_MEMORY;
293 goto out;
294 }
295 }
296
297 if (host) {
298 host_copy = z_user_string_alloc_copy((char *)host, 64);
299 if (!host_copy) {
300 ret = DNS_EAI_MEMORY;
301 goto out;
302 }
303 }
304
305 ret = z_impl_z_zsock_getaddrinfo_internal(host_copy, service_copy,
306 hints ? &hints_copy : NULL,
307 (struct zsock_addrinfo *)res);
308 out:
309 k_free(service_copy);
310 k_free(host_copy);
311
312 return ret;
313 }
314 #include <syscalls/z_zsock_getaddrinfo_internal_mrsh.c>
315 #endif /* CONFIG_USERSPACE */
316
317 #endif /* defined(CONFIG_DNS_RESOLVER) */
318
319 #if defined(CONFIG_NET_IP)
try_resolve_literal_addr(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo * res)320 static int try_resolve_literal_addr(const char *host, const char *service,
321 const struct zsock_addrinfo *hints,
322 struct zsock_addrinfo *res)
323 {
324 int family = AF_UNSPEC;
325 int resolved_family = AF_UNSPEC;
326 long port = 0;
327 bool result;
328 int socktype = SOCK_STREAM;
329 int protocol = IPPROTO_TCP;
330
331 if (!host) {
332 return DNS_EAI_NONAME;
333 }
334
335 if (hints) {
336 family = hints->ai_family;
337 if (hints->ai_socktype == SOCK_DGRAM) {
338 socktype = SOCK_DGRAM;
339 protocol = IPPROTO_UDP;
340 }
341 }
342
343 result = net_ipaddr_parse(host, strlen(host), &res->_ai_addr);
344
345 if (!result) {
346 return DNS_EAI_NONAME;
347 }
348
349 resolved_family = res->_ai_addr.sa_family;
350
351 if ((family != AF_UNSPEC) && (resolved_family != family)) {
352 return DNS_EAI_NONAME;
353 }
354
355 if (service) {
356 port = strtol(service, NULL, 10);
357 if (port < 1 || port > 65535) {
358 return DNS_EAI_NONAME;
359 }
360 }
361
362 res->ai_family = resolved_family;
363 res->ai_socktype = socktype;
364 res->ai_protocol = protocol;
365
366 switch (resolved_family) {
367 case AF_INET:
368 {
369 struct sockaddr_in *addr =
370 (struct sockaddr_in *)&res->_ai_addr;
371
372 INIT_ADDRINFO(res, addr);
373 addr->sin_port = htons(port);
374 addr->sin_family = AF_INET;
375 break;
376 }
377
378 case AF_INET6:
379 {
380 struct sockaddr_in6 *addr =
381 (struct sockaddr_in6 *)&res->_ai_addr;
382
383 INIT_ADDRINFO(res, addr);
384 addr->sin6_port = htons(port);
385 addr->sin6_family = AF_INET6;
386 break;
387 }
388
389 default:
390 return DNS_EAI_NONAME;
391 }
392
393 return 0;
394 }
395 #endif /* CONFIG_NET_IP */
396
zsock_getaddrinfo(const char * host,const char * service,const struct zsock_addrinfo * hints,struct zsock_addrinfo ** res)397 int zsock_getaddrinfo(const char *host, const char *service,
398 const struct zsock_addrinfo *hints,
399 struct zsock_addrinfo **res)
400 {
401 if (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD)) {
402 return socket_offload_getaddrinfo(host, service, hints, res);
403 }
404
405 int ret = DNS_EAI_FAIL;
406
407 #if defined(ANY_RESOLVER)
408 *res = calloc(AI_ARR_MAX, sizeof(struct zsock_addrinfo));
409 if (!(*res)) {
410 return DNS_EAI_MEMORY;
411 }
412 #endif
413
414 #if defined(CONFIG_NET_IP)
415 /* Resolve literal address even if DNS is not available */
416 if (ret) {
417 ret = try_resolve_literal_addr(host, service, hints, *res);
418 }
419 #endif
420
421 #if defined(CONFIG_DNS_RESOLVER)
422 if (ret) {
423 ret = z_zsock_getaddrinfo_internal(host, service, hints, *res);
424 }
425 #endif
426
427 #if defined(ANY_RESOLVER)
428 if (ret) {
429 free(*res);
430 *res = NULL;
431 }
432 #endif
433
434 return ret;
435 }
436
zsock_freeaddrinfo(struct zsock_addrinfo * ai)437 void zsock_freeaddrinfo(struct zsock_addrinfo *ai)
438 {
439 if (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD)) {
440 return socket_offload_freeaddrinfo(ai);
441 }
442
443 free(ai);
444 }
445
446 #define ERR(e) case DNS_ ## e: return #e
zsock_gai_strerror(int errcode)447 const char *zsock_gai_strerror(int errcode)
448 {
449 switch (errcode) {
450 ERR(EAI_BADFLAGS);
451 ERR(EAI_NONAME);
452 ERR(EAI_AGAIN);
453 ERR(EAI_FAIL);
454 ERR(EAI_NODATA);
455 ERR(EAI_MEMORY);
456 ERR(EAI_SYSTEM);
457 ERR(EAI_SERVICE);
458
459 default:
460 return "EAI_UNKNOWN";
461 }
462 }
463 #undef ERR
464