1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2021 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 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
26 #define _WINSOCK_DEPRECATED_NO_WARNINGS
27 #endif
28 #define MBEDTLS_ALLOW_PRIVATE_ACCESS
29 #include "private-lib-core.h"
30
31 #if defined(LWS_WITH_MBEDTLS)
32 #if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
33 #include "mbedtls/net_sockets.h"
34 #else
35 #include "mbedtls/net.h"
36 #endif
37 #endif
38
39 int
lws_send_pipe_choked(struct lws * wsi)40 lws_send_pipe_choked(struct lws *wsi)
41 { struct lws *wsi_eff;
42
43 #if defined(LWS_WITH_HTTP2)
44 wsi_eff = lws_get_network_wsi(wsi);
45 #else
46 wsi_eff = wsi;
47 #endif
48 /* the fact we checked implies we avoided back-to-back writes */
49 wsi_eff->could_have_pending = 0;
50
51 /* treat the fact we got a truncated send pending as if we're choked */
52 if (lws_has_buffered_out(wsi_eff)
53 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
54 ||wsi->http.comp_ctx.buflist_comp ||
55 wsi->http.comp_ctx.may_have_more
56 #endif
57 )
58 return 1;
59
60 return (int)wsi_eff->sock_send_blocking;
61 }
62
63 int
lws_poll_listen_fd(struct lws_pollfd * fd)64 lws_poll_listen_fd(struct lws_pollfd *fd)
65 {
66 fd_set readfds;
67 struct timeval tv = { 0, 0 };
68
69 assert((fd->events & LWS_POLLIN) == LWS_POLLIN);
70
71 FD_ZERO(&readfds);
72 FD_SET(fd->fd, &readfds);
73
74 return select(((int)fd->fd) + 1, &readfds, NULL, NULL, &tv);
75 }
76
77 int
lws_plat_set_nonblocking(lws_sockfd_type fd)78 lws_plat_set_nonblocking(lws_sockfd_type fd)
79 {
80 u_long optl = 1;
81 int result = !!ioctlsocket(fd, FIONBIO, &optl);
82 if (result)
83 {
84 int error = LWS_ERRNO;
85 lwsl_err("ioctlsocket FIONBIO 1 failed with error %d\n", error);
86 }
87 return result;
88 }
89
90 int
lws_plat_set_socket_options(struct lws_vhost * vhost,lws_sockfd_type fd,int unix_skt)91 lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
92 int unix_skt)
93 {
94 int optval = 1;
95 int optlen = sizeof(optval);
96 DWORD dwBytesRet;
97 struct tcp_keepalive alive;
98 int protonbr;
99 #ifndef _WIN32_WCE
100 struct protoent *tcp_proto;
101 #endif
102
103 if (vhost->ka_time) {
104 /* enable keepalive on this socket */
105 optval = 1;
106 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
107 (const char *)&optval, optlen) < 0) {
108 int error = LWS_ERRNO;
109 lwsl_err("setsockopt SO_KEEPALIVE 1 failed with error %d\n", error);
110 return 1;
111 }
112
113 alive.onoff = TRUE;
114 alive.keepalivetime = vhost->ka_time * 1000;
115 alive.keepaliveinterval = vhost->ka_interval * 1000;
116
117 if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
118 NULL, 0, &dwBytesRet, NULL, NULL)) {
119 int error = LWS_ERRNO;
120 lwsl_err("WSAIoctl SIO_KEEPALIVE_VALS 1 %lu %lu failed with error %d\n", alive.keepalivetime, alive.keepaliveinterval, error);
121 return 1;
122 }
123 }
124
125 /* Disable Nagle */
126 optval = 1;
127 #ifndef _WIN32_WCE
128 tcp_proto = getprotobyname("TCP");
129 if (!tcp_proto) {
130 int error = LWS_ERRNO;
131 lwsl_warn("getprotobyname(\"TCP\") failed with error, falling back to 6 %d\n", error);
132 protonbr = 6; /* IPPROTO_TCP */
133 } else
134 protonbr = tcp_proto->p_proto;
135 #else
136 protonbr = 6;
137 #endif
138
139 if (setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen) ) {
140 int error = LWS_ERRNO;
141 lwsl_warn("setsockopt TCP_NODELAY 1 failed with error %d\n", error);
142 }
143
144 return lws_plat_set_nonblocking(fd);
145 }
146
147 int
lws_plat_set_socket_options_ip(lws_sockfd_type fd,uint8_t pri,int lws_flags)148 lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
149 {
150 /*
151 * Seems to require "differeniated services" but no docs
152 *
153 * https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
154 * https://docs.microsoft.com/en-us/previous-versions/windows/desktop/qos/differentiated-services
155 */
156 lwsl_warn("%s: not implemented on windows platform\n", __func__);
157
158 return 0;
159 }
160
161 int
lws_interface_to_sa(int ipv6,const char * ifname,struct sockaddr_in * addr,size_t addrlen)162 lws_interface_to_sa(int ipv6,
163 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
164 {
165 long long address;
166 #ifdef LWS_WITH_IPV6
167 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
168
169 if (ipv6) {
170 if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
171 return LWS_ITOSA_USABLE;
172 }
173 }
174 #endif
175
176 address = inet_addr(ifname);
177
178 if (address == INADDR_NONE) {
179 struct hostent *entry = gethostbyname(ifname);
180 if (entry)
181 address = ((struct in_addr *)entry->h_addr_list[0])->s_addr;
182 }
183
184 if (address == INADDR_NONE)
185 return LWS_ITOSA_NOT_EXIST;
186
187 addr->sin_addr.s_addr = (unsigned long)(lws_intptr_t)address;
188
189 return LWS_ITOSA_USABLE;
190 }
191
192 void
lws_plat_insert_socket_into_fds(struct lws_context * context,struct lws * wsi)193 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
194 {
195 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
196
197 #if defined(LWS_WITH_UDP)
198 if (wsi->udp) {
199 lwsl_info("%s: UDP\n", __func__);
200 pt->fds[pt->fds_count].events |= LWS_POLLIN;
201 }
202 #endif
203
204 if (context->event_loop_ops->io)
205 context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
206
207 pt->fds[pt->fds_count++].revents = 0;
208
209 lws_plat_change_pollfd(context, wsi, &pt->fds[pt->fds_count - 1]);
210 }
211
212 void
lws_plat_delete_socket_from_fds(struct lws_context * context,struct lws * wsi,int m)213 lws_plat_delete_socket_from_fds(struct lws_context *context,
214 struct lws *wsi, int m)
215 {
216 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
217
218 pt->fds_count--;
219 }
220
221
222 int
lws_plat_check_connection_error(struct lws * wsi)223 lws_plat_check_connection_error(struct lws *wsi)
224 {
225 int optVal;
226 int optLen = sizeof(int);
227
228 if (getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
229 (char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
230 optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
231 optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
232 lwsl_debug("Connect failed SO_ERROR=%d\n", optVal);
233 return 1;
234 }
235
236 return 0;
237 }
238
239 int
lws_plat_change_pollfd(struct lws_context * context,struct lws * wsi,struct lws_pollfd * pfd)240 lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
241 struct lws_pollfd *pfd)
242 {
243 //struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
244
245 return 0;
246 }
247
248 #if defined(LWS_WITH_TLS)
249
250 int
lws_plat_vhost_tls_client_ctx_init(struct lws_vhost * vhost)251 lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
252 {
253 #if !defined(LWS_WITH_MBEDTLS) && defined(LWS_SSL_CLIENT_USE_OS_CA_CERTS)
254 PCCERT_CONTEXT pcc = NULL;
255 CERT_ENHKEY_USAGE* ceu = NULL;
256 DWORD ceu_alloc = 0;
257 X509_STORE* store;
258 HCERTSTORE hStore;
259 int imps = 0;
260
261 if (lws_check_opt(vhost->options,
262 LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
263 return 0;
264
265 /*
266 * Windows Trust Store code adapted from curl (MIT) openssl.c
267 * https://github.com/warmcat/libwebsockets/pull/2233
268 */
269
270 store = SSL_CTX_get_cert_store(vhost->tls.ssl_client_ctx);
271 hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, TEXT("ROOT"));
272
273 if (!hStore) {
274 lwsl_notice("%s: no store\n", __func__);
275 return 1;
276 }
277
278 do {
279 const unsigned char* ecert;
280 char cert_name[256];
281 DWORD req_size = 0;
282 BYTE key_usage[2];
283 FILETIME ft;
284 X509* x509;
285
286 pcc = CertEnumCertificatesInStore(hStore, pcc);
287 if (!pcc)
288 break;
289
290 if (!CertGetNameStringA(pcc, CERT_NAME_SIMPLE_DISPLAY_TYPE,
291 0, NULL, cert_name, sizeof(cert_name)))
292 strcpy(cert_name, "Unknown");
293
294 lwsl_debug("%s: Checking cert \"%s\"\n", __func__, cert_name);
295
296 ecert = (const unsigned char*)pcc->pbCertEncoded;
297 if (!ecert)
298 continue;
299
300 GetSystemTimeAsFileTime(&ft);
301 if (CompareFileTime(&pcc->pCertInfo->NotBefore, &ft) > 0 ||
302 CompareFileTime(&ft, &pcc->pCertInfo->NotAfter) > 0)
303 continue;
304
305 /* If key usage exists check for signing attribute */
306 if (CertGetIntendedKeyUsage(pcc->dwCertEncodingType,
307 pcc->pCertInfo,
308 key_usage, sizeof(key_usage))) {
309 if (!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
310 continue;
311 } else
312 if (GetLastError())
313 continue;
314
315 /*
316 * If enhanced key usage exists check for server auth attribute.
317 *
318 * Note "In a Microsoft environment, a certificate might also
319 * have EKU extended properties that specify valid uses for the
320 * certificate."
321 * The call below checks both, and behavior varies depending on
322 * what is found. For more details see CertGetEnhancedKeyUsage
323 * doc.
324 */
325 if (!CertGetEnhancedKeyUsage(pcc, 0, NULL, &req_size))
326 continue;
327
328 if (req_size && req_size > ceu_alloc) {
329 void* tmp = lws_realloc(ceu, req_size, __func__);
330
331 if (!tmp) {
332 lwsl_err("%s: OOM", __func__);
333 break;
334 }
335
336 ceu = (CERT_ENHKEY_USAGE*)tmp;
337 ceu_alloc = req_size;
338 }
339
340 if (!CertGetEnhancedKeyUsage(pcc, 0, ceu, &req_size))
341 continue;
342
343 if (!ceu || (ceu && !ceu->cUsageIdentifier)) {
344 /*
345 * "If GetLastError returns CRYPT_E_NOT_FOUND, the
346 * certificate is good for all uses. If it returns
347 * zero, the certificate has no valid uses."
348 */
349 if ((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
350 continue;
351
352 /* ... allow it... */
353
354 } else
355 if (ceu) {
356 BOOL found = FALSE;
357 DWORD i;
358
359 /*
360 * If there is a CEU, check that it specifies
361 * we can use the cert for server validation
362 */
363
364 for (i = 0; i < ceu->cUsageIdentifier; i++) {
365 if (strcmp("1.3.6.1.5.5.7.3.1"
366 /* OID server auth */,
367 ceu->rgpszUsageIdentifier[i]))
368 continue;
369
370 found = TRUE;
371 break;
372 }
373
374 if (!found)
375 /* Don't use cert if no usage match */
376 continue;
377 }
378
379 x509 = d2i_X509(NULL, &ecert, pcc->cbCertEncoded);
380 if (!x509)
381 /* We can't parse it as am X.509, skip it */
382 continue;
383
384 if (X509_STORE_add_cert(store, x509) == 1) {
385 lwsl_debug("%s: Imported cert \"%s\"\n", __func__,
386 cert_name);
387 imps++;
388 }
389
390 /*
391 * Treat failure as nonfatal, eg, may be dupe
392 */
393
394 X509_free(x509);
395 } while (1);
396
397 lws_free(ceu);
398 CertFreeCertificateContext(pcc);
399 CertCloseStore(hStore, 0);
400
401 lwsl_notice("%s: Imported %d certs from plat store\n", __func__, imps);
402 #endif
403
404 return 0;
405 }
406
407 #endif
408
409 const char *
lws_plat_inet_ntop(int af,const void * src,char * dst,socklen_t cnt)410 lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
411 {
412 WCHAR *buffer;
413 size_t bufferlen = (size_t)cnt;
414 BOOL ok = FALSE;
415
416 buffer = lws_malloc(bufferlen * 2, "inet_ntop");
417 if (!buffer) {
418 lwsl_err("Out of memory\n");
419 return NULL;
420 }
421
422 if (af == AF_INET) {
423 struct sockaddr_in srcaddr;
424 memset(&srcaddr, 0, sizeof(srcaddr));
425 srcaddr.sin_family = AF_INET;
426 memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
427
428 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr,
429 sizeof(srcaddr), 0, buffer,
430 (LPDWORD)&bufferlen))
431 ok = TRUE;
432 #ifdef LWS_WITH_IPV6
433 } else if (af == AF_INET6) {
434 struct sockaddr_in6 srcaddr;
435 memset(&srcaddr, 0, sizeof(srcaddr));
436 srcaddr.sin6_family = AF_INET6;
437 memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
438
439 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr,
440 sizeof(srcaddr), 0, buffer,
441 (LPDWORD)&bufferlen))
442 ok = TRUE;
443 #endif
444 } else
445 lwsl_err("Unsupported type\n");
446
447 if (!ok) {
448 int rv = WSAGetLastError();
449 lwsl_err("WSAAddressToString() : %d\n", rv);
450 } else {
451 if (WideCharToMultiByte(CP_ACP, 0, buffer, (int)bufferlen, dst,
452 cnt, 0, NULL) <= 0)
453 ok = FALSE;
454 }
455
456 lws_free(buffer);
457 return ok ? dst : NULL;
458 }
459
460 int
lws_plat_inet_pton(int af,const char * src,void * dst)461 lws_plat_inet_pton(int af, const char *src, void *dst)
462 {
463 WCHAR *buffer;
464 size_t bufferlen = strlen(src) + 1;
465 BOOL ok = FALSE;
466
467 buffer = lws_malloc(bufferlen * 2, "inet_pton");
468 if (!buffer) {
469 lwsl_err("Out of memory\n");
470 return -1;
471 }
472
473 if (MultiByteToWideChar(CP_ACP, 0, src, (int)bufferlen, buffer,
474 (int)bufferlen) <= 0) {
475 lwsl_err("Failed to convert multi byte to wide char\n");
476 lws_free(buffer);
477 return -1;
478 }
479
480 if (af == AF_INET) {
481 struct sockaddr_in dstaddr;
482 int dstaddrlen = sizeof(dstaddr);
483
484 memset(&dstaddr, 0, sizeof(dstaddr));
485 dstaddr.sin_family = AF_INET;
486
487 if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
488 ok = TRUE;
489 memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
490 }
491 #ifdef LWS_WITH_IPV6
492 } else if (af == AF_INET6) {
493 struct sockaddr_in6 dstaddr;
494 int dstaddrlen = sizeof(dstaddr);
495
496 memset(&dstaddr, 0, sizeof(dstaddr));
497 dstaddr.sin6_family = AF_INET6;
498
499 if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
500 ok = TRUE;
501 memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
502 }
503 #endif
504 } else
505 lwsl_err("Unsupported type\n");
506
507 if (!ok) {
508 int rv = WSAGetLastError();
509 lwsl_err("WSAAddressToString() : %d\n", rv);
510 }
511
512 lws_free(buffer);
513 return ok ? 1 : -1;
514 }
515
516 int
lws_plat_ifname_to_hwaddr(int fd,const char * ifname,uint8_t * hwaddr,int len)517 lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
518 {
519 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
520
521 return -1;
522 }
523
524 int
lws_plat_rawudp_broadcast(uint8_t * p,const uint8_t * canned,size_t canned_len,size_t n,int fd,const char * iface)525 lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
526 size_t n, int fd, const char *iface)
527 {
528 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
529
530 return -1;
531 }
532
533 int
lws_plat_if_up(const char * ifname,int fd,int up)534 lws_plat_if_up(const char *ifname, int fd, int up)
535 {
536 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
537
538 return -1;
539 }
540
541 int
lws_plat_BINDTODEVICE(lws_sockfd_type fd,const char * ifname)542 lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
543 {
544 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
545
546 return -1;
547 }
548
549 int
lws_plat_ifconfig(int fd,uint8_t * ip,lws_dhcpc_ifstate_t * is)550 lws_plat_ifconfig(int fd, uint8_t *ip, lws_dhcpc_ifstate_t *is)
551 {
552 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
553
554 return -1;
555 }
556
557 #if defined(LWS_WITH_MBEDTLS)
558 int
lws_plat_mbedtls_net_send(void * ctx,const uint8_t * buf,size_t len)559 lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
560 {
561 int fd = ((mbedtls_net_context *) ctx)->fd;
562 int ret, en;
563
564 if (fd < 0)
565 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
566
567 ret = send(fd, buf, (unsigned int)len, 0);
568 if (ret >= 0)
569 return ret;
570
571 en = LWS_ERRNO;
572 if (en == EAGAIN || en == EWOULDBLOCK)
573 return MBEDTLS_ERR_SSL_WANT_WRITE;
574
575 ret = WSAGetLastError();
576 lwsl_notice("%s: errno %d, GLE %d\n", __func__, en, ret);
577 if (ret == WSAECONNRESET )
578 return( MBEDTLS_ERR_NET_CONN_RESET );
579
580 return MBEDTLS_ERR_NET_SEND_FAILED;
581 }
582
583 int
lws_plat_mbedtls_net_recv(void * ctx,unsigned char * buf,size_t len)584 lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
585 {
586 int fd = ((mbedtls_net_context *) ctx)->fd;
587 int ret, en;
588
589 if (fd < 0)
590 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
591
592 ret = (int)recv(fd, buf, (unsigned int)len, 0);
593 if (ret >= 0)
594 return ret;
595
596 en = LWS_ERRNO;
597 if (en == EAGAIN || en == EWOULDBLOCK)
598 return MBEDTLS_ERR_SSL_WANT_READ;
599
600 ret = WSAGetLastError();
601 lwsl_notice("%s: errno %d, GLE %d\n", __func__, en, ret);
602
603 if (ret == WSAECONNRESET)
604 return MBEDTLS_ERR_NET_CONN_RESET;
605
606 return MBEDTLS_ERR_NET_RECV_FAILED;
607 }
608 #endif
609
610