1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26 #include <errno.h>
27
28 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
29 static int
interface_to_sa(struct lws_vhost * vh,const char * ifname,struct sockaddr_in * addr,size_t addrlen,int allow_ipv6)30 interface_to_sa(struct lws_vhost *vh, const char *ifname,
31 struct sockaddr_in *addr, size_t addrlen, int allow_ipv6)
32 {
33 int ipv6 = 0;
34 #ifdef LWS_WITH_IPV6
35 if (allow_ipv6)
36 ipv6 = LWS_IPV6_ENABLED(vh);
37 #endif
38 (void)vh;
39
40 return lws_interface_to_sa(ipv6, ifname, addr, addrlen);
41 }
42 #endif
43
44 #ifndef LWS_PLAT_OPTEE
45 static int
lws_get_addresses(struct lws_vhost * vh,void * ads,char * name,int name_len,char * rip,int rip_len)46 lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
47 int name_len, char *rip, int rip_len)
48 {
49 struct addrinfo ai, *res;
50 struct sockaddr_in addr4;
51
52 rip[0] = '\0';
53 name[0] = '\0';
54 addr4.sin_family = AF_UNSPEC;
55
56 #ifdef LWS_WITH_IPV6
57 if (LWS_IPV6_ENABLED(vh)) {
58 if (!lws_plat_inet_ntop(AF_INET6,
59 &((struct sockaddr_in6 *)ads)->sin6_addr,
60 rip, (socklen_t)rip_len)) {
61 lwsl_vhost_err(vh, "inet_ntop: %s", strerror(LWS_ERRNO));
62 return -1;
63 }
64
65 // Strip off the IPv4 to IPv6 header if one exists
66 if (strncmp(rip, "::ffff:", 7) == 0)
67 memmove(rip, rip + 7, strlen(rip) - 6);
68
69 getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
70 name,
71 #if defined(__ANDROID__)
72 (size_t)name_len,
73 #else
74 (socklen_t)name_len,
75 #endif
76 NULL, 0, 0);
77
78 return 0;
79 } else
80 #endif
81 {
82 struct addrinfo *result;
83
84 memset(&ai, 0, sizeof ai);
85 ai.ai_family = PF_UNSPEC;
86 ai.ai_socktype = SOCK_STREAM;
87 #if !defined(LWS_PLAT_FREERTOS)
88 if (getnameinfo((struct sockaddr *)ads,
89 sizeof(struct sockaddr_in),
90 name,
91 #if defined(__ANDROID__)
92 (size_t)name_len,
93 #else
94 (socklen_t)name_len,
95 #endif
96 NULL, 0, 0))
97 return -1;
98 #endif
99
100 if (getaddrinfo(name, NULL, &ai, &result))
101 return -1;
102
103 res = result;
104 while (addr4.sin_family == AF_UNSPEC && res) {
105 switch (res->ai_family) {
106 case AF_INET:
107 addr4.sin_addr =
108 ((struct sockaddr_in *)res->ai_addr)->sin_addr;
109 addr4.sin_family = AF_INET;
110 break;
111 }
112
113 res = res->ai_next;
114 }
115 freeaddrinfo(result);
116 }
117
118 if (addr4.sin_family == AF_UNSPEC)
119 return -1;
120
121 if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip,
122 (socklen_t)rip_len) == NULL)
123 return -1;
124
125 return 0;
126 }
127
128 const char *
lws_get_peer_simple_fd(lws_sockfd_type fd,char * name,size_t namelen)129 lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen)
130 {
131 lws_sockaddr46 sa46;
132 socklen_t len = sizeof(sa46);
133
134 if (getpeername(fd, (struct sockaddr *)&sa46, &len) < 0) {
135 lws_snprintf(name, namelen, "getpeername: %s",
136 strerror(LWS_ERRNO));
137 return name;
138 }
139
140 lws_sa46_write_numeric_address(&sa46, name, namelen);
141
142 return name;
143 }
144
145 const char *
lws_get_peer_simple(struct lws * wsi,char * name,size_t namelen)146 lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen)
147 {
148 wsi = lws_get_network_wsi(wsi);
149 return lws_get_peer_simple_fd(wsi->desc.sockfd, name, namelen);
150 }
151 #endif
152
153 void
lws_get_peer_addresses(struct lws * wsi,lws_sockfd_type fd,char * name,int name_len,char * rip,int rip_len)154 lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
155 int name_len, char *rip, int rip_len)
156 {
157 #ifndef LWS_PLAT_OPTEE
158 socklen_t len;
159 #ifdef LWS_WITH_IPV6
160 struct sockaddr_in6 sin6;
161 #endif
162 struct sockaddr_in sin4;
163 void *p;
164
165 rip[0] = '\0';
166 name[0] = '\0';
167
168 #ifdef LWS_WITH_IPV6
169 if (LWS_IPV6_ENABLED(wsi->a.vhost)) {
170 len = sizeof(sin6);
171 p = &sin6;
172 } else
173 #endif
174 {
175 len = sizeof(sin4);
176 p = &sin4;
177 }
178
179 if (getpeername(fd, p, &len) < 0) {
180 lwsl_wsi_warn(wsi, "getpeername: %s", strerror(LWS_ERRNO));
181 goto bail;
182 }
183
184 lws_get_addresses(wsi->a.vhost, p, name, name_len, rip, rip_len);
185
186 bail:
187 #endif
188 (void)wsi;
189 (void)fd;
190 (void)name;
191 (void)name_len;
192 (void)rip;
193 (void)rip_len;
194 }
195
196
197
198 /* note: this returns a random port, or one of these <= 0 return codes:
199 *
200 * LWS_ITOSA_USABLE: the interface is usable, returned if so and sockfd invalid
201 * LWS_ITOSA_NOT_EXIST: the requested iface does not even exist
202 * LWS_ITOSA_NOT_USABLE: the requested iface exists but is not usable (eg, no IP)
203 * LWS_ITOSA_BUSY: the port at the requested iface + port is already in use
204 */
205
206 int
lws_socket_bind(struct lws_vhost * vhost,struct lws * wsi,lws_sockfd_type sockfd,int port,const char * iface,int af)207 lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
208 lws_sockfd_type sockfd, int port, const char *iface,
209 int af)
210 {
211 #ifdef LWS_WITH_UNIX_SOCK
212 struct sockaddr_un serv_unix;
213 #endif
214 #ifdef LWS_WITH_IPV6
215 struct sockaddr_in6 serv_addr6;
216 #endif
217 struct sockaddr_in serv_addr4;
218 #ifndef LWS_PLAT_OPTEE
219 socklen_t len = sizeof(struct sockaddr_storage);
220 #endif
221 int n = 0;
222 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
223 int m;
224 #endif
225 struct sockaddr_storage sin, *psin = &sin;
226 struct sockaddr *v;
227
228 memset(&sin, 0, sizeof(sin));
229
230 /* if there's a wsi, we want to mark it with our source ads:port */
231 if (wsi)
232 psin = (struct sockaddr_storage *)&wsi->sa46_local;
233
234 switch (af) {
235 #if defined(LWS_WITH_UNIX_SOCK)
236 case AF_UNIX:
237 v = (struct sockaddr *)&serv_unix;
238 memset(&serv_unix, 0, sizeof(serv_unix));
239 serv_unix.sun_family = AF_UNIX;
240 if (!iface)
241 return LWS_ITOSA_NOT_EXIST;
242 if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
243 lwsl_wsi_err(wsi, "\"%s\" too long for UNIX domain socket",
244 iface);
245 return LWS_ITOSA_NOT_EXIST;
246 }
247 n = (int)(sizeof(uint16_t) + strlen(iface));
248 strcpy(serv_unix.sun_path, iface);
249 if (serv_unix.sun_path[0] == '@')
250 serv_unix.sun_path[0] = '\0';
251 else
252 unlink(serv_unix.sun_path);
253
254 // lwsl_hexdump_notice(v, n);
255 break;
256 #endif
257 #if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
258 case AF_INET6:
259 v = (struct sockaddr *)&serv_addr6;
260 n = sizeof(struct sockaddr_in6);
261
262 memset(&serv_addr6, 0, sizeof(serv_addr6));
263 serv_addr6.sin6_family = AF_INET6;
264 if (iface) {
265 m = interface_to_sa(vhost, iface,
266 (struct sockaddr_in *)v, (unsigned int)n, 1);
267 if (m == LWS_ITOSA_NOT_USABLE) {
268 lwsl_wsi_info(wsi, "netif %s: Not usable",
269 iface);
270 return m;
271 }
272 if (m == LWS_ITOSA_NOT_EXIST) {
273 lwsl_wsi_info(wsi, "netif %s: Does not exist",
274 iface);
275 return m;
276 }
277 serv_addr6.sin6_scope_id = (unsigned int)htonl((uint32_t)
278 lws_get_addr_scope(wsi, iface));
279 }
280
281 serv_addr6.sin6_port = (uint16_t)htons((uint16_t)port);
282 break;
283 #endif
284
285 case AF_INET:
286 v = (struct sockaddr *)&serv_addr4;
287 n = sizeof(serv_addr4);
288 memset(&serv_addr4, 0, sizeof(serv_addr4));
289 serv_addr4.sin_addr.s_addr = INADDR_ANY;
290 serv_addr4.sin_family = AF_INET;
291
292 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
293 if (iface) {
294 m = interface_to_sa(vhost, iface,
295 (struct sockaddr_in *)v, (unsigned int)n, 0);
296 if (m == LWS_ITOSA_NOT_USABLE) {
297 lwsl_wsi_info(wsi, "netif %s: Not usable",
298 iface);
299 return m;
300 }
301 if (m == LWS_ITOSA_NOT_EXIST) {
302 lwsl_wsi_info(wsi, "netif %s: Does not exist",
303 iface);
304 return m;
305 }
306 }
307 #endif
308 serv_addr4.sin_port = htons((uint16_t)(unsigned int)port);
309 break;
310 default:
311 return -1;
312 } /* switch */
313
314 /* just checking for the interface extant */
315 if (sockfd == LWS_SOCK_INVALID)
316 return LWS_ITOSA_USABLE;
317
318 n = bind(sockfd, v, (socklen_t)n);
319 #ifdef LWS_WITH_UNIX_SOCK
320 if (n < 0 && af == AF_UNIX) {
321 lwsl_wsi_err(wsi, "ERROR on binding fd %d to \"%s\" (%d %d)",
322 sockfd, iface, n, LWS_ERRNO);
323
324 return LWS_ITOSA_NOT_EXIST;
325 } else
326 #endif
327 if (n < 0) {
328 int _lws_errno = LWS_ERRNO;
329
330 lwsl_wsi_err(wsi, "ERROR on binding fd %d to port %d (%d %d)",
331 sockfd, port, n, _lws_errno);
332
333 /* if something already listening, tell caller to fail permanently */
334
335 if (_lws_errno == LWS_EADDRINUSE)
336 return LWS_ITOSA_BUSY;
337
338 /* otherwise ask caller to retry later */
339
340 return LWS_ITOSA_NOT_EXIST;
341 }
342
343 #if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
344 if (af == AF_UNIX) {
345 uid_t uid = vhost->context->uid;
346 gid_t gid = vhost->context->gid;
347
348 if (vhost->unix_socket_perms) {
349 if (lws_plat_user_colon_group_to_ids(
350 vhost->unix_socket_perms, &uid, &gid)) {
351 lwsl_wsi_err(wsi, "Failed to translate %s",
352 vhost->unix_socket_perms);
353 return LWS_ITOSA_NOT_EXIST;
354 }
355 }
356 if (iface && iface[0] != '@' && uid && gid) {
357 if (chown(iface, uid, gid)) {
358 lwsl_wsi_err(wsi, "failed to set %s perms %u:%u",
359 iface, (unsigned int)uid,
360 (unsigned int)gid);
361
362 return LWS_ITOSA_NOT_EXIST;
363 }
364 lwsl_wsi_notice(wsi, "vh %s unix skt %s perms %u:%u",
365 vhost->name, iface,
366 (unsigned int)uid,
367 (unsigned int)gid);
368
369 if (chmod(iface, 0660)) {
370 lwsl_wsi_err(wsi, "0600 mode on %s fail", iface);
371
372 return LWS_ITOSA_NOT_EXIST;
373 }
374 }
375 }
376 #endif
377
378 #ifndef LWS_PLAT_OPTEE
379 if (getsockname(sockfd, (struct sockaddr *)psin, &len) == -1)
380 lwsl_wsi_warn(wsi, "getsockname: %s", strerror(LWS_ERRNO));
381 else
382 #endif
383 #if defined(LWS_WITH_IPV6)
384 port = (sin.ss_family == AF_INET6) ?
385 ntohs(((struct sockaddr_in6 *)psin)->sin6_port) :
386 ntohs(((struct sockaddr_in *)psin)->sin_port);
387 #else
388 {
389 struct sockaddr_in sain;
390 memcpy(&sain, psin, sizeof(sain));
391 port = ntohs(sain.sin_port);
392 }
393 #endif
394
395 {
396 char buf[72];
397 lws_sa46_write_numeric_address((lws_sockaddr46 *)psin,
398 buf, sizeof(buf));
399
400 lwsl_vhost_notice(vhost, "source ads %s", buf);
401 }
402
403 return port;
404 }
405
406 #if defined(LWS_WITH_CLIENT)
407
408 unsigned int
lws_retry_get_delay_ms(struct lws_context * context,const lws_retry_bo_t * retry,uint16_t * ctry,char * conceal)409 lws_retry_get_delay_ms(struct lws_context *context,
410 const lws_retry_bo_t *retry, uint16_t *ctry,
411 char *conceal)
412 {
413 uint64_t ms = 3000, pc = 30; /* sane-ish defaults if no retry table */
414 uint16_t ra;
415
416 if (conceal)
417 *conceal = 0;
418
419 if (retry) {
420 if (retry->retry_ms_table_count) {
421 if (*ctry < retry->retry_ms_table_count)
422 ms = retry->retry_ms_table[*ctry];
423 else
424 ms = retry->retry_ms_table[
425 retry->retry_ms_table_count - 1];
426 }
427
428 /* if no percent given, use the default 30% */
429 if (retry->jitter_percent)
430 pc = retry->jitter_percent;
431 }
432
433 if (lws_get_random(context, &ra, sizeof(ra)) == sizeof(ra))
434 ms += ((ms * pc * ra) >> 16) / 100;
435 else
436 assert(0);
437
438 if (*ctry < 0xffff)
439 (*ctry)++;
440
441 if (retry && conceal)
442 *conceal = (int)*ctry <= retry->conceal_count;
443
444 return (unsigned int)ms;
445 }
446
447 int
lws_retry_sul_schedule(struct lws_context * context,int tid,lws_sorted_usec_list_t * sul,const lws_retry_bo_t * retry,sul_cb_t cb,uint16_t * ctry)448 lws_retry_sul_schedule(struct lws_context *context, int tid,
449 lws_sorted_usec_list_t *sul,
450 const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
451 {
452 char conceal;
453 uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
454
455 if (!conceal)
456 return 1;
457
458 lwsl_cx_info(context, "sul %p: scheduling retry in %dms", sul, (int)ms);
459
460 lws_sul_schedule(context, tid, sul, cb, (int64_t)(ms * 1000));
461
462 return 0;
463 }
464
465 int
lws_retry_sul_schedule_retry_wsi(struct lws * wsi,lws_sorted_usec_list_t * sul,sul_cb_t cb,uint16_t * ctry)466 lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
467 sul_cb_t cb, uint16_t *ctry)
468 {
469 char conceal;
470 lws_usec_t us = lws_retry_get_delay_ms(wsi->a.context,
471 wsi->retry_policy, ctry,
472 &conceal) * LWS_US_PER_MS;
473
474 if (!conceal)
475 /* if our reties are up, they're up... */
476 return 1;
477
478 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
479 if (
480 #if defined(LWS_ROLE_H1)
481 wsi->role_ops == &role_ops_h1
482 #endif
483 #if defined(LWS_ROLE_H1) && defined(LWS_ROLE_H2)
484 ||
485 #endif
486 #if defined(LWS_ROLE_H2)
487 wsi->role_ops == &role_ops_h2
488 #endif
489 )
490 /*
491 * Since we're doing it by wsi, we're in a position to check for
492 * http retry-after, it will increase us accordingly if found
493 */
494 lws_http_check_retry_after(wsi, &us);
495 #endif
496 lws_sul_schedule(wsi->a.context, wsi->tsi, sul, cb, us);
497
498 return 0;
499 }
500
501 #endif
502
503 #if defined(LWS_WITH_IPV6)
504 unsigned long
lws_get_addr_scope(struct lws * wsi,const char * ifname_or_ipaddr)505 lws_get_addr_scope(struct lws *wsi, const char *ifname_or_ipaddr)
506 {
507 unsigned long scope;
508 char ip[NI_MAXHOST];
509 unsigned int i;
510 #if !defined(WIN32)
511 struct ifaddrs *addrs, *addr;
512 #else
513 PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
514 PIP_ADAPTER_UNICAST_ADDRESS addr;
515 struct sockaddr_in6 *sockaddr;
516 ULONG size = 0;
517 int found = 0;
518 DWORD ret;
519 #endif
520
521 /*
522 * First see if we can look the string up as a network interface name...
523 * windows vista+ also has this
524 */
525
526 scope = if_nametoindex(ifname_or_ipaddr);
527 if (scope > 0)
528 /* we found it from the interface name lookup */
529 return scope;
530
531 /*
532 * if not, try to look it up as an IP -> interface -> interface index
533 */
534
535 scope = 0;
536
537 #if !defined(WIN32)
538
539 getifaddrs(&addrs);
540 for (addr = addrs; addr; addr = addr->ifa_next) {
541 if (!addr->ifa_addr ||
542 addr->ifa_addr->sa_family != AF_INET6)
543 continue;
544
545 ip[0] = '\0';
546 getnameinfo(addr->ifa_addr, sizeof(struct sockaddr_in6),
547 ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
548
549 i = 0;
550 while (ip[i])
551 if (ip[i++] == '%') {
552 ip[i - 1] = '\0';
553 break;
554 }
555
556 if (!strcmp(ip, ifname_or_ipaddr)) {
557 scope = if_nametoindex(addr->ifa_name);
558 break;
559 }
560 }
561 freeifaddrs(addrs);
562 #else
563
564 for (i = 0; i < 5; i++) {
565 ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
566 NULL, addrs, &size);
567 if (ret == NO_ERROR || ret == ERROR_NO_DATA)
568 break;
569
570 if (addrs)
571 free(addrs);
572
573 if (ret != ERROR_BUFFER_OVERFLOW) {
574 addrs = NULL;
575 lwsl_wsi_err(wsi, "Get IPv6 ads table fail (%d)", ret);
576 break;
577 }
578
579 addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
580 }
581
582 if ((ret == NO_ERROR) && (addrs)) {
583 adapter = addrs;
584 while (adapter && !found) {
585 addr = adapter->FirstUnicastAddress;
586 while (addr && !found) {
587 if (addr->Address.lpSockaddr->sa_family ==
588 AF_INET6) {
589 sockaddr = (struct sockaddr_in6 *)
590 (addr->Address.lpSockaddr);
591
592 lws_plat_inet_ntop(sockaddr->sin6_family,
593 &sockaddr->sin6_addr,
594 ip, sizeof(ip));
595
596 if (!strcmp(ip, ifname_or_ipaddr)) {
597 scope = sockaddr->sin6_scope_id;
598 found = 1;
599 break;
600 }
601 }
602 addr = addr->Next;
603 }
604 adapter = adapter->Next;
605 }
606 }
607 if (addrs)
608 free(addrs);
609 #endif
610
611 return scope;
612 }
613 #endif
614
615 /*
616 * https://en.wikipedia.org/wiki/IPv6_address
617 *
618 * An IPv6 address is represented as eight groups of four hexadecimal digits,
619 * each group representing 16 bits (two octets, a group sometimes also called a
620 * hextet[6][7]). The groups are separated by colons (:). An example of an IPv6
621 * address is:
622 *
623 * 2001:0db8:85a3:0000:0000:8a2e:0370:7334
624 *
625 * The hexadecimal digits are case-insensitive, but IETF recommendations suggest
626 * the use of lower case letters. The full representation of eight 4-digit
627 * groups may be simplified by several techniques, eliminating parts of the
628 * representation.
629 *
630 * Leading zeroes in a group may be omitted, but each group must retain at least
631 * one hexadecimal digit.[1] Thus, the example address may be written as:
632 *
633 * 2001:db8:85a3:0:0:8a2e:370:7334
634 *
635 * One or more consecutive groups containing zeros only may be replaced with a
636 * single empty group, using two consecutive colons (::).[1] The substitution
637 * may only be applied once in the address, however, because multiple
638 * occurrences would create an ambiguous representation. Thus, the example
639 * address can be further simplified:
640 *
641 * 2001:db8:85a3::8a2e:370:7334
642 *
643 * The localhost (loopback) address, 0:0:0:0:0:0:0:1, and the IPv6 unspecified
644 * address, 0:0:0:0:0:0:0:0, are reduced to ::1 and ::, respectively.
645 *
646 * During the transition of the Internet from IPv4 to IPv6, it is typical to
647 * operate in a mixed addressing environment. For such use cases, a special
648 * notation has been introduced, which expresses IPv4-mapped and IPv4-compatible
649 * IPv6 addresses by writing the least-significant 32 bits of an address in the
650 * familiar IPv4 dot-decimal notation, whereas the other 96 (most significant)
651 * bits are written in IPv6 format. For example, the IPv4-mapped IPv6 address
652 * ::ffff:c000:0280 is written as ::ffff:192.0.2.128, thus expressing clearly
653 * the original IPv4 address that was mapped to IPv6.
654 */
655
656 int
lws_parse_numeric_address(const char * ads,uint8_t * result,size_t max_len)657 lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len)
658 {
659 struct lws_tokenize ts;
660 uint8_t *orig = result, temp[16];
661 int sects = 0, ipv6 = !!strchr(ads, ':'), skip_point = -1, dm = 0;
662 char t[5];
663 size_t n;
664 long u;
665
666 lws_tokenize_init(&ts, ads, LWS_TOKENIZE_F_NO_INTEGERS |
667 LWS_TOKENIZE_F_MINUS_NONTERM);
668 ts.len = strlen(ads);
669 if (!ipv6 && ts.len < 7)
670 return -1;
671
672 if (ipv6 && ts.len < 2)
673 return -2;
674
675 if (!ipv6 && max_len < 4)
676 return -3;
677
678 if (ipv6 && max_len < 16)
679 return -4;
680
681 if (ipv6)
682 memset(result, 0, max_len);
683
684 do {
685 ts.e = (int8_t)lws_tokenize(&ts);
686 switch (ts.e) {
687 case LWS_TOKZE_TOKEN:
688 dm = 0;
689 if (ipv6) {
690 if (ts.token_len > 4)
691 return -1;
692 memcpy(t, ts.token, ts.token_len);
693 t[ts.token_len] = '\0';
694 for (n = 0; n < ts.token_len; n++)
695 if (t[n] < '0' || t[n] > 'f' ||
696 (t[n] > '9' && t[n] < 'A') ||
697 (t[n] > 'F' && t[n] < 'a'))
698 return -1;
699 u = strtol(t, NULL, 16);
700 if (u > 0xffff)
701 return -5;
702 *result++ = (uint8_t)(u >> 8);
703 } else {
704 if (ts.token_len > 3)
705 return -1;
706 memcpy(t, ts.token, ts.token_len);
707 t[ts.token_len] = '\0';
708 for (n = 0; n < ts.token_len; n++)
709 if (t[n] < '0' || t[n] > '9')
710 return -1;
711 u = strtol(t, NULL, 10);
712 if (u > 0xff)
713 return -6;
714 }
715 if (u < 0)
716 return -7;
717 *result++ = (uint8_t)u;
718 sects++;
719 break;
720
721 case LWS_TOKZE_DELIMITER:
722 if (dm++) {
723 if (dm > 2)
724 return -8;
725 if (*ts.token != ':')
726 return -9;
727 /* back to back : */
728 *result++ = 0;
729 *result++ = 0;
730 skip_point = lws_ptr_diff(result, orig);
731 break;
732 }
733 if (ipv6 && orig[2] == 0xff && orig[3] == 0xff &&
734 skip_point == 2) {
735 /* ipv4 backwards compatible format */
736 ipv6 = 0;
737 memset(orig, 0, max_len);
738 orig[10] = 0xff;
739 orig[11] = 0xff;
740 skip_point = -1;
741 result = &orig[12];
742 sects = 0;
743 break;
744 }
745 if (ipv6 && *ts.token != ':')
746 return -10;
747 if (!ipv6 && *ts.token != '.')
748 return -11;
749 break;
750
751 case LWS_TOKZE_ENDED:
752 if (!ipv6 && sects == 4)
753 return lws_ptr_diff(result, orig);
754 if (ipv6 && sects == 8)
755 return lws_ptr_diff(result, orig);
756 if (skip_point != -1) {
757 int ow = lws_ptr_diff(result, orig);
758 /*
759 * contains ...::...
760 */
761 if (ow == 16)
762 return 16;
763 memcpy(temp, &orig[skip_point], (unsigned int)(ow - skip_point));
764 memset(&orig[skip_point], 0, (unsigned int)(16 - skip_point));
765 memcpy(&orig[16 - (ow - skip_point)], temp,
766 (unsigned int)(ow - skip_point));
767
768 return 16;
769 }
770 return -12;
771
772 default: /* includes ENDED */
773 lwsl_err("%s: malformed ip address\n",
774 __func__);
775
776 return -13;
777 }
778 } while (ts.e > 0 && result - orig <= (int)max_len);
779
780 lwsl_err("%s: ended on e %d\n", __func__, ts.e);
781
782 return -14;
783 }
784
785 int
lws_sa46_parse_numeric_address(const char * ads,lws_sockaddr46 * sa46)786 lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46)
787 {
788 uint8_t a[16];
789 int n;
790
791 n = lws_parse_numeric_address(ads, a, sizeof(a));
792 if (n < 0)
793 return -1;
794
795 #if defined(LWS_WITH_IPV6)
796 if (n == 16) {
797 sa46->sa6.sin6_family = AF_INET6;
798 memcpy(sa46->sa6.sin6_addr.s6_addr, a,
799 sizeof(sa46->sa6.sin6_addr.s6_addr));
800
801 return 0;
802 }
803 #endif
804
805 if (n != 4)
806 return -1;
807
808 sa46->sa4.sin_family = AF_INET;
809 memcpy(&sa46->sa4.sin_addr.s_addr, a,
810 sizeof(sa46->sa4.sin_addr.s_addr));
811
812 return 0;
813 }
814
815 int
lws_write_numeric_address(const uint8_t * ads,int size,char * buf,size_t len)816 lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len)
817 {
818 char c, elided = 0, soe = 0, zb = (char)-1, n, ipv4 = 0;
819 const char *e = buf + len;
820 char *obuf = buf;
821 int q = 0;
822
823 if (size == 4)
824 return lws_snprintf(buf, len, "%u.%u.%u.%u",
825 ads[0], ads[1], ads[2], ads[3]);
826
827 if (size != 16)
828 return -1;
829
830 for (c = 0; c < (char)size / 2; c++) {
831 uint16_t v = (uint16_t)((ads[q] << 8) | ads[q + 1]);
832
833 if (buf + 8 > e)
834 return -1;
835
836 q += 2;
837 if (soe) {
838 if (v)
839 *buf++ = ':';
840 /* fall thru to print hex value */
841 } else
842 if (!elided && !soe && !v) {
843 elided = soe = 1;
844 zb = c;
845 continue;
846 }
847
848 if (ipv4) {
849 n = (char)lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%u.%u",
850 ads[q - 2], ads[q - 1]);
851 buf += n;
852 if (c == 6)
853 *buf++ = '.';
854 } else {
855 if (soe && !v)
856 continue;
857 if (c)
858 *buf++ = ':';
859
860 buf += lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%x", v);
861
862 if (soe && v) {
863 soe = 0;
864 if (c == 5 && v == 0xffff && !zb) {
865 ipv4 = 1;
866 *buf++ = ':';
867 }
868 }
869 }
870 }
871 if (buf + 3 > e)
872 return -1;
873
874 if (soe) { /* as is the case for all zeros */
875 *buf++ = ':';
876 *buf++ = ':';
877 *buf = '\0';
878 }
879
880 return lws_ptr_diff(buf, obuf);
881 }
882
883 int
lws_sa46_write_numeric_address(lws_sockaddr46 * sa46,char * buf,size_t len)884 lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
885 {
886 *buf = '\0';
887 #if defined(LWS_WITH_IPV6)
888 if (sa46->sa4.sin_family == AF_INET6)
889 return lws_write_numeric_address(
890 (uint8_t *)&sa46->sa6.sin6_addr, 16, buf, len);
891 #endif
892 if (sa46->sa4.sin_family == AF_INET)
893 return lws_write_numeric_address(
894 (uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
895
896 #if defined(LWS_WITH_UNIX_SOCK)
897 if (sa46->sa4.sin_family == AF_UNIX)
898 return lws_snprintf(buf, len, "(unix skt)");
899 #endif
900
901 if (!sa46->sa4.sin_family)
902 return lws_snprintf(buf, len, "(unset)");
903
904 if (sa46->sa4.sin_family == AF_INET6)
905 return lws_snprintf(buf, len, "(ipv6 unsupp)");
906
907 lws_snprintf(buf, len, "(AF%d unsupp)", (int)sa46->sa4.sin_family);
908
909 return -1;
910 }
911
912 int
lws_sa46_compare_ads(const lws_sockaddr46 * sa46a,const lws_sockaddr46 * sa46b)913 lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
914 {
915 if (sa46a->sa4.sin_family != sa46b->sa4.sin_family)
916 return 1;
917
918 #if defined(LWS_WITH_IPV6)
919 if (sa46a->sa4.sin_family == AF_INET6)
920 return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
921 #endif
922
923 if (sa46a->sa4.sin_family == AF_INET)
924 return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
925
926 return 0;
927 }
928
929 void
lws_4to6(uint8_t * v6addr,const uint8_t * v4addr)930 lws_4to6(uint8_t *v6addr, const uint8_t *v4addr)
931 {
932 v6addr[12] = v4addr[0];
933 v6addr[13] = v4addr[1];
934 v6addr[14] = v4addr[2];
935 v6addr[15] = v4addr[3];
936
937 memset(v6addr, 0, 10);
938
939 v6addr[10] = v6addr[11] = 0xff;
940 }
941
942 #if defined(LWS_WITH_IPV6)
943 void
lws_sa46_4to6(lws_sockaddr46 * sa46,const uint8_t * v4addr,uint16_t port)944 lws_sa46_4to6(lws_sockaddr46 *sa46, const uint8_t *v4addr, uint16_t port)
945 {
946 sa46->sa4.sin_family = AF_INET6;
947
948 lws_4to6((uint8_t *)&sa46->sa6.sin6_addr.s6_addr[0], v4addr);
949
950 sa46->sa6.sin6_port = htons(port);
951 }
952 #endif
953
954 int
lws_sa46_on_net(const lws_sockaddr46 * sa46a,const lws_sockaddr46 * sa46_net,int net_len)955 lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
956 int net_len)
957 {
958 uint8_t mask = 0xff, norm[16];
959 const uint8_t *p1, *p2;
960
961 if (sa46a->sa4.sin_family == AF_INET) {
962 p1 = (uint8_t *)&sa46a->sa4.sin_addr;
963 if (sa46_net->sa4.sin_family == AF_INET6) {
964 /* ip is v4, net is v6, promote ip to v6 */
965
966 lws_4to6(norm, p1);
967 p1 = norm;
968 }
969 #if defined(LWS_WITH_IPV6)
970 } else
971 if (sa46a->sa4.sin_family == AF_INET6) {
972 p1 = (uint8_t *)&sa46a->sa6.sin6_addr;
973 #endif
974 } else
975 return 1;
976
977 if (sa46_net->sa4.sin_family == AF_INET) {
978 p2 = (uint8_t *)&sa46_net->sa4.sin_addr;
979 if (sa46a->sa4.sin_family == AF_INET6) {
980 /* ip is v6, net is v4, promote net to v6 */
981
982 lws_4to6(norm, p2);
983 p2 = norm;
984 /* because the mask length is for net v4 address */
985 net_len += 12 * 8;
986 }
987 #if defined(LWS_WITH_IPV6)
988 } else
989 if (sa46a->sa4.sin_family == AF_INET6) {
990 p2 = (uint8_t *)&sa46_net->sa6.sin6_addr;
991 #endif
992 } else
993 return 1;
994
995 while (net_len > 0) {
996 if (net_len < 8)
997 mask = (uint8_t)(mask << (8 - net_len));
998
999 if (((*p1++) & mask) != ((*p2++) & mask))
1000 return 1;
1001
1002 net_len -= 8;
1003 }
1004
1005 return 0;
1006 }
1007
1008 void
lws_sa46_copy_address(lws_sockaddr46 * sa46a,const void * in,int af)1009 lws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af)
1010 {
1011 sa46a->sa4.sin_family = (sa_family_t)af;
1012
1013 if (af == AF_INET)
1014 memcpy(&sa46a->sa4.sin_addr, in, 4);
1015 #if defined(LWS_WITH_IPV6)
1016 else if (af == AF_INET6)
1017 memcpy(&sa46a->sa6.sin6_addr, in, sizeof(sa46a->sa6.sin6_addr));
1018 #endif
1019 }
1020
1021 #if defined(LWS_WITH_SYS_STATE)
1022 lws_state_manager_t *
lws_system_get_state_manager(struct lws_context * context)1023 lws_system_get_state_manager(struct lws_context *context)
1024 {
1025 return &context->mgr_system;
1026 }
1027 #endif
1028