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