• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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