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
27 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
28 static int
interface_to_sa(struct lws_vhost * vh,const char * ifname,struct sockaddr_in * addr,size_t addrlen,int allow_ipv6)29 interface_to_sa(struct lws_vhost *vh, const char *ifname,
30 struct sockaddr_in *addr, size_t addrlen, int allow_ipv6)
31 {
32 int ipv6 = 0;
33 #ifdef LWS_WITH_IPV6
34 if (allow_ipv6)
35 ipv6 = LWS_IPV6_ENABLED(vh);
36 #endif
37 (void)vh;
38
39 return lws_interface_to_sa(ipv6, ifname, addr, addrlen);
40 }
41 #endif
42
43 #ifndef LWS_PLAT_OPTEE
44 static int
lws_get_addresses(struct lws_vhost * vh,void * ads,char * name,int name_len,char * rip,int rip_len)45 lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
46 int name_len, char *rip, int rip_len)
47 {
48 struct addrinfo ai, *res;
49 struct sockaddr_in addr4;
50
51 rip[0] = '\0';
52 name[0] = '\0';
53 addr4.sin_family = AF_UNSPEC;
54
55 #ifdef LWS_WITH_IPV6
56 if (LWS_IPV6_ENABLED(vh)) {
57 if (!lws_plat_inet_ntop(AF_INET6,
58 &((struct sockaddr_in6 *)ads)->sin6_addr,
59 rip, rip_len)) {
60 lwsl_err("inet_ntop: %s", strerror(LWS_ERRNO));
61 return -1;
62 }
63
64 // Strip off the IPv4 to IPv6 header if one exists
65 if (strncmp(rip, "::ffff:", 7) == 0)
66 memmove(rip, rip + 7, strlen(rip) - 6);
67
68 getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
69 name, name_len, NULL, 0, 0);
70
71 return 0;
72 } else
73 #endif
74 {
75 struct addrinfo *result;
76
77 memset(&ai, 0, sizeof ai);
78 ai.ai_family = PF_UNSPEC;
79 ai.ai_socktype = SOCK_STREAM;
80 #if !defined(LWS_PLAT_FREERTOS)
81 if (getnameinfo((struct sockaddr *)ads,
82 sizeof(struct sockaddr_in),
83 name, name_len, NULL, 0, 0))
84 return -1;
85 #endif
86
87 if (getaddrinfo(name, NULL, &ai, &result))
88 return -1;
89
90 res = result;
91 while (addr4.sin_family == AF_UNSPEC && res) {
92 switch (res->ai_family) {
93 case AF_INET:
94 addr4.sin_addr =
95 ((struct sockaddr_in *)res->ai_addr)->sin_addr;
96 addr4.sin_family = AF_INET;
97 break;
98 }
99
100 res = res->ai_next;
101 }
102 freeaddrinfo(result);
103 }
104
105 if (addr4.sin_family == AF_UNSPEC)
106 return -1;
107
108 if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip, rip_len) == NULL)
109 return -1;
110
111 return 0;
112 }
113
114 const char *
lws_get_peer_simple_fd(lws_sockfd_type fd,char * name,size_t namelen)115 lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen)
116 {
117 lws_sockaddr46 sa46;
118 socklen_t len = sizeof(sa46);
119
120 if (getpeername(fd, (struct sockaddr *)&sa46, &len) < 0) {
121 lws_snprintf(name, namelen, "getpeername: %s",
122 strerror(LWS_ERRNO));
123 return name;
124 }
125
126 lws_sa46_write_numeric_address(&sa46, name, namelen);
127
128 return name;
129 }
130
131 const char *
lws_get_peer_simple(struct lws * wsi,char * name,size_t namelen)132 lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen)
133 {
134 wsi = lws_get_network_wsi(wsi);
135 return lws_get_peer_simple_fd(wsi->desc.sockfd, name, namelen);
136 }
137 #endif
138
139 void
lws_get_peer_addresses(struct lws * wsi,lws_sockfd_type fd,char * name,int name_len,char * rip,int rip_len)140 lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
141 int name_len, char *rip, int rip_len)
142 {
143 #ifndef LWS_PLAT_OPTEE
144 socklen_t len;
145 #ifdef LWS_WITH_IPV6
146 struct sockaddr_in6 sin6;
147 #endif
148 struct sockaddr_in sin4;
149 void *p;
150
151 rip[0] = '\0';
152 name[0] = '\0';
153
154 #ifdef LWS_WITH_IPV6
155 if (LWS_IPV6_ENABLED(wsi->vhost)) {
156 len = sizeof(sin6);
157 p = &sin6;
158 } else
159 #endif
160 {
161 len = sizeof(sin4);
162 p = &sin4;
163 }
164
165 if (getpeername(fd, p, &len) < 0) {
166 lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
167 goto bail;
168 }
169
170 lws_get_addresses(wsi->vhost, p, name, name_len, rip, rip_len);
171
172 bail:
173 #endif
174 (void)wsi;
175 (void)fd;
176 (void)name;
177 (void)name_len;
178 (void)rip;
179 (void)rip_len;
180 }
181
182
183
184 /* note: this returns a random port, or one of these <= 0 return codes:
185 *
186 * LWS_ITOSA_USABLE: the interface is usable, returned if so and sockfd invalid
187 * LWS_ITOSA_NOT_EXIST: the requested iface does not even exist
188 * LWS_ITOSA_NOT_USABLE: the requested iface exists but is not usable (eg, no IP)
189 * LWS_ITOSA_BUSY: the port at the requested iface + port is already in use
190 */
191
192 int
lws_socket_bind(struct lws_vhost * vhost,lws_sockfd_type sockfd,int port,const char * iface,int ipv6_allowed)193 lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
194 const char *iface, int ipv6_allowed)
195 {
196 #ifdef LWS_WITH_UNIX_SOCK
197 struct sockaddr_un serv_unix;
198 #endif
199 #ifdef LWS_WITH_IPV6
200 struct sockaddr_in6 serv_addr6;
201 #endif
202 struct sockaddr_in serv_addr4;
203 #ifndef LWS_PLAT_OPTEE
204 socklen_t len = sizeof(struct sockaddr_storage);
205 #endif
206 int n;
207 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
208 int m;
209 #endif
210 struct sockaddr_storage sin;
211 struct sockaddr *v;
212
213 memset(&sin, 0, sizeof(sin));
214
215 #if defined(LWS_WITH_UNIX_SOCK)
216 if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
217 v = (struct sockaddr *)&serv_unix;
218 n = sizeof(struct sockaddr_un);
219 memset(&serv_unix, 0, sizeof(serv_unix));
220 serv_unix.sun_family = AF_UNIX;
221 if (!iface)
222 return LWS_ITOSA_NOT_EXIST;
223 if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
224 lwsl_err("\"%s\" too long for UNIX domain socket\n",
225 iface);
226 return LWS_ITOSA_NOT_EXIST;
227 }
228 strcpy(serv_unix.sun_path, iface);
229 if (serv_unix.sun_path[0] == '@')
230 serv_unix.sun_path[0] = '\0';
231 else
232 unlink(serv_unix.sun_path);
233
234 } else
235 #endif
236 #if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
237 if (ipv6_allowed && LWS_IPV6_ENABLED(vhost)) {
238 v = (struct sockaddr *)&serv_addr6;
239 n = sizeof(struct sockaddr_in6);
240 memset(&serv_addr6, 0, sizeof(serv_addr6));
241 if (iface) {
242 m = interface_to_sa(vhost, iface,
243 (struct sockaddr_in *)v, n, 1);
244 if (m == LWS_ITOSA_NOT_USABLE) {
245 lwsl_info("%s: netif %s: Not usable\n",
246 __func__, iface);
247 return m;
248 }
249 if (m == LWS_ITOSA_NOT_EXIST) {
250 lwsl_info("%s: netif %s: Does not exist\n",
251 __func__, iface);
252 return m;
253 }
254 serv_addr6.sin6_scope_id = lws_get_addr_scope(iface);
255 }
256
257 serv_addr6.sin6_family = AF_INET6;
258 serv_addr6.sin6_port = htons(port);
259 } else
260 #endif
261 {
262 v = (struct sockaddr *)&serv_addr4;
263 n = sizeof(serv_addr4);
264 memset(&serv_addr4, 0, sizeof(serv_addr4));
265 serv_addr4.sin_addr.s_addr = INADDR_ANY;
266 serv_addr4.sin_family = AF_INET;
267
268 #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
269 if (iface) {
270 m = interface_to_sa(vhost, iface,
271 (struct sockaddr_in *)v, n, 0);
272 if (m == LWS_ITOSA_NOT_USABLE) {
273 lwsl_info("%s: netif %s: Not usable\n",
274 __func__, iface);
275 return m;
276 }
277 if (m == LWS_ITOSA_NOT_EXIST) {
278 lwsl_info("%s: netif %s: Does not exist\n",
279 __func__, iface);
280 return m;
281 }
282 }
283 #endif
284 serv_addr4.sin_port = htons(port);
285 } /* ipv4 */
286
287 /* just checking for the interface extant */
288 if (sockfd == LWS_SOCK_INVALID)
289 return LWS_ITOSA_USABLE;
290
291 n = bind(sockfd, v, n);
292 #ifdef LWS_WITH_UNIX_SOCK
293 if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) {
294 lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n",
295 sockfd, iface, n, LWS_ERRNO);
296 return LWS_ITOSA_NOT_EXIST;
297 } else
298 #endif
299 if (n < 0) {
300 int _lws_errno = LWS_ERRNO;
301
302 lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n",
303 sockfd, port, n, _lws_errno);
304
305 /* if something already listening, tell caller to fail permanently */
306
307 if (_lws_errno == LWS_EADDRINUSE)
308 return LWS_ITOSA_BUSY;
309
310 /* otherwise ask caller to retry later */
311
312 return LWS_ITOSA_NOT_EXIST;
313 }
314
315 #if defined(LWS_WITH_UNIX_SOCK)
316 if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
317 uid_t uid = vhost->context->uid;
318 gid_t gid = vhost->context->gid;
319
320 if (vhost->unix_socket_perms) {
321 if (lws_plat_user_colon_group_to_ids(
322 vhost->unix_socket_perms, &uid, &gid)) {
323 lwsl_err("%s: Failed to translate %s\n",
324 __func__, vhost->unix_socket_perms);
325 return LWS_ITOSA_NOT_EXIST;
326 }
327 }
328 if (uid && gid) {
329 if (chown(serv_unix.sun_path, uid, gid)) {
330 lwsl_err("%s: failed to set %s perms %u:%u\n",
331 __func__, serv_unix.sun_path,
332 (unsigned int)uid, (unsigned int)gid);
333
334 return LWS_ITOSA_NOT_EXIST;
335 }
336 lwsl_notice("%s: vh %s unix skt %s perms %u:%u\n",
337 __func__, vhost->name, serv_unix.sun_path,
338 (unsigned int)uid, (unsigned int)gid);
339
340 if (chmod(serv_unix.sun_path, 0660)) {
341 lwsl_err("%s: failed to set %s to 0600 mode\n",
342 __func__, serv_unix.sun_path);
343
344 return LWS_ITOSA_NOT_EXIST;
345 }
346 }
347 }
348 #endif
349
350 #ifndef LWS_PLAT_OPTEE
351 if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
352 lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
353 else
354 #endif
355 #if defined(LWS_WITH_IPV6)
356 port = (sin.ss_family == AF_INET6) ?
357 ntohs(((struct sockaddr_in6 *) &sin)->sin6_port) :
358 ntohs(((struct sockaddr_in *) &sin)->sin_port);
359 #else
360 {
361 struct sockaddr_in sain;
362 memcpy(&sain, &sin, sizeof(sain));
363 port = ntohs(sain.sin_port);
364 }
365 #endif
366
367 return port;
368 }
369
370 unsigned int
lws_retry_get_delay_ms(struct lws_context * context,const lws_retry_bo_t * retry,uint16_t * ctry,char * conceal)371 lws_retry_get_delay_ms(struct lws_context *context,
372 const lws_retry_bo_t *retry, uint16_t *ctry,
373 char *conceal)
374 {
375 uint64_t ms = 3000, pc = 30; /* sane-ish defaults if no retry table */
376 uint16_t ra;
377
378 if (conceal)
379 *conceal = 0;
380
381 if (retry) {
382 if (*ctry < retry->retry_ms_table_count)
383 ms = retry->retry_ms_table[*ctry];
384 else
385 ms = retry->retry_ms_table[
386 retry->retry_ms_table_count - 1];
387
388 /* if no percent given, use the default 30% */
389 if (retry->jitter_percent)
390 pc = retry->jitter_percent;
391 }
392
393 if (lws_get_random(context, &ra, sizeof(ra)) == sizeof(ra))
394 ms += ((ms * pc * ra) >> 16) / 100;
395 else
396 assert(0);
397
398 if (*ctry < 0xffff)
399 (*ctry)++;
400
401 if (retry && conceal)
402 *conceal = (int)*ctry <= retry->conceal_count;
403
404 return (unsigned int)ms;
405 }
406
407 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)408 lws_retry_sul_schedule(struct lws_context *context, int tid,
409 lws_sorted_usec_list_t *sul,
410 const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
411 {
412 char conceal;
413 uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
414
415 if (!conceal)
416 return 1;
417
418 lwsl_info("%s: sul %p: scheduling retry in %dms\n", __func__, sul,
419 (int)ms);
420
421 lws_sul_schedule(context, tid, sul, cb, ms * 1000);
422
423 return 0;
424 }
425
426 int
lws_retry_sul_schedule_retry_wsi(struct lws * wsi,lws_sorted_usec_list_t * sul,sul_cb_t cb,uint16_t * ctry)427 lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
428 sul_cb_t cb, uint16_t *ctry)
429 {
430 return lws_retry_sul_schedule(wsi->context, wsi->tsi, sul,
431 wsi->retry_policy, cb, ctry);
432 }
433
434 #if defined(LWS_WITH_IPV6)
435 unsigned long
lws_get_addr_scope(const char * ipaddr)436 lws_get_addr_scope(const char *ipaddr)
437 {
438 unsigned long scope = 0;
439
440 #ifndef WIN32
441 struct ifaddrs *addrs, *addr;
442 char ip[NI_MAXHOST];
443 unsigned int i;
444
445 getifaddrs(&addrs);
446 for (addr = addrs; addr; addr = addr->ifa_next) {
447 if (!addr->ifa_addr ||
448 addr->ifa_addr->sa_family != AF_INET6)
449 continue;
450
451 getnameinfo(addr->ifa_addr,
452 sizeof(struct sockaddr_in6),
453 ip, sizeof(ip),
454 NULL, 0, NI_NUMERICHOST);
455
456 i = 0;
457 while (ip[i])
458 if (ip[i++] == '%') {
459 ip[i - 1] = '\0';
460 break;
461 }
462
463 if (!strcmp(ip, ipaddr)) {
464 scope = if_nametoindex(addr->ifa_name);
465 break;
466 }
467 }
468 freeifaddrs(addrs);
469 #else
470 PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
471 PIP_ADAPTER_UNICAST_ADDRESS addr;
472 ULONG size = 0;
473 DWORD ret;
474 struct sockaddr_in6 *sockaddr;
475 char ip[NI_MAXHOST];
476 unsigned int i;
477 int found = 0;
478
479 for (i = 0; i < 5; i++)
480 {
481 ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
482 NULL, addrs, &size);
483 if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) {
484 break;
485 } else if (ret == ERROR_BUFFER_OVERFLOW)
486 {
487 if (addrs)
488 free(addrs);
489 addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
490 } else
491 {
492 if (addrs)
493 {
494 free(addrs);
495 addrs = NULL;
496 }
497 lwsl_err("Failed to get IPv6 address table (%d)", ret);
498 break;
499 }
500 }
501
502 if ((ret == NO_ERROR) && (addrs)) {
503 adapter = addrs;
504 while (adapter && !found) {
505 addr = adapter->FirstUnicastAddress;
506 while (addr && !found) {
507 if (addr->Address.lpSockaddr->sa_family ==
508 AF_INET6) {
509 sockaddr = (struct sockaddr_in6 *)
510 (addr->Address.lpSockaddr);
511
512 lws_plat_inet_ntop(sockaddr->sin6_family,
513 &sockaddr->sin6_addr,
514 ip, sizeof(ip));
515
516 if (!strcmp(ip, ipaddr)) {
517 scope = sockaddr->sin6_scope_id;
518 found = 1;
519 break;
520 }
521 }
522 addr = addr->Next;
523 }
524 adapter = adapter->Next;
525 }
526 }
527 if (addrs)
528 free(addrs);
529 #endif
530
531 return scope;
532 }
533 #endif
534
535 /*
536 * https://en.wikipedia.org/wiki/IPv6_address
537 *
538 * An IPv6 address is represented as eight groups of four hexadecimal digits,
539 * each group representing 16 bits (two octets, a group sometimes also called a
540 * hextet[6][7]). The groups are separated by colons (:). An example of an IPv6
541 * address is:
542 *
543 * 2001:0db8:85a3:0000:0000:8a2e:0370:7334
544 *
545 * The hexadecimal digits are case-insensitive, but IETF recommendations suggest
546 * the use of lower case letters. The full representation of eight 4-digit
547 * groups may be simplified by several techniques, eliminating parts of the
548 * representation.
549 *
550 * Leading zeroes in a group may be omitted, but each group must retain at least
551 * one hexadecimal digit.[1] Thus, the example address may be written as:
552 *
553 * 2001:db8:85a3:0:0:8a2e:370:7334
554 *
555 * One or more consecutive groups containing zeros only may be replaced with a
556 * single empty group, using two consecutive colons (::).[1] The substitution
557 * may only be applied once in the address, however, because multiple
558 * occurrences would create an ambiguous representation. Thus, the example
559 * address can be further simplified:
560 *
561 * 2001:db8:85a3::8a2e:370:7334
562 *
563 * The localhost (loopback) address, 0:0:0:0:0:0:0:1, and the IPv6 unspecified
564 * address, 0:0:0:0:0:0:0:0, are reduced to ::1 and ::, respectively.
565 *
566 * During the transition of the Internet from IPv4 to IPv6, it is typical to
567 * operate in a mixed addressing environment. For such use cases, a special
568 * notation has been introduced, which expresses IPv4-mapped and IPv4-compatible
569 * IPv6 addresses by writing the least-significant 32 bits of an address in the
570 * familiar IPv4 dot-decimal notation, whereas the other 96 (most significant)
571 * bits are written in IPv6 format. For example, the IPv4-mapped IPv6 address
572 * ::ffff:c000:0280 is written as ::ffff:192.0.2.128, thus expressing clearly
573 * the original IPv4 address that was mapped to IPv6.
574 */
575
576 int
lws_parse_numeric_address(const char * ads,uint8_t * result,size_t max_len)577 lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len)
578 {
579 struct lws_tokenize ts;
580 uint8_t *orig = result, temp[16];
581 int sects = 0, ipv6 = !!strchr(ads, ':'), skip_point = -1, dm = 0;
582 char t[5];
583 size_t n;
584 long u;
585
586 lws_tokenize_init(&ts, ads, LWS_TOKENIZE_F_NO_INTEGERS |
587 LWS_TOKENIZE_F_MINUS_NONTERM);
588 ts.len = strlen(ads);
589 if (!ipv6 && ts.len < 7)
590 return -1;
591
592 if (ipv6 && ts.len < 2)
593 return -2;
594
595 if (!ipv6 && max_len < 4)
596 return -3;
597
598 if (ipv6 && max_len < 16)
599 return -4;
600
601 if (ipv6)
602 memset(result, 0, max_len);
603
604 do {
605 ts.e = lws_tokenize(&ts);
606 switch (ts.e) {
607 case LWS_TOKZE_TOKEN:
608 dm = 0;
609 if (ipv6) {
610 if (ts.token_len > 4)
611 return -1;
612 memcpy(t, ts.token, ts.token_len);
613 t[ts.token_len] = '\0';
614 for (n = 0; n < ts.token_len; n++)
615 if (t[n] < '0' || t[n] > 'f' ||
616 (t[n] > '9' && t[n] < 'A') ||
617 (t[n] > 'F' && t[n] < 'a'))
618 return -1;
619 u = strtol(t, NULL, 16);
620 if (u > 0xffff)
621 return -5;
622 *result++ = (uint8_t)(u >> 8);
623 } else {
624 if (ts.token_len > 3)
625 return -1;
626 memcpy(t, ts.token, ts.token_len);
627 t[ts.token_len] = '\0';
628 for (n = 0; n < ts.token_len; n++)
629 if (t[n] < '0' || t[n] > '9')
630 return -1;
631 u = strtol(t, NULL, 10);
632 if (u > 0xff)
633 return -6;
634 }
635 if (u < 0)
636 return -7;
637 *result++ = (uint8_t)u;
638 sects++;
639 break;
640
641 case LWS_TOKZE_DELIMITER:
642 if (dm++) {
643 if (dm > 2)
644 return -8;
645 if (*ts.token != ':')
646 return -9;
647 /* back to back : */
648 *result++ = 0;
649 *result++ = 0;
650 skip_point = lws_ptr_diff(result, orig);
651 break;
652 }
653 if (ipv6 && orig[2] == 0xff && orig[3] == 0xff &&
654 skip_point == 2) {
655 /* ipv4 backwards compatible format */
656 ipv6 = 0;
657 memset(orig, 0, max_len);
658 orig[10] = 0xff;
659 orig[11] = 0xff;
660 skip_point = -1;
661 result = &orig[12];
662 sects = 0;
663 break;
664 }
665 if (ipv6 && *ts.token != ':')
666 return -10;
667 if (!ipv6 && *ts.token != '.')
668 return -11;
669 break;
670
671 case LWS_TOKZE_ENDED:
672 if (!ipv6 && sects == 4)
673 return lws_ptr_diff(result, orig);
674 if (ipv6 && sects == 8)
675 return lws_ptr_diff(result, orig);
676 if (skip_point != -1) {
677 int ow = lws_ptr_diff(result, orig);
678 /*
679 * contains ...::...
680 */
681 if (ow == 16)
682 return 16;
683 memcpy(temp, &orig[skip_point], ow - skip_point);
684 memset(&orig[skip_point], 0, 16 - skip_point);
685 memcpy(&orig[16 - (ow - skip_point)], temp,
686 ow - skip_point);
687
688 return 16;
689 }
690 return -12;
691
692 default: /* includes ENDED */
693 lwsl_err("%s: malformed ip address\n",
694 __func__);
695
696 return -13;
697 }
698 } while (ts.e > 0 && result - orig <= (int)max_len);
699
700 lwsl_err("%s: ended on e %d\n", __func__, ts.e);
701
702 return -14;
703 }
704
705 int
lws_sa46_parse_numeric_address(const char * ads,lws_sockaddr46 * sa46)706 lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46)
707 {
708 uint8_t a[16];
709 int n;
710
711 n = lws_parse_numeric_address(ads, a, sizeof(a));
712 if (n < 0)
713 return -1;
714
715 #if defined(LWS_WITH_IPV6)
716 if (n == 16) {
717 sa46->sa6.sin6_family = AF_INET6;
718 memcpy(sa46->sa6.sin6_addr.s6_addr, a,
719 sizeof(sa46->sa6.sin6_addr.s6_addr));
720
721 return 0;
722 }
723 #endif
724
725 if (n != 4)
726 return -1;
727
728 sa46->sa4.sin_family = AF_INET;
729 memcpy(&sa46->sa4.sin_addr.s_addr, a,
730 sizeof(sa46->sa4.sin_addr.s_addr));
731
732 return 0;
733 }
734
735 int
lws_write_numeric_address(const uint8_t * ads,int size,char * buf,size_t len)736 lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len)
737 {
738 char c, elided = 0, soe = 0, zb = -1, n, ipv4 = 0;
739 const char *e = buf + len;
740 char *obuf = buf;
741 int q = 0;
742
743 if (size == 4)
744 return lws_snprintf(buf, len, "%u.%u.%u.%u",
745 ads[0], ads[1], ads[2], ads[3]);
746
747 if (size != 16)
748 return -1;
749
750 for (c = 0; c < (char)size / 2; c++) {
751 uint16_t v = (ads[q] << 8) | ads[q + 1];
752
753 if (buf + 8 > e)
754 return -1;
755
756 q += 2;
757 if (soe) {
758 if (v)
759 *buf++ = ':';
760 /* fall thru to print hex value */
761 } else
762 if (!elided && !soe && !v) {
763 elided = soe = 1;
764 zb = c;
765 continue;
766 }
767
768 if (ipv4) {
769 n = lws_snprintf(buf, e - buf, "%u.%u",
770 ads[q - 2], ads[q - 1]);
771 buf += n;
772 if (c == 6)
773 *buf++ = '.';
774 } else {
775 if (soe && !v)
776 continue;
777 if (c)
778 *buf++ = ':';
779
780 buf += lws_snprintf(buf, e - buf, "%x", v);
781
782 if (soe && v) {
783 soe = 0;
784 if (c == 5 && v == 0xffff && !zb) {
785 ipv4 = 1;
786 *buf++ = ':';
787 }
788 }
789 }
790 }
791 if (buf + 3 > e)
792 return -1;
793
794 if (soe) { /* as is the case for all zeros */
795 *buf++ = ':';
796 *buf++ = ':';
797 *buf = '\0';
798 }
799
800 return lws_ptr_diff(buf, obuf);
801 }
802
803 int
lws_sa46_write_numeric_address(lws_sockaddr46 * sa46,char * buf,size_t len)804 lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
805 {
806 *buf = '\0';
807 #if defined(LWS_WITH_IPV6)
808 if (sa46->sa4.sin_family == AF_INET6)
809 return lws_write_numeric_address(
810 (uint8_t *)&sa46->sa6.sin6_addr, 16, buf, len);
811 #endif
812 if (sa46->sa4.sin_family == AF_INET)
813 return lws_write_numeric_address(
814 (uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
815
816 return -1;
817 }
818
819 int
lws_sa46_compare_ads(const lws_sockaddr46 * sa46a,const lws_sockaddr46 * sa46b)820 lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
821 {
822 if (sa46a->sa4.sin_family != sa46b->sa4.sin_family)
823 return 1;
824
825 #if defined(LWS_WITH_IPV6)
826 if (sa46a->sa4.sin_family == AF_INET6)
827 return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
828 #endif
829
830 return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
831 }
832
833 lws_state_manager_t *
lws_system_get_state_manager(struct lws_context * context)834 lws_system_get_state_manager(struct lws_context *context)
835 {
836 return &context->mgr_system;
837 }
838