1 /* coap_address.c -- representation of network addresses
2 *
3 * Copyright (C) 2015-2016,2019-2023 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 /**
12 * @file coap_address.c
13 * @brief Handling of network addresses
14 */
15
16 #include "coap3/coap_internal.h"
17
18 #if !defined(WITH_CONTIKI) && !defined(WITH_LWIP)
19 #ifdef HAVE_ARPA_INET_H
20 #include <arpa/inet.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 #include <netinet/in.h>
24 #endif
25 #ifdef HAVE_SYS_SOCKET_H
26 #include <sys/socket.h>
27 #endif
28 #ifdef HAVE_NET_IF_H
29 #include <net/if.h>
30 #endif
31 #ifdef HAVE_IFADDRS_H
32 #include <ifaddrs.h>
33 #endif
34 #ifdef HAVE_WS2TCPIP_H
35 #include <ws2tcpip.h>
36 #endif
37
38 #ifdef RIOT_VERSION
39 /* FIXME */
40 #define IN_MULTICAST(Address) (0)
41 #endif /* RIOT_VERSION */
42
43 uint16_t
coap_address_get_port(const coap_address_t * addr)44 coap_address_get_port(const coap_address_t *addr) {
45 assert(addr != NULL);
46 switch (addr->addr.sa.sa_family) {
47 #if COAP_IPV4_SUPPORT
48 case AF_INET:
49 return ntohs(addr->addr.sin.sin_port);
50 #endif /* COAP_IPV4_SUPPORT */
51 #if COAP_IPV6_SUPPORT
52 case AF_INET6:
53 return ntohs(addr->addr.sin6.sin6_port);
54 #endif /* COAP_IPV6_SUPPORT */
55 default: /* undefined */
56 ;
57 }
58 return 0;
59 }
60
61 void
coap_address_set_port(coap_address_t * addr,uint16_t port)62 coap_address_set_port(coap_address_t *addr, uint16_t port) {
63 assert(addr != NULL);
64 switch (addr->addr.sa.sa_family) {
65 #if COAP_IPV4_SUPPORT
66 case AF_INET:
67 addr->addr.sin.sin_port = htons(port);
68 break;
69 #endif /* COAP_IPV4_SUPPORT */
70 #if COAP_IPV6_SUPPORT
71 case AF_INET6:
72 addr->addr.sin6.sin6_port = htons(port);
73 break;
74 #endif /* COAP_IPV6_SUPPORT */
75 default: /* undefined */
76 ;
77 }
78 }
79
80 int
coap_address_equals(const coap_address_t * a,const coap_address_t * b)81 coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
82 assert(a);
83 assert(b);
84
85 if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family)
86 return 0;
87
88 /* need to compare only relevant parts of sockaddr_in6 */
89 switch (a->addr.sa.sa_family) {
90 #if COAP_IPV4_SUPPORT
91 case AF_INET:
92 return a->addr.sin.sin_port == b->addr.sin.sin_port &&
93 memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr,
94 sizeof(struct in_addr)) == 0;
95 #endif /* COAP_IPV4_SUPPORT */
96 #if COAP_IPV6_SUPPORT
97 case AF_INET6:
98 return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port &&
99 memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr,
100 sizeof(struct in6_addr)) == 0;
101 #endif /* COAP_IPV6_SUPPORT */
102 default: /* fall through and signal error */
103 ;
104 }
105 return 0;
106 }
107
108 int
coap_is_af_unix(const coap_address_t * a)109 coap_is_af_unix(const coap_address_t *a) {
110 #if COAP_AF_UNIX_SUPPORT
111 return a->addr.sa.sa_family == AF_UNIX;
112 #else /* ! COAP_AF_UNIX_SUPPORT */
113 (void)a;
114 return 0;
115 #endif /* ! COAP_AF_UNIX_SUPPORT */
116 }
117
118 int
coap_is_mcast(const coap_address_t * a)119 coap_is_mcast(const coap_address_t *a) {
120 if (!a)
121 return 0;
122
123 /* Treat broadcast in same way as multicast */
124 if (coap_is_bcast(a))
125 return 1;
126
127 switch (a->addr.sa.sa_family) {
128 #if COAP_IPV4_SUPPORT
129 case AF_INET:
130 return IN_MULTICAST(ntohl(a->addr.sin.sin_addr.s_addr));
131 #endif /* COAP_IPV4_SUPPORT */
132 #if COAP_IPV6_SUPPORT
133 case AF_INET6:
134 #if COAP_IPV4_SUPPORT
135 return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr) ||
136 (IN6_IS_ADDR_V4MAPPED(&a->addr.sin6.sin6_addr) &&
137 IN_MULTICAST(ntohl(a->addr.sin6.sin6_addr.s6_addr[12])));
138 #else /* ! COAP_IPV4_SUPPORT */
139 return a->addr.sin6.sin6_addr.s6_addr[0] == 0xff;
140 #endif /* ! COAP_IPV4_SUPPORT */
141 #endif /* COAP_IPV6_SUPPORT */
142 default: /* fall through and signal not multicast */
143 ;
144 }
145 return 0;
146 }
147
148 #ifndef COAP_BCST_CNT
149 #define COAP_BCST_CNT 15
150 #endif /* COAP_BCST_CNT */
151
152 /* How frequently to refresh the list of valid IPv4 broadcast addresses */
153 #ifndef COAP_BCST_REFRESH_SECS
154 #define COAP_BCST_REFRESH_SECS 30
155 #endif /* COAP_BCST_REFRESH_SECS */
156
157 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
coap_is_bcast(const coap_address_t * a)158 int coap_is_bcast(const coap_address_t *a) {
159 if (a == NULL)
160 return 0;
161 switch(a->addr.sa.sa_family) {
162 case AF_INET:
163 if (a->addr.sin.sin_addr.s_addr == 0xFFFFFFFF)
164 return 1;
165 else
166 return 0;
167 case AF_INET6: /* broadcast not support ipv6 now */
168 default:
169 return 0;
170 }
171 }
172 #else /* !COAP_SUPPORT_SOCKET_BROADCAST */
173 #if COAP_IPV4_SUPPORT && defined(HAVE_IFADDRS_H)
174 static int bcst_cnt = -1;
175 static coap_tick_t last_refresh;
176 static struct in_addr b_ipv4[COAP_BCST_CNT];
177 #endif /* COAP_IPV4_SUPPORT && HAVE_IFADDRS_H */
178
179 int
coap_is_bcast(const coap_address_t * a)180 coap_is_bcast(const coap_address_t *a) {
181 #if COAP_IPV4_SUPPORT
182 struct in_addr ipv4;
183 #if defined(HAVE_IFADDRS_H)
184 int i;
185 coap_tick_t now;
186 #endif /* HAVE_IFADDRS_H */
187 #endif /* COAP_IPV4_SUPPORT */
188
189 if (!a)
190 return 0;
191
192 switch (a->addr.sa.sa_family) {
193 #if COAP_IPV4_SUPPORT
194 case AF_INET:
195 ipv4.s_addr = a->addr.sin.sin_addr.s_addr;
196 break;
197 #endif /* COAP_IPV4_SUPPORT */
198 #if COAP_IPV6_SUPPORT
199 case AF_INET6:
200 #if COAP_IPV4_SUPPORT
201 if (IN6_IS_ADDR_V4MAPPED(&a->addr.sin6.sin6_addr)) {
202 memcpy(&ipv4, &a->addr.sin6.sin6_addr.s6_addr[12], sizeof(ipv4));
203 break;
204 }
205 #endif /* COAP_IPV4_SUPPORT */
206 /* IPv6 does not support broadcast */
207 return 0;
208 #endif /* COAP_IPV6_SUPPORT */
209 default:
210 return 0;
211 }
212 #if COAP_IPV4_SUPPORT
213 #ifndef INADDR_BROADCAST
214 #define INADDR_BROADCAST ((uint32_t)0xffffffffUL)
215 #endif /* !INADDR_BROADCAST */
216 if (ipv4.s_addr == INADDR_BROADCAST)
217 return 1;
218
219 #if defined(HAVE_IFADDRS_H)
220 coap_ticks(&now);
221 if (bcst_cnt == -1 ||
222 (now - last_refresh) > (COAP_BCST_REFRESH_SECS * COAP_TICKS_PER_SECOND)) {
223 /* Determine the list of broadcast interfaces */
224 struct ifaddrs *ifa = NULL;
225 struct ifaddrs *ife;
226
227 if (getifaddrs(&ifa) != 0) {
228 coap_log_warn("coap_is_bcst: Cannot determine any broadcast addresses\n");
229 return 0;
230 }
231 bcst_cnt = 0;
232 last_refresh = now;
233 ife = ifa;
234 while (ife && bcst_cnt < COAP_BCST_CNT) {
235 if (ife->ifa_addr && ife->ifa_addr->sa_family == AF_INET &&
236 ife->ifa_flags & IFF_BROADCAST) {
237 b_ipv4[bcst_cnt].s_addr = ((struct sockaddr_in *)ife->ifa_broadaddr)->sin_addr.s_addr;
238 bcst_cnt++;
239 }
240 ife = ife->ifa_next;
241 }
242 if (ife) {
243 coap_log_warn("coap_is_bcst: Insufficient space for broadcast addresses\n");
244 }
245 freeifaddrs(ifa);
246 }
247 for (i = 0; i < bcst_cnt; i++) {
248 if (ipv4.s_addr == b_ipv4[i].s_addr)
249 return 1;
250 }
251 #endif /* HAVE_IFADDRS_H */
252 return 0;
253 #endif /* COAP_IPV4_SUPPORT */
254 }
255 #endif /* COAP_SUPPORT_SOCKET_BROADCAST */
256 #endif /* !defined(WITH_CONTIKI) && !defined(WITH_LWIP) */
257
258 void
coap_address_init(coap_address_t * addr)259 coap_address_init(coap_address_t *addr) {
260 assert(addr);
261 memset(addr, 0, sizeof(coap_address_t));
262 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
263 /* lwip and Contiki have constant address sizes and don't need the .size part */
264 addr->size = sizeof(addr->addr);
265 #endif
266 }
267
268 void
coap_address_ntop(const coap_address_t * addr,char * dst,int len)269 coap_address_ntop(const coap_address_t *addr, char *dst, int len) {
270 if ((addr == NULL) || (dst == NULL) || (len < INET6_ADDRSTRLEN))
271 return;
272 #if defined(WITH_LWIP)
273 (void)ipaddr_ntoa_r(&(addr->addr), dst, len);
274 #elif defined(WITH_CONTIKI)
275 coap_log_warn("coap_address_ntop: contiki not supported");
276 #else
277 if (addr->addr.sa.sa_family == AF_INET) {
278 const void *addrptr = &addr->addr.sin.sin_addr;
279 (void)inet_ntop(addr->addr.sa.sa_family, addrptr, dst, len);
280 } else if (addr->addr.sa.sa_family == AF_INET6) {
281 const void *addrptr = &addr->addr.sin6.sin6_addr;
282 (void)inet_ntop(addr->addr.sa.sa_family, addrptr, dst, len);
283 } else {
284 coap_log_warn("coap_address_ntop: not support other sa_family");
285 }
286 #endif
287 }
288
289 int
coap_address_set_unix_domain(coap_address_t * addr,const uint8_t * host,size_t host_len)290 coap_address_set_unix_domain(coap_address_t *addr,
291 const uint8_t *host, size_t host_len) {
292 #if COAP_AF_UNIX_SUPPORT
293 size_t i;
294 size_t ofs = 0;
295
296 coap_address_init(addr);
297 addr->addr.cun.sun_family = AF_UNIX;
298 for (i = 0; i < host_len; i++) {
299 if ((host_len - i) >= 3 && host[i] == '%' && host[i+1] == '2' &&
300 (host[i+2] == 'F' || host[i+2] == 'f')) {
301 addr->addr.cun.sun_path[ofs++] = '/';
302 i += 2;
303 } else {
304 addr->addr.cun.sun_path[ofs++] = host[i];
305 }
306 if (ofs == COAP_UNIX_PATH_MAX)
307 break;
308 }
309 if (ofs < COAP_UNIX_PATH_MAX)
310 addr->addr.cun.sun_path[ofs] = '\000';
311 else
312 addr->addr.cun.sun_path[ofs-1] = '\000';
313 return 1;
314 #else /* ! COAP_AF_UNIX_SUPPORT */
315 (void)addr;
316 (void)host;
317 (void)host_len;
318 return 0;
319 #endif /* ! COAP_AF_UNIX_SUPPORT */
320 }
321
322 #if !defined(WITH_CONTIKI)
323 static void
update_port(coap_address_t * addr,uint16_t port,uint16_t default_port,int update_port0)324 update_port(coap_address_t *addr, uint16_t port, uint16_t default_port,
325 int update_port0) {
326 /* Client target port must be set if default of 0 */
327 if (port == 0 && update_port0)
328 port = default_port;
329
330 coap_address_set_port(addr, port);
331 return;
332 }
333
334 #ifdef HAVE_NETDB_H
335 #include <netdb.h>
336 #endif
337
338 uint32_t
coap_get_available_scheme_hint_bits(int have_pki_psk,int ws_check,coap_proto_t use_unix_proto)339 coap_get_available_scheme_hint_bits(int have_pki_psk, int ws_check,
340 coap_proto_t use_unix_proto) {
341 uint32_t scheme_hint_bits = 0;
342 coap_uri_scheme_t scheme;
343
344 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
345 switch (scheme) {
346 case COAP_URI_SCHEME_COAP:
347 scheme_hint_bits |= 1 << scheme;
348 break;
349 case COAP_URI_SCHEME_COAPS:
350 if (!(coap_dtls_is_supported() && have_pki_psk))
351 continue;
352 scheme_hint_bits |= 1 << scheme;
353 break;
354 case COAP_URI_SCHEME_COAP_TCP:
355 if (!coap_tcp_is_supported())
356 continue;
357 scheme_hint_bits |= 1 << scheme;
358 break;
359 case COAP_URI_SCHEME_COAPS_TCP:
360 if (!(coap_tls_is_supported() && have_pki_psk))
361 continue;
362 scheme_hint_bits |= 1 << scheme;
363 break;
364 case COAP_URI_SCHEME_COAP_WS:
365 if (!ws_check || !coap_ws_is_supported())
366 continue;
367 scheme_hint_bits |= 1 << scheme;
368 break;
369 case COAP_URI_SCHEME_COAPS_WS:
370 if (!ws_check || !(coap_wss_is_supported() && have_pki_psk))
371 continue;
372 scheme_hint_bits |= 1 << scheme;
373 break;
374 case COAP_URI_SCHEME_HTTP:
375 case COAP_URI_SCHEME_HTTPS:
376 case COAP_URI_SCHEME_LAST:
377 default:
378 continue;
379 }
380 }
381
382 switch (use_unix_proto) {
383 /* For AF_UNIX, can only listen on a single endpoint */
384 case COAP_PROTO_UDP:
385 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP;
386 break;
387 case COAP_PROTO_TCP:
388 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_TCP;
389 break;
390 case COAP_PROTO_DTLS:
391 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS;
392 break;
393 case COAP_PROTO_TLS:
394 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_TCP;
395 break;
396 case COAP_PROTO_WS:
397 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_WS;
398 break;
399 case COAP_PROTO_WSS:
400 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_WS;
401 break;
402 case COAP_PROTO_NONE: /* If use_unix_proto was not defined */
403 case COAP_PROTO_LAST:
404 default:
405 break;
406 }
407 return scheme_hint_bits;
408 }
409
410 coap_addr_info_t *
coap_resolve_address_info(const coap_str_const_t * address,uint16_t port,uint16_t secure_port,uint16_t ws_port,uint16_t ws_secure_port,int ai_hints_flags,int scheme_hint_bits,coap_resolve_type_t type)411 coap_resolve_address_info(const coap_str_const_t *address,
412 uint16_t port,
413 uint16_t secure_port,
414 uint16_t ws_port,
415 uint16_t ws_secure_port,
416 int ai_hints_flags,
417 int scheme_hint_bits,
418 coap_resolve_type_t type) {
419 #if !defined(RIOT_VERSION)
420
421 struct addrinfo *res, *ainfo;
422 struct addrinfo hints;
423 static char addrstr[256];
424 int error;
425 coap_addr_info_t *info = NULL;
426 coap_addr_info_t *info_prev = NULL;
427 coap_addr_info_t *info_list = NULL;
428 coap_addr_info_t *info_tmp;
429 coap_uri_scheme_t scheme;
430 coap_proto_t proto = 0;
431
432 #if COAP_AF_UNIX_SUPPORT
433 if (address && coap_host_is_unix_domain(address)) {
434 /* There can only be one unique filename entry for AF_UNIX */
435 if (address->length >= COAP_UNIX_PATH_MAX) {
436 coap_log_err("Unix Domain host too long\n");
437 return NULL;
438 }
439 /* Need to chose the first defined one in scheme_hint_bits */
440 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
441 if (scheme_hint_bits & (1 << scheme)) {
442 break;
443 }
444 }
445 if (scheme == COAP_URI_SCHEME_LAST) {
446 return NULL;
447 }
448 switch (scheme) {
449 case COAP_URI_SCHEME_COAP:
450 proto = COAP_PROTO_UDP;
451 break;
452 case COAP_URI_SCHEME_COAPS:
453 if (!coap_dtls_is_supported())
454 return NULL;
455 proto = COAP_PROTO_DTLS;
456 break;
457 case COAP_URI_SCHEME_COAP_TCP:
458 if (!coap_tcp_is_supported())
459 return NULL;
460 proto = COAP_PROTO_TCP;
461 break;
462 case COAP_URI_SCHEME_COAPS_TCP:
463 if (!coap_tls_is_supported())
464 return NULL;
465 proto = COAP_PROTO_TLS;
466 break;
467 case COAP_URI_SCHEME_HTTP:
468 if (!coap_tcp_is_supported())
469 return NULL;
470 proto = COAP_PROTO_NONE;
471 break;
472 case COAP_URI_SCHEME_HTTPS:
473 if (!coap_tls_is_supported())
474 return NULL;
475 proto = COAP_PROTO_NONE;
476 break;
477 case COAP_URI_SCHEME_COAP_WS:
478 if (!coap_ws_is_supported())
479 return NULL;
480 proto = COAP_PROTO_WS;
481 break;
482 case COAP_URI_SCHEME_COAPS_WS:
483 if (!coap_wss_is_supported())
484 return NULL;
485 proto = COAP_PROTO_WSS;
486 break;
487 case COAP_URI_SCHEME_LAST:
488 default:
489 return NULL;
490 }
491 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
492 if (info == NULL)
493 return NULL;
494 info->next = NULL;
495 info->proto = proto;
496 info->scheme = scheme;
497
498 coap_address_init(&info->addr);
499 if (!coap_address_set_unix_domain(&info->addr, address->s,
500 address->length)) {
501 coap_free_type(COAP_STRING, info);
502 return NULL;
503 }
504 return info;
505 }
506 #endif /* COAP_AF_UNIX_SUPPORT */
507
508 memset(addrstr, 0, sizeof(addrstr));
509 if (address && address->length)
510 memcpy(addrstr, address->s, address->length);
511 else
512 memcpy(addrstr, "localhost", 9);
513
514 memset((char *)&hints, 0, sizeof(hints));
515 hints.ai_socktype = 0;
516 hints.ai_family = AF_UNSPEC;
517 hints.ai_flags = ai_hints_flags;
518
519 error = getaddrinfo(addrstr, NULL, &hints, &res);
520
521 if (error != 0) {
522 coap_log_warn("getaddrinfo: %s\n", gai_strerror(error));
523 return NULL;
524 }
525
526 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
527 #if !defined(WITH_LWIP)
528 if (ainfo->ai_addrlen > (socklen_t)sizeof(info->addr.addr))
529 continue;
530 #endif /* ! WITH_LWIP */
531
532 switch (ainfo->ai_family) {
533 #if COAP_IPV4_SUPPORT
534 case AF_INET:
535 #endif /* COAP_IPV4_SUPPORT */
536 #if COAP_IPV6_SUPPORT
537 case AF_INET6:
538 #endif /* COAP_IPV6_SUPPORT */
539 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
540 if (scheme_hint_bits & (1 << scheme)) {
541 switch (scheme) {
542 case COAP_URI_SCHEME_COAP:
543 proto = COAP_PROTO_UDP;
544 break;
545 case COAP_URI_SCHEME_COAPS:
546 if (!coap_dtls_is_supported())
547 continue;
548 proto = COAP_PROTO_DTLS;
549 break;
550 case COAP_URI_SCHEME_COAP_TCP:
551 if (!coap_tcp_is_supported())
552 continue;
553 proto = COAP_PROTO_TCP;
554 break;
555 case COAP_URI_SCHEME_COAPS_TCP:
556 if (!coap_tls_is_supported())
557 continue;
558 proto = COAP_PROTO_TLS;
559 break;
560 case COAP_URI_SCHEME_HTTP:
561 if (!coap_tcp_is_supported())
562 continue;
563 proto = COAP_PROTO_NONE;
564 break;
565 case COAP_URI_SCHEME_HTTPS:
566 if (!coap_tls_is_supported())
567 continue;
568 proto = COAP_PROTO_NONE;
569 break;
570 case COAP_URI_SCHEME_COAP_WS:
571 if (!coap_ws_is_supported())
572 continue;
573 proto = COAP_PROTO_WS;
574 break;
575 case COAP_URI_SCHEME_COAPS_WS:
576 if (!coap_wss_is_supported())
577 continue;
578 proto = COAP_PROTO_WSS;
579 break;
580 case COAP_URI_SCHEME_LAST:
581 default:
582 continue;
583 }
584
585 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
586 if (info == NULL) {
587 freeaddrinfo(res);
588 /* malloc failure - return what we have so far */
589 return info_list;
590 }
591
592 info->next = NULL;
593 info->scheme = scheme;
594 info->proto = proto;
595 coap_address_init(&info->addr);
596 #if !defined(WITH_LWIP)
597 info->addr.size = (socklen_t)ainfo->ai_addrlen;
598 memcpy(&info->addr.addr, ainfo->ai_addr, ainfo->ai_addrlen);
599 #else /* WITH_LWIP */
600 memset(&info->addr, 0, sizeof(info->addr));
601 switch (ainfo->ai_family) {
602 #if COAP_IPV6_SUPPORT
603 struct sockaddr_in6 *sock6;
604 #endif /* COAP_IPV6_SUPPORT */
605 #if COAP_IPV4_SUPPORT
606 struct sockaddr_in *sock4;
607 case AF_INET:
608 sock4 = (struct sockaddr_in *)ainfo->ai_addr;
609 info->addr.port = ntohs(sock4->sin_port);
610 memcpy(&info->addr.addr, &sock4->sin_addr, 4);
611 #if LWIP_IPV6
612 info->addr.addr.type = IPADDR_TYPE_V4;
613 #endif /* LWIP_IPV6 */
614 break;
615 #endif /* COAP_IPV4_SUPPORT */
616 #if COAP_IPV6_SUPPORT
617 case AF_INET6:
618 sock6 = (struct sockaddr_in6 *)ainfo->ai_addr;
619 info->addr.port = ntohs(sock6->sin6_port);
620 memcpy(&info->addr.addr, &sock6->sin6_addr, 16);
621 #if LWIP_IPV6 && LWIP_IPV4
622 info->addr.addr.type = IPADDR_TYPE_V6;
623 #endif /* LWIP_IPV6 && LWIP_IPV4 */
624 break;
625 #endif /* COAP_IPV6_SUPPORT */
626 default:
627 ;
628 }
629 #endif /* WITH_LWIP */
630 switch (scheme) {
631 case COAP_URI_SCHEME_COAP:
632 update_port(&info->addr, port, COAP_DEFAULT_PORT,
633 type == COAP_RESOLVE_TYPE_LOCAL);
634 break;
635 case COAP_URI_SCHEME_COAPS:
636 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
637 type == COAP_RESOLVE_TYPE_LOCAL);
638 break;
639 case COAP_URI_SCHEME_COAP_TCP:
640 update_port(&info->addr, port, COAP_DEFAULT_PORT,
641 type == COAP_RESOLVE_TYPE_LOCAL);
642 break;
643 case COAP_URI_SCHEME_COAPS_TCP:
644 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
645 type == COAP_RESOLVE_TYPE_LOCAL);
646 break;
647 case COAP_URI_SCHEME_HTTP:
648 update_port(&info->addr, port, 80,
649 type == COAP_RESOLVE_TYPE_LOCAL);
650 break;
651 case COAP_URI_SCHEME_HTTPS:
652 update_port(&info->addr, secure_port, 443,
653 type == COAP_RESOLVE_TYPE_LOCAL);
654 break;
655 case COAP_URI_SCHEME_COAP_WS:
656 update_port(&info->addr, ws_port, 80,
657 type == COAP_RESOLVE_TYPE_LOCAL);
658 break;
659 case COAP_URI_SCHEME_COAPS_WS:
660 update_port(&info->addr, ws_secure_port, 443,
661 type == COAP_RESOLVE_TYPE_LOCAL);
662 break;
663 case COAP_URI_SCHEME_LAST:
664 default:
665 break;
666 }
667
668 /* Check there are no duplications */
669 info_tmp = info_list;
670 while (info_tmp) {
671 if (info_tmp->proto == info->proto &&
672 info_tmp->scheme == info->scheme &&
673 coap_address_equals(&info_tmp->addr, &info->addr)) {
674 break;
675 }
676 info_tmp = info_tmp->next;
677 }
678
679 if (info_tmp) {
680 /* Duplicate */
681 coap_free_type(COAP_STRING, info);
682 } else {
683 /* Need to return in same order as getaddrinfo() */
684 if (!info_prev) {
685 info_list = info;
686 info_prev = info;
687 } else {
688 info_prev->next = info;
689 info_prev = info;
690 }
691 }
692 }
693 }
694 break;
695 default:
696 break;
697 }
698 }
699
700 freeaddrinfo(res);
701 return info_list;
702 #else /* RIOT_VERSION */
703 #if COAP_IPV6_SUPPORT
704 #include "net/utils.h"
705 ipv6_addr_t addr_ipv6;
706 netif_t *netif = NULL;
707 coap_addr_info_t *info = NULL;
708 coap_addr_info_t *info_prev = NULL;
709 coap_addr_info_t *info_list = NULL;
710 coap_uri_scheme_t scheme;
711 coap_proto_t proto = 0;
712 (void)ai_hints_flags;
713
714 if (netutils_get_ipv6(&addr_ipv6, &netif, (const char *)address->s) >= 0) {
715 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
716 if (scheme_hint_bits & (1 << scheme)) {
717 switch (scheme) {
718 case COAP_URI_SCHEME_COAP:
719 proto = COAP_PROTO_UDP;
720 break;
721 case COAP_URI_SCHEME_COAPS:
722 if (!coap_dtls_is_supported())
723 continue;
724 proto = COAP_PROTO_DTLS;
725 break;
726 case COAP_URI_SCHEME_COAP_TCP:
727 if (!coap_tcp_is_supported())
728 continue;
729 proto = COAP_PROTO_TCP;
730 break;
731 case COAP_URI_SCHEME_COAPS_TCP:
732 if (!coap_tls_is_supported())
733 continue;
734 proto = COAP_PROTO_TLS;
735 break;
736 case COAP_URI_SCHEME_HTTP:
737 if (!coap_tcp_is_supported())
738 continue;
739 proto = COAP_PROTO_NONE;
740 break;
741 case COAP_URI_SCHEME_HTTPS:
742 if (!coap_tls_is_supported())
743 continue;
744 proto = COAP_PROTO_NONE;
745 break;
746 case COAP_URI_SCHEME_COAP_WS:
747 if (!coap_ws_is_supported())
748 continue;
749 proto = COAP_PROTO_WS;
750 break;
751 case COAP_URI_SCHEME_COAPS_WS:
752 if (!coap_wss_is_supported())
753 continue;
754 proto = COAP_PROTO_WSS;
755 break;
756 case COAP_URI_SCHEME_LAST:
757 default:
758 continue;
759 }
760
761 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
762 if (info == NULL) {
763 /* malloc failure - return what we have so far */
764 return info_list;
765 }
766 info->next = NULL;
767 /* Need to return in same order as getaddrinfo() */
768 if (!info_prev) {
769 info_list = info;
770 info_prev = info;
771 } else {
772 info_prev->next = info;
773 info_prev = info;
774 }
775
776 info->scheme = scheme;
777 info->proto = proto;
778 coap_address_init(&info->addr);
779 info->addr.size = sizeof(struct sockaddr_in6);
780 info->addr.addr.sin6.sin6_family = AF_INET6;
781 memcpy(&info->addr.addr.sin6.sin6_addr, &addr_ipv6,
782 sizeof(info->addr.addr.sin6.sin6_addr));
783 info->addr.addr.sin6.sin6_scope_id = (uint32_t)netif_get_id(netif);
784 switch (scheme) {
785 case COAP_URI_SCHEME_COAP:
786 update_port(&info->addr, port, COAP_DEFAULT_PORT,
787 type == COAP_RESOLVE_TYPE_LOCAL);
788 break;
789 case COAP_URI_SCHEME_COAPS:
790 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
791 type == COAP_RESOLVE_TYPE_LOCAL);
792 break;
793 case COAP_URI_SCHEME_COAP_TCP:
794 update_port(&info->addr, port, COAP_DEFAULT_PORT,
795 type == COAP_RESOLVE_TYPE_LOCAL);
796 break;
797 case COAP_URI_SCHEME_COAPS_TCP:
798 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
799 type == COAP_RESOLVE_TYPE_LOCAL);
800 break;
801 case COAP_URI_SCHEME_HTTP:
802 update_port(&info->addr, port, ws_port,
803 type == COAP_RESOLVE_TYPE_LOCAL);
804 break;
805 case COAP_URI_SCHEME_HTTPS:
806 update_port(&info->addr, secure_port, ws_secure_port,
807 type == COAP_RESOLVE_TYPE_LOCAL);
808 break;
809 case COAP_URI_SCHEME_LAST:
810 default:
811 break;
812 }
813 }
814 }
815 return info_list;
816 }
817 #endif /* COAP_IPV6_SUPPORT */
818 return NULL;
819 #endif /* RIOT_VERSION */
820 }
821 #endif /* !WITH_CONTIKI */
822
823 void
coap_free_address_info(coap_addr_info_t * info)824 coap_free_address_info(coap_addr_info_t *info) {
825 while (info) {
826 coap_addr_info_t *info_next = info->next;
827
828 coap_free_type(COAP_STRING, info);
829 info = info_next;
830 }
831 }
832
833 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
834 void
coap_address_copy(coap_address_t * dst,const coap_address_t * src)835 coap_address_copy(coap_address_t *dst, const coap_address_t *src) {
836 #if defined(WITH_LWIP) || defined(WITH_CONTIKI)
837 memcpy(dst, src, sizeof(coap_address_t));
838 #else
839 memset(dst, 0, sizeof(coap_address_t));
840 dst->size = src->size;
841 #if COAP_IPV6_SUPPORT
842 if (src->addr.sa.sa_family == AF_INET6) {
843 dst->addr.sin6.sin6_family = src->addr.sin6.sin6_family;
844 dst->addr.sin6.sin6_addr = src->addr.sin6.sin6_addr;
845 dst->addr.sin6.sin6_port = src->addr.sin6.sin6_port;
846 dst->addr.sin6.sin6_scope_id = src->addr.sin6.sin6_scope_id;
847 }
848 #endif /* COAP_IPV6_SUPPORT */
849 #if COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT
850 else
851 #endif /* COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT */
852 #if COAP_IPV4_SUPPORT
853 if (src->addr.sa.sa_family == AF_INET) {
854 dst->addr.sin = src->addr.sin;
855 }
856 #endif /* COAP_IPV4_SUPPORT */
857 else {
858 memcpy(&dst->addr, &src->addr, src->size);
859 }
860 #endif
861 }
862
863 int
_coap_address_isany_impl(const coap_address_t * a)864 _coap_address_isany_impl(const coap_address_t *a) {
865 /* need to compare only relevant parts of sockaddr_in6 */
866 switch (a->addr.sa.sa_family) {
867 #if COAP_IPV4_SUPPORT
868 case AF_INET:
869 return a->addr.sin.sin_addr.s_addr == INADDR_ANY;
870 #endif /* COAP_IPV4_SUPPORT */
871 #if COAP_IPV6_SUPPORT
872 case AF_INET6:
873 return memcmp(&in6addr_any,
874 &a->addr.sin6.sin6_addr,
875 sizeof(in6addr_any)) == 0;
876 #endif /* COAP_IPV6_SUPPORT */
877 default:
878 ;
879 }
880
881 return 0;
882 }
883 #endif /* ! WITH_LWIP && ! WITH_CONTIKI */
884