• 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 #if !defined(_GNU_SOURCE)
26 #define _GNU_SOURCE
27 #endif
28 #include "private-lib-core.h"
29 
30 #include <sys/ioctl.h>
31 #include <net/route.h>
32 #include <net/if.h>
33 
34 #include <pwd.h>
35 #include <grp.h>
36 
37 
38 
39 int
lws_send_pipe_choked(struct lws * wsi)40 lws_send_pipe_choked(struct lws *wsi)
41 {
42 	struct lws_pollfd fds;
43 	struct lws *wsi_eff;
44 
45 #if !defined(LWS_WITHOUT_EXTENSIONS)
46 	if (wsi->ws && wsi->ws->tx_draining_ext)
47 		return 1;
48 #endif
49 
50 #if defined(LWS_WITH_HTTP2)
51 	wsi_eff = lws_get_network_wsi(wsi);
52 #else
53 	wsi_eff = wsi;
54 #endif
55 
56 	/* the fact we checked implies we avoided back-to-back writes */
57 	wsi_eff->could_have_pending = 0;
58 
59 	/* treat the fact we got a truncated send pending as if we're choked */
60 	if (lws_has_buffered_out(wsi_eff)
61 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
62 	    ||wsi->http.comp_ctx.buflist_comp ||
63 	    wsi->http.comp_ctx.may_have_more
64 #endif
65 	    )
66 		return 1;
67 
68 	fds.fd = wsi_eff->desc.sockfd;
69 	fds.events = POLLOUT;
70 	fds.revents = 0;
71 
72 	if (poll(&fds, 1, 0) != 1)
73 		return 1;
74 
75 	if ((fds.revents & POLLOUT) == 0)
76 		return 1;
77 
78 	/* okay to send another packet without blocking */
79 
80 	return 0;
81 }
82 
83 int
lws_plat_set_nonblocking(lws_sockfd_type fd)84 lws_plat_set_nonblocking(lws_sockfd_type fd)
85 {
86 	return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
87 }
88 
89 int
lws_plat_set_socket_options(struct lws_vhost * vhost,int fd,int unix_skt)90 lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
91 {
92 	int optval = 1;
93 	socklen_t optlen = sizeof(optval);
94 
95 #if defined(__APPLE__) || \
96     defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
97     defined(__NetBSD__) || \
98     defined(__OpenBSD__) || \
99     defined(__HAIKU__)
100 	struct protoent *tcp_proto;
101 #endif
102 
103 	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
104 
105 	if (!unix_skt && vhost->ka_time) {
106 		/* enable keepalive on this socket */
107 		optval = 1;
108 		if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
109 			       (const void *)&optval, optlen) < 0)
110 			return 1;
111 
112 #if defined(__APPLE__) || \
113     defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
114     defined(__NetBSD__) || \
115     defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \
116     defined(__HAIKU__)
117 
118 		/*
119 		 * didn't find a way to set these per-socket, need to
120 		 * tune kernel systemwide values
121 		 */
122 #else
123 		/* set the keepalive conditions we want on it too */
124 
125 #if defined(LWS_HAVE_TCP_USER_TIMEOUT)
126 		optval = 1000 * (vhost->ka_time +
127 				 (vhost->ka_interval * vhost->ka_probes));
128 		if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
129 			       (const void *)&optval, optlen) < 0)
130 			return 1;
131 #endif
132 		optval = vhost->ka_time;
133 		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
134 			       (const void *)&optval, optlen) < 0)
135 			return 1;
136 
137 		optval = vhost->ka_interval;
138 		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
139 			       (const void *)&optval, optlen) < 0)
140 			return 1;
141 
142 		optval = vhost->ka_probes;
143 		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
144 			       (const void *)&optval, optlen) < 0)
145 			return 1;
146 #endif
147 	}
148 
149 #if defined(SO_BINDTODEVICE)
150 	if (!unix_skt && vhost->bind_iface && vhost->iface) {
151 		lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
152 		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
153 				strlen(vhost->iface)) < 0) {
154 			lwsl_warn("Failed to bind to device %s\n", vhost->iface);
155 			return 1;
156 		}
157 	}
158 #endif
159 
160 	/* Disable Nagle */
161 	optval = 1;
162 #if defined (__sun) || defined(__QNX__)
163 	if (!unix_skt && setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
164 		return 1;
165 #elif !defined(__APPLE__) && \
166       !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) &&        \
167       !defined(__NetBSD__) && \
168       !defined(__OpenBSD__) && \
169       !defined(__HAIKU__)
170 	if (!unix_skt && setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
171 		return 1;
172 #else
173 	tcp_proto = getprotobyname("TCP");
174 	if (!unix_skt && setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
175 		return 1;
176 #endif
177 
178 	return lws_plat_set_nonblocking(fd);
179 }
180 
181 
182 /* cast a struct sockaddr_in6 * into addr for ipv6 */
183 
184 int
lws_interface_to_sa(int ipv6,const char * ifname,struct sockaddr_in * addr,size_t addrlen)185 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
186 		    size_t addrlen)
187 {
188 	int rc = LWS_ITOSA_NOT_EXIST;
189 
190 	struct ifaddrs *ifr;
191 	struct ifaddrs *ifc;
192 #ifdef LWS_WITH_IPV6
193 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
194 #endif
195 
196 	getifaddrs(&ifr);
197 	for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
198 		if (!ifc->ifa_addr)
199 			continue;
200 
201 		lwsl_debug(" interface %s vs %s (fam %d) ipv6 %d\n",
202 			   ifc->ifa_name, ifname,
203 			   ifc->ifa_addr->sa_family, ipv6);
204 
205 		if (strcmp(ifc->ifa_name, ifname))
206 			continue;
207 
208 		switch (ifc->ifa_addr->sa_family) {
209 #if defined(AF_PACKET)
210 		case AF_PACKET:
211 			/* interface exists but is not usable */
212 			rc = LWS_ITOSA_NOT_USABLE;
213 			continue;
214 #endif
215 
216 		case AF_INET:
217 #ifdef LWS_WITH_IPV6
218 			if (ipv6) {
219 				/* map IPv4 to IPv6 */
220 				memset((char *)&addr6->sin6_addr, 0,
221 						sizeof(struct in6_addr));
222 				addr6->sin6_addr.s6_addr[10] = 0xff;
223 				addr6->sin6_addr.s6_addr[11] = 0xff;
224 				memcpy(&addr6->sin6_addr.s6_addr[12],
225 				       &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
226 							sizeof(struct in_addr));
227 				lwsl_debug("%s: uplevelling ipv4 bind to ipv6\n", __func__);
228 			} else
229 #endif
230 				memcpy(addr,
231 					(struct sockaddr_in *)ifc->ifa_addr,
232 						    sizeof(struct sockaddr_in));
233 			break;
234 #ifdef LWS_WITH_IPV6
235 		case AF_INET6:
236 			memcpy(&addr6->sin6_addr,
237 			  &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
238 						       sizeof(struct in6_addr));
239 			break;
240 #endif
241 		default:
242 			continue;
243 		}
244 		rc = LWS_ITOSA_USABLE;
245 	}
246 
247 	freeifaddrs(ifr);
248 
249 	if (rc) {
250 		/* check if bind to IP address */
251 #ifdef LWS_WITH_IPV6
252 		if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
253 			rc = LWS_ITOSA_USABLE;
254 		else
255 #endif
256 		if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
257 			rc = LWS_ITOSA_USABLE;
258 	}
259 
260 	return rc;
261 }
262 
263 
264 const char *
lws_plat_inet_ntop(int af,const void * src,char * dst,int cnt)265 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
266 {
267 	return inet_ntop(af, src, dst, cnt);
268 }
269 
270 int
lws_plat_inet_pton(int af,const char * src,void * dst)271 lws_plat_inet_pton(int af, const char *src, void *dst)
272 {
273 	return inet_pton(af, src, dst);
274 }
275 
276 int
lws_plat_ifname_to_hwaddr(int fd,const char * ifname,uint8_t * hwaddr,int len)277 lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
278 {
279 #if defined(__linux__)
280 	struct ifreq i;
281 
282 	memset(&i, 0, sizeof(i));
283 	lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name));
284 
285 	if (ioctl(fd, SIOCGIFHWADDR, &i) < 0)
286 		return -1;
287 
288 	memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6);
289 
290 	return 6;
291 #else
292 	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
293 
294 	return -1;
295 #endif
296 }
297 
298 int
lws_plat_rawudp_broadcast(uint8_t * p,const uint8_t * canned,int canned_len,int n,int fd,const char * iface)299 lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
300 			  int n, int fd, const char *iface)
301 {
302 #if defined(__linux__)
303 	struct sockaddr_ll sll;
304 	uint16_t *p16 = (uint16_t *)p;
305 	uint32_t ucs = 0;
306 
307 	memcpy(p, canned, canned_len);
308 
309 	p[2] = n >> 8;
310 	p[3] = n;
311 
312 	while (p16 < (uint16_t *)(p + 20))
313 		ucs += ntohs(*p16++);
314 
315 	ucs += ucs >> 16;
316 	ucs ^= 0xffff;
317 
318 	p[10] = ucs >> 8;
319 	p[11] = ucs;
320 	p[24] = (n - 20) >> 8;
321 	p[25] = (n - 20);
322 
323 	memset(&sll, 0, sizeof(sll));
324 	sll.sll_family = AF_PACKET;
325 	sll.sll_protocol = htons(0x800);
326 	sll.sll_halen = 6;
327 	sll.sll_ifindex = if_nametoindex(iface);
328 	memset(sll.sll_addr, 0xff, 6);
329 
330 	return sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll));
331 #else
332 	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
333 
334 	return -1;
335 #endif
336 }
337 
338 int
lws_plat_if_up(const char * ifname,int fd,int up)339 lws_plat_if_up(const char *ifname, int fd, int up)
340 {
341 #if defined(__linux__)
342 	struct ifreq ifr;
343 
344 	memset(&ifr, 0, sizeof(ifr));
345 	lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
346 
347 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
348 		lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__);
349 		return 1;
350 	}
351 
352 	if (up)
353 		ifr.ifr_flags |= IFF_UP;
354 	else
355 		ifr.ifr_flags &= ~IFF_UP;
356 
357 	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
358 		lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__);
359 		return 1;
360 	}
361 
362 	return 0;
363 #else
364 	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
365 
366 	return -1;
367 #endif
368 }
369 
370 int
lws_plat_BINDTODEVICE(lws_sockfd_type fd,const char * ifname)371 lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
372 {
373 #if defined(__linux__)
374 	struct ifreq i;
375 
376 	memset(&i, 0, sizeof(i));
377 	i.ifr_addr.sa_family = AF_INET;
378 	lws_strncpy(i.ifr_ifrn.ifrn_name, ifname,
379 		    sizeof(i.ifr_ifrn.ifrn_name));
380 	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) {
381 		lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO);
382 		return 1;
383 	}
384 
385 	return 0;
386 #else
387 	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
388 
389 	return -1;
390 #endif
391 }
392 
393 int
lws_plat_ifconfig_ip(const char * ifname,int fd,uint8_t * ip,uint8_t * mask_ip,uint8_t * gateway_ip)394 lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
395 			uint8_t *gateway_ip)
396 {
397 #if defined(__linux__)
398 	struct sockaddr_in *addr;
399 	struct sockaddr_in sin;
400 	struct rtentry route;
401 	struct ifreq ifr;
402 
403 	memset(&ifr, 0, sizeof(ifr));
404 	memset(&route, 0, sizeof(route));
405 	memset(&sin, 0, sizeof(sin));
406 
407 	lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
408 
409 	lws_plat_if_up(ifname, fd, 0);
410 
411 	sin.sin_family = AF_INET;
412 	sin.sin_addr.s_addr = htonl(*(uint32_t *)ip);
413 
414 	memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
415 	if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
416 		lwsl_err("%s: SIOCSIFADDR fail\n", __func__);
417 		return 1;
418 	}
419 
420 	sin.sin_addr.s_addr = htonl(*(uint32_t *)mask_ip);
421 	memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
422 	if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
423 		lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__);
424 		return 1;
425 	}
426 
427 	lws_plat_if_up(ifname, fd, 1);
428 
429 	addr = (struct sockaddr_in *)&route.rt_gateway;
430 	addr->sin_family = AF_INET;
431 	addr->sin_addr.s_addr = htonl(*(uint32_t *)gateway_ip);
432 
433 	addr = (struct sockaddr_in *)&route.rt_dst;
434 	addr->sin_family = AF_INET;
435 	addr->sin_addr.s_addr = 0;
436 
437 	addr = (struct sockaddr_in *)&route.rt_genmask;
438 	addr->sin_family = AF_INET;
439 	addr->sin_addr.s_addr = 0;
440 
441 	route.rt_flags = RTF_UP | RTF_GATEWAY;
442 	route.rt_metric = 100;
443 	route.rt_dev = (char *)ifname;
444 
445 	if (ioctl(fd, SIOCADDRT, &route) < 0) {
446 		lwsl_err("%s: SIOCADDRT 0x%x fail: %d\n", __func__,
447 			(unsigned int)htonl(*(uint32_t *)gateway_ip), LWS_ERRNO);
448 		return 1;
449 	}
450 
451 	return 0;
452 #else
453 	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
454 
455 	return -1;
456 #endif
457 }
458