• 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 {
281     const void *addrptr = &addr->addr.sin6.sin6_addr;
282     (void)inet_ntop(addr->addr.sa.sa_family, addrptr, dst, len);
283   }
284 #endif
285 }
286 
287 int
coap_address_set_unix_domain(coap_address_t * addr,const uint8_t * host,size_t host_len)288 coap_address_set_unix_domain(coap_address_t *addr,
289                              const uint8_t *host, size_t host_len) {
290 #if COAP_AF_UNIX_SUPPORT
291   size_t i;
292   size_t ofs = 0;
293 
294   coap_address_init(addr);
295   addr->addr.cun.sun_family = AF_UNIX;
296   for (i = 0; i < host_len; i++) {
297     if ((host_len - i) >= 3 && host[i] == '%' && host[i+1] == '2' &&
298         (host[i+2] == 'F' || host[i+2] == 'f')) {
299       addr->addr.cun.sun_path[ofs++] = '/';
300       i += 2;
301     } else {
302       addr->addr.cun.sun_path[ofs++] = host[i];
303     }
304     if (ofs == COAP_UNIX_PATH_MAX)
305       break;
306   }
307   if (ofs < COAP_UNIX_PATH_MAX)
308     addr->addr.cun.sun_path[ofs] = '\000';
309   else
310     addr->addr.cun.sun_path[ofs-1] = '\000';
311   return 1;
312 #else /* ! COAP_AF_UNIX_SUPPORT */
313   (void)addr;
314   (void)host;
315   (void)host_len;
316   return 0;
317 #endif /* ! COAP_AF_UNIX_SUPPORT */
318 }
319 
320 #if !defined(WITH_CONTIKI)
321 static void
update_port(coap_address_t * addr,uint16_t port,uint16_t default_port,int update_port0)322 update_port(coap_address_t *addr, uint16_t port, uint16_t default_port,
323             int update_port0) {
324   /* Client target port must be set if default of 0 */
325   if (port == 0 && update_port0)
326     port = default_port;
327 
328   coap_address_set_port(addr, port);
329   return;
330 }
331 
332 #ifdef HAVE_NETDB_H
333 #include <netdb.h>
334 #endif
335 
336 uint32_t
coap_get_available_scheme_hint_bits(int have_pki_psk,int ws_check,coap_proto_t use_unix_proto)337 coap_get_available_scheme_hint_bits(int have_pki_psk, int ws_check,
338                                     coap_proto_t use_unix_proto) {
339   uint32_t scheme_hint_bits = 0;
340   coap_uri_scheme_t scheme;
341 
342   for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
343     switch (scheme) {
344     case COAP_URI_SCHEME_COAP:
345       scheme_hint_bits |= 1 << scheme;
346       break;
347     case COAP_URI_SCHEME_COAPS:
348       if (!(coap_dtls_is_supported() && have_pki_psk))
349         continue;
350       scheme_hint_bits |= 1 << scheme;
351       break;
352     case COAP_URI_SCHEME_COAP_TCP:
353       if (!coap_tcp_is_supported())
354         continue;
355       scheme_hint_bits |= 1 << scheme;
356       break;
357     case COAP_URI_SCHEME_COAPS_TCP:
358       if (!(coap_tls_is_supported() && have_pki_psk))
359         continue;
360       scheme_hint_bits |= 1 << scheme;
361       break;
362     case COAP_URI_SCHEME_COAP_WS:
363       if (!ws_check || !coap_ws_is_supported())
364         continue;
365       scheme_hint_bits |= 1 << scheme;
366       break;
367     case COAP_URI_SCHEME_COAPS_WS:
368       if (!ws_check || !(coap_wss_is_supported() && have_pki_psk))
369         continue;
370       scheme_hint_bits |= 1 << scheme;
371       break;
372     case COAP_URI_SCHEME_HTTP:
373     case COAP_URI_SCHEME_HTTPS:
374     case COAP_URI_SCHEME_LAST:
375     default:
376       continue;
377     }
378   }
379 
380   switch (use_unix_proto) {
381   /* For AF_UNIX, can only listen on a single endpoint */
382   case COAP_PROTO_UDP:
383     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP;
384     break;
385   case COAP_PROTO_TCP:
386     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_TCP;
387     break;
388   case COAP_PROTO_DTLS:
389     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS;
390     break;
391   case COAP_PROTO_TLS:
392     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_TCP;
393     break;
394   case COAP_PROTO_WS:
395     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_WS;
396     break;
397   case COAP_PROTO_WSS:
398     scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_WS;
399     break;
400   case COAP_PROTO_NONE: /* If use_unix_proto was not defined */
401   case COAP_PROTO_LAST:
402   default:
403     break;
404   }
405   return scheme_hint_bits;
406 }
407 
408 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)409 coap_resolve_address_info(const coap_str_const_t *address,
410                           uint16_t port,
411                           uint16_t secure_port,
412                           uint16_t ws_port,
413                           uint16_t ws_secure_port,
414                           int ai_hints_flags,
415                           int scheme_hint_bits,
416                           coap_resolve_type_t type) {
417 #if !defined(RIOT_VERSION)
418 
419   struct addrinfo *res, *ainfo;
420   struct addrinfo hints;
421   static char addrstr[256];
422   int error;
423   coap_addr_info_t *info = NULL;
424   coap_addr_info_t *info_prev = NULL;
425   coap_addr_info_t *info_list = NULL;
426   coap_addr_info_t *info_tmp;
427   coap_uri_scheme_t scheme;
428   coap_proto_t proto = 0;
429 
430 #if COAP_AF_UNIX_SUPPORT
431   if (address && coap_host_is_unix_domain(address)) {
432     /* There can only be one unique filename entry for AF_UNIX */
433     if (address->length >= COAP_UNIX_PATH_MAX) {
434       coap_log_err("Unix Domain host too long\n");
435       return NULL;
436     }
437     /* Need to chose the first defined one  in scheme_hint_bits */
438     for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
439       if (scheme_hint_bits & (1 << scheme)) {
440         break;
441       }
442     }
443     if (scheme == COAP_URI_SCHEME_LAST) {
444       return NULL;
445     }
446     switch (scheme) {
447     case COAP_URI_SCHEME_COAP:
448       proto = COAP_PROTO_UDP;
449       break;
450     case COAP_URI_SCHEME_COAPS:
451       if (!coap_dtls_is_supported())
452         return NULL;
453       proto = COAP_PROTO_DTLS;
454       break;
455     case COAP_URI_SCHEME_COAP_TCP:
456       if (!coap_tcp_is_supported())
457         return NULL;
458       proto = COAP_PROTO_TCP;
459       break;
460     case COAP_URI_SCHEME_COAPS_TCP:
461       if (!coap_tls_is_supported())
462         return NULL;
463       proto = COAP_PROTO_TLS;
464       break;
465     case COAP_URI_SCHEME_HTTP:
466       if (!coap_tcp_is_supported())
467         return NULL;
468       proto = COAP_PROTO_NONE;
469       break;
470     case COAP_URI_SCHEME_HTTPS:
471       if (!coap_tls_is_supported())
472         return NULL;
473       proto = COAP_PROTO_NONE;
474       break;
475     case COAP_URI_SCHEME_COAP_WS:
476       if (!coap_ws_is_supported())
477         return NULL;
478       proto = COAP_PROTO_WS;
479       break;
480     case COAP_URI_SCHEME_COAPS_WS:
481       if (!coap_wss_is_supported())
482         return NULL;
483       proto = COAP_PROTO_WSS;
484       break;
485     case COAP_URI_SCHEME_LAST:
486     default:
487       return NULL;
488     }
489     info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
490     if (info == NULL)
491       return NULL;
492     info->next = NULL;
493     info->proto = proto;
494     info->scheme = scheme;
495 
496     coap_address_init(&info->addr);
497     if (!coap_address_set_unix_domain(&info->addr, address->s,
498                                       address->length)) {
499       coap_free_type(COAP_STRING, info);
500       return NULL;
501     }
502     return info;
503   }
504 #endif /* COAP_AF_UNIX_SUPPORT */
505 
506   memset(addrstr, 0, sizeof(addrstr));
507   if (address && address->length)
508     memcpy(addrstr, address->s, address->length);
509   else
510     memcpy(addrstr, "localhost", 9);
511 
512   memset((char *)&hints, 0, sizeof(hints));
513   hints.ai_socktype = 0;
514   hints.ai_family = AF_UNSPEC;
515   hints.ai_flags = ai_hints_flags;
516 
517   error = getaddrinfo(addrstr, NULL, &hints, &res);
518 
519   if (error != 0) {
520     coap_log_warn("getaddrinfo: %s\n", gai_strerror(error));
521     return NULL;
522   }
523 
524   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
525 #if !defined(WITH_LWIP)
526     if (ainfo->ai_addrlen > (socklen_t)sizeof(info->addr.addr))
527       continue;
528 #endif /* ! WITH_LWIP */
529 
530     switch (ainfo->ai_family) {
531 #if COAP_IPV4_SUPPORT
532     case AF_INET:
533 #endif /* COAP_IPV4_SUPPORT */
534 #if COAP_IPV6_SUPPORT
535     case AF_INET6:
536 #endif /* COAP_IPV6_SUPPORT */
537       for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
538         if (scheme_hint_bits & (1 << scheme)) {
539           switch (scheme) {
540           case COAP_URI_SCHEME_COAP:
541             proto = COAP_PROTO_UDP;
542             break;
543           case COAP_URI_SCHEME_COAPS:
544             if (!coap_dtls_is_supported())
545               continue;
546             proto = COAP_PROTO_DTLS;
547             break;
548           case COAP_URI_SCHEME_COAP_TCP:
549             if (!coap_tcp_is_supported())
550               continue;
551             proto = COAP_PROTO_TCP;
552             break;
553           case COAP_URI_SCHEME_COAPS_TCP:
554             if (!coap_tls_is_supported())
555               continue;
556             proto = COAP_PROTO_TLS;
557             break;
558           case COAP_URI_SCHEME_HTTP:
559             if (!coap_tcp_is_supported())
560               continue;
561             proto = COAP_PROTO_NONE;
562             break;
563           case COAP_URI_SCHEME_HTTPS:
564             if (!coap_tls_is_supported())
565               continue;
566             proto = COAP_PROTO_NONE;
567             break;
568           case COAP_URI_SCHEME_COAP_WS:
569             if (!coap_ws_is_supported())
570               continue;
571             proto = COAP_PROTO_WS;
572             break;
573           case COAP_URI_SCHEME_COAPS_WS:
574             if (!coap_wss_is_supported())
575               continue;
576             proto = COAP_PROTO_WSS;
577             break;
578           case COAP_URI_SCHEME_LAST:
579           default:
580             continue;
581           }
582 
583           info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
584           if (info == NULL) {
585             freeaddrinfo(res);
586             /* malloc failure - return what we have so far */
587             return info_list;
588           }
589 
590           info->next = NULL;
591           info->scheme = scheme;
592           info->proto = proto;
593           coap_address_init(&info->addr);
594 #if !defined(WITH_LWIP)
595           info->addr.size = (socklen_t)ainfo->ai_addrlen;
596           memcpy(&info->addr.addr, ainfo->ai_addr, ainfo->ai_addrlen);
597 #else /* WITH_LWIP */
598           memset(&info->addr, 0, sizeof(info->addr));
599           switch (ainfo->ai_family) {
600 #if COAP_IPV6_SUPPORT
601             struct sockaddr_in6 *sock6;
602 #endif /* COAP_IPV6_SUPPORT */
603 #if COAP_IPV4_SUPPORT
604             struct sockaddr_in *sock4;
605           case AF_INET:
606             sock4 = (struct sockaddr_in *)ainfo->ai_addr;
607             info->addr.port = ntohs(sock4->sin_port);
608             memcpy(&info->addr.addr, &sock4->sin_addr, 4);
609 #if LWIP_IPV6
610             info->addr.addr.type = IPADDR_TYPE_V4;
611 #endif /* LWIP_IPV6 */
612             break;
613 #endif /* COAP_IPV4_SUPPORT */
614 #if COAP_IPV6_SUPPORT
615           case AF_INET6:
616             sock6 = (struct sockaddr_in6 *)ainfo->ai_addr;
617             info->addr.port = ntohs(sock6->sin6_port);
618             memcpy(&info->addr.addr, &sock6->sin6_addr, 16);
619 #if LWIP_IPV6 && LWIP_IPV4
620             info->addr.addr.type = IPADDR_TYPE_V6;
621 #endif /* LWIP_IPV6 && LWIP_IPV4 */
622             break;
623 #endif /* COAP_IPV6_SUPPORT */
624           default:
625             ;
626           }
627 #endif /* WITH_LWIP */
628           switch (scheme) {
629           case COAP_URI_SCHEME_COAP:
630             update_port(&info->addr, port, COAP_DEFAULT_PORT,
631                         type == COAP_RESOLVE_TYPE_LOCAL);
632             break;
633           case COAP_URI_SCHEME_COAPS:
634             update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
635                         type == COAP_RESOLVE_TYPE_LOCAL);
636             break;
637           case COAP_URI_SCHEME_COAP_TCP:
638             update_port(&info->addr, port, COAP_DEFAULT_PORT,
639                         type == COAP_RESOLVE_TYPE_LOCAL);
640             break;
641           case COAP_URI_SCHEME_COAPS_TCP:
642             update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
643                         type == COAP_RESOLVE_TYPE_LOCAL);
644             break;
645           case COAP_URI_SCHEME_HTTP:
646             update_port(&info->addr, port, 80,
647                         type == COAP_RESOLVE_TYPE_LOCAL);
648             break;
649           case COAP_URI_SCHEME_HTTPS:
650             update_port(&info->addr, secure_port, 443,
651                         type == COAP_RESOLVE_TYPE_LOCAL);
652             break;
653           case COAP_URI_SCHEME_COAP_WS:
654             update_port(&info->addr, ws_port, 80,
655                         type == COAP_RESOLVE_TYPE_LOCAL);
656             break;
657           case COAP_URI_SCHEME_COAPS_WS:
658             update_port(&info->addr, ws_secure_port, 443,
659                         type == COAP_RESOLVE_TYPE_LOCAL);
660             break;
661           case COAP_URI_SCHEME_LAST:
662           default:
663             break;
664           }
665 
666           /* Check there are no duplications */
667           info_tmp = info_list;
668           while (info_tmp) {
669             if (info_tmp->proto == info->proto &&
670                 info_tmp->scheme == info->scheme &&
671                 coap_address_equals(&info_tmp->addr, &info->addr)) {
672               break;
673             }
674             info_tmp = info_tmp->next;
675           }
676 
677           if (info_tmp) {
678             /* Duplicate */
679             coap_free_type(COAP_STRING, info);
680           } else {
681             /* Need to return in same order as getaddrinfo() */
682             if (!info_prev) {
683               info_list = info;
684               info_prev = info;
685             } else {
686               info_prev->next = info;
687               info_prev = info;
688             }
689           }
690         }
691       }
692       break;
693     default:
694       break;
695     }
696   }
697 
698   freeaddrinfo(res);
699   return info_list;
700 #else /* RIOT_VERSION */
701 #if COAP_IPV6_SUPPORT
702 #include "net/utils.h"
703   ipv6_addr_t addr_ipv6;
704   netif_t *netif = NULL;
705   coap_addr_info_t *info = NULL;
706   coap_addr_info_t *info_prev = NULL;
707   coap_addr_info_t *info_list = NULL;
708   coap_uri_scheme_t scheme;
709   coap_proto_t proto = 0;
710   (void)ai_hints_flags;
711 
712   if (netutils_get_ipv6(&addr_ipv6, &netif, (const char *)address->s) >= 0) {
713     for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
714       if (scheme_hint_bits & (1 << scheme)) {
715         switch (scheme) {
716         case COAP_URI_SCHEME_COAP:
717           proto = COAP_PROTO_UDP;
718           break;
719         case COAP_URI_SCHEME_COAPS:
720           if (!coap_dtls_is_supported())
721             continue;
722           proto = COAP_PROTO_DTLS;
723           break;
724         case COAP_URI_SCHEME_COAP_TCP:
725           if (!coap_tcp_is_supported())
726             continue;
727           proto = COAP_PROTO_TCP;
728           break;
729         case COAP_URI_SCHEME_COAPS_TCP:
730           if (!coap_tls_is_supported())
731             continue;
732           proto = COAP_PROTO_TLS;
733           break;
734         case COAP_URI_SCHEME_HTTP:
735           if (!coap_tcp_is_supported())
736             continue;
737           proto = COAP_PROTO_NONE;
738           break;
739         case COAP_URI_SCHEME_HTTPS:
740           if (!coap_tls_is_supported())
741             continue;
742           proto = COAP_PROTO_NONE;
743           break;
744         case COAP_URI_SCHEME_COAP_WS:
745           if (!coap_ws_is_supported())
746             continue;
747           proto = COAP_PROTO_WS;
748           break;
749         case COAP_URI_SCHEME_COAPS_WS:
750           if (!coap_wss_is_supported())
751             continue;
752           proto = COAP_PROTO_WSS;
753           break;
754         case COAP_URI_SCHEME_LAST:
755         default:
756           continue;
757         }
758 
759         info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
760         if (info == NULL) {
761           /* malloc failure - return what we have so far */
762           return info_list;
763         }
764         info->next = NULL;
765         /* Need to return in same order as getaddrinfo() */
766         if (!info_prev) {
767           info_list = info;
768           info_prev = info;
769         } else {
770           info_prev->next = info;
771           info_prev = info;
772         }
773 
774         info->scheme = scheme;
775         info->proto = proto;
776         coap_address_init(&info->addr);
777         info->addr.size = sizeof(struct sockaddr_in6);
778         info->addr.addr.sin6.sin6_family = AF_INET6;
779         memcpy(&info->addr.addr.sin6.sin6_addr, &addr_ipv6,
780                sizeof(info->addr.addr.sin6.sin6_addr));
781         info->addr.addr.sin6.sin6_scope_id = (uint32_t)netif_get_id(netif);
782         switch (scheme) {
783         case COAP_URI_SCHEME_COAP:
784           update_port(&info->addr, port, COAP_DEFAULT_PORT,
785                       type == COAP_RESOLVE_TYPE_LOCAL);
786           break;
787         case COAP_URI_SCHEME_COAPS:
788           update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
789                       type == COAP_RESOLVE_TYPE_LOCAL);
790           break;
791         case COAP_URI_SCHEME_COAP_TCP:
792           update_port(&info->addr, port, COAP_DEFAULT_PORT,
793                       type == COAP_RESOLVE_TYPE_LOCAL);
794           break;
795         case COAP_URI_SCHEME_COAPS_TCP:
796           update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
797                       type == COAP_RESOLVE_TYPE_LOCAL);
798           break;
799         case COAP_URI_SCHEME_HTTP:
800           update_port(&info->addr, port, ws_port,
801                       type == COAP_RESOLVE_TYPE_LOCAL);
802           break;
803         case COAP_URI_SCHEME_HTTPS:
804           update_port(&info->addr, secure_port, ws_secure_port,
805                       type == COAP_RESOLVE_TYPE_LOCAL);
806           break;
807         case COAP_URI_SCHEME_LAST:
808         default:
809           break;
810         }
811       }
812     }
813     return info_list;
814   }
815 #endif /* COAP_IPV6_SUPPORT */
816   return NULL;
817 #endif /* RIOT_VERSION */
818 }
819 #endif /* !WITH_CONTIKI */
820 
821 void
coap_free_address_info(coap_addr_info_t * info)822 coap_free_address_info(coap_addr_info_t *info) {
823   while (info) {
824     coap_addr_info_t *info_next = info->next;
825 
826     coap_free_type(COAP_STRING, info);
827     info = info_next;
828   }
829 }
830 
831 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
832 void
coap_address_copy(coap_address_t * dst,const coap_address_t * src)833 coap_address_copy(coap_address_t *dst, const coap_address_t *src) {
834 #if defined(WITH_LWIP) || defined(WITH_CONTIKI)
835   memcpy(dst, src, sizeof(coap_address_t));
836 #else
837   memset(dst, 0, sizeof(coap_address_t));
838   dst->size = src->size;
839 #if COAP_IPV6_SUPPORT
840   if (src->addr.sa.sa_family == AF_INET6) {
841     dst->addr.sin6.sin6_family = src->addr.sin6.sin6_family;
842     dst->addr.sin6.sin6_addr = src->addr.sin6.sin6_addr;
843     dst->addr.sin6.sin6_port = src->addr.sin6.sin6_port;
844     dst->addr.sin6.sin6_scope_id = src->addr.sin6.sin6_scope_id;
845   }
846 #endif /* COAP_IPV6_SUPPORT */
847 #if COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT
848   else
849 #endif /* COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT */
850 #if COAP_IPV4_SUPPORT
851     if (src->addr.sa.sa_family == AF_INET) {
852       dst->addr.sin = src->addr.sin;
853     }
854 #endif /* COAP_IPV4_SUPPORT */
855     else {
856       memcpy(&dst->addr, &src->addr, src->size);
857     }
858 #endif
859 }
860 
861 int
_coap_address_isany_impl(const coap_address_t * a)862 _coap_address_isany_impl(const coap_address_t *a) {
863   /* need to compare only relevant parts of sockaddr_in6 */
864   switch (a->addr.sa.sa_family) {
865 #if COAP_IPV4_SUPPORT
866   case AF_INET:
867     return a->addr.sin.sin_addr.s_addr == INADDR_ANY;
868 #endif /* COAP_IPV4_SUPPORT */
869 #if COAP_IPV6_SUPPORT
870   case AF_INET6:
871     return memcmp(&in6addr_any,
872                   &a->addr.sin6.sin6_addr,
873                   sizeof(in6addr_any)) == 0;
874 #endif /* COAP_IPV6_SUPPORT */
875   default:
876     ;
877   }
878 
879   return 0;
880 }
881 #endif /* ! WITH_LWIP && ! WITH_CONTIKI */
882