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