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)
29static int
30interface_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
45static int
46lws_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
128const char *
129lws_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
145const char *
146lws_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
153void
154lws_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
186bail:
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
206int
207lws_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
408unsigned int
409lws_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
447int
448lws_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
465int
466lws_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)
504unsigned long
505lws_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
656int
657lws_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
785int
786lws_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
815int
816lws_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
883int
884lws_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
912int
913lws_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
929void
930lws_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)
943void
944lws_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
954int
955lws_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
1008void
1009lws_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)
1022lws_state_manager_t *
1023lws_system_get_state_manager(struct lws_context *context)
1024{
1025	return &context->mgr_system;
1026}
1027#endif
1028