diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cf1781c7..d17d32e5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1487,6 +1487,11 @@ else() endif() endif() +if (LWS_WITH_SOCKS5 AND NOT LWS_WITHOUT_CLIENT) + list(APPEND SOURCES + lib/core-net/socks5-client.c) +endif() + if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_SERVER) list(APPEND SOURCES lib/roles/http/server/server.c diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index a2b21318a..c379b0fc1 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -513,7 +513,9 @@ struct lws_context_creation_info { * If proxy auth is required, use format * "username:password\@server:port" */ unsigned int socks_proxy_port; - /**< VHOST: If socks_proxy_address was non-NULL, uses this port */ + /**< VHOST: If socks_proxy_address was non-NULL, uses this port + * if nonzero, otherwise requires "server:port" in .socks_proxy_address + */ #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) cap_value_t caps[4]; /**< CONTEXT: array holding Linux capabilities you want to diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index a02a8254a..093508cff 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -1127,7 +1127,7 @@ lws_destroy_event_pipe(struct lws *wsi); /* socks */ int -socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len); +lws_socks5c_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len); #if defined(LWS_WITH_SERVER_STATUS) void @@ -1378,6 +1378,24 @@ lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx); int lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname); +int +lws_socks5c_ads_server(struct lws_vhost *vh, + const struct lws_context_creation_info *info); + +int +lws_socks5c_handle_state(struct lws *wsi, struct lws_pollfd *pollfd, + const char **pcce); + +int +lws_socks5c_greet(struct lws *wsi, const char **pcce); + +enum { + LW5CHS_RET_RET0, + LW5CHS_RET_BAIL3, + LW5CHS_RET_STARTHS, + LW5CHS_RET_NOTHING +}; + #ifdef __cplusplus }; #endif diff --git a/lib/core-net/socks5-client.c b/lib/core-net/socks5-client.c new file mode 100644 index 000000000..e57584e28 --- /dev/null +++ b/lib/core-net/socks5-client.c @@ -0,0 +1,378 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2020 Andy Green + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Socks5 Client -related helpers + */ + +#include "private-lib-core.h" + +int +lws_set_socks(struct lws_vhost *vhost, const char *socks) +{ + char *p_at, *p_colon; + char user[96]; + char password[96]; + + if (!socks) + return -1; + + vhost->socks_user[0] = '\0'; + vhost->socks_password[0] = '\0'; + + p_at = strrchr(socks, '@'); + if (p_at) { /* auth is around */ + if ((unsigned int)(p_at - socks) > (sizeof(user) + + sizeof(password) - 2)) { + lwsl_err("Socks auth too long\n"); + goto bail; + } + + p_colon = strchr(socks, ':'); + if (p_colon) { + if ((unsigned int)(p_colon - socks) > (sizeof(user) + - 1) ) { + lwsl_err("Socks user too long\n"); + goto bail; + } + if ((unsigned int)(p_at - p_colon) > (sizeof(password) + - 1) ) { + lwsl_err("Socks password too long\n"); + goto bail; + } + + lws_strncpy(vhost->socks_user, socks, + p_colon - socks + 1); + lws_strncpy(vhost->socks_password, p_colon + 1, + p_at - (p_colon + 1) + 1); + } + + lwsl_info(" Socks auth, user: %s, password: %s\n", + vhost->socks_user, vhost->socks_password ); + + socks = p_at + 1; + } + + lws_strncpy(vhost->socks_proxy_address, socks, + sizeof(vhost->socks_proxy_address)); + + p_colon = strchr(vhost->socks_proxy_address, ':'); + if (!p_colon && !vhost->socks_proxy_port) { + lwsl_err("socks_proxy needs to be address:port\n"); + return -1; + } else { + if (p_colon) { + *p_colon = '\0'; + vhost->socks_proxy_port = atoi(p_colon + 1); + } + } + + lwsl_notice("%s: Connections via Socks5 %s:%u\n", __func__, + vhost->socks_proxy_address, vhost->socks_proxy_port); + + return 0; + +bail: + return -1; +} + +int +lws_socks5c_generate_msg(struct lws *wsi, enum socks_msg_type type, + ssize_t *msg_len) +{ + struct lws_context *context = wsi->context; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + uint8_t *p = pt->serv_buf, *end = &p[context->pt_serv_buf_size]; + ssize_t n, passwd_len; + short net_num; + char *cp; + + switch (type) { + case SOCKS_MSG_GREETING: + if (lws_ptr_diff(end, p) < 4) + return 1; + /* socks version, version 5 only */ + *p++ = SOCKS_VERSION_5; + /* number of methods */ + *p++ = 2; + /* username password method */ + *p++ = SOCKS_AUTH_USERNAME_PASSWORD; + /* no authentication method */ + *p++ = SOCKS_AUTH_NO_AUTH; + break; + + case SOCKS_MSG_USERNAME_PASSWORD: + n = strlen(wsi->vhost->socks_user); + passwd_len = strlen(wsi->vhost->socks_password); + + if (n > 254 || passwd_len > 254) + return 1; + + if (lws_ptr_diff(end, p) < 3 + n + passwd_len) + return 1; + + /* the subnegotiation version */ + *p++ = SOCKS_SUBNEGOTIATION_VERSION_1; + + /* length of the user name */ + *p++ = n; + /* user name */ + memcpy(p, wsi->vhost->socks_user, n); + p += n; + + /* length of the password */ + *p++ = passwd_len; + + /* password */ + memcpy(p, wsi->vhost->socks_password, passwd_len); + p += passwd_len; + break; + + case SOCKS_MSG_CONNECT: + n = strlen(wsi->stash->cis[CIS_ADDRESS]); + + if (n > 254 || lws_ptr_diff(end, p) < 5 + n + 2) + return 1; + + cp = (char *)&net_num; + + /* socks version */ + *p++ = SOCKS_VERSION_5; + /* socks command */ + *p++ = SOCKS_COMMAND_CONNECT; + /* reserved */ + *p++ = 0; + /* address type */ + *p++ = SOCKS_ATYP_DOMAINNAME; + /* length of ---> */ + *p++ = n; + + /* the address we tell SOCKS proxy to connect to */ + memcpy(p, wsi->stash->cis[CIS_ADDRESS], n); + p += n; + + net_num = htons(wsi->c_port); + + /* the port we tell SOCKS proxy to connect to */ + *p++ = cp[0]; + *p++ = cp[1]; + + break; + + default: + return 1; + } + + *msg_len = lws_ptr_diff(p, pt->serv_buf); + + return 0; +} + +int +lws_socks5c_ads_server(struct lws_vhost *vh, + const struct lws_context_creation_info *info) +{ + /* socks proxy */ + if (info->socks_proxy_address) { + /* override for backwards compatibility */ + if (info->socks_proxy_port) + vh->socks_proxy_port = info->socks_proxy_port; + lws_set_socks(vh, info->socks_proxy_address); + + return 0; + } +#ifdef LWS_HAVE_GETENV + { + char *p = getenv("socks_proxy"); + + if (p && strlen(p) > 0 && strlen(p) < 95) + lws_set_socks(vh, p); + } +#endif + + return 0; +} + +/* + * Returns 0 = nothing for caller to do, 1 = return wsi, -1 = goto failed + */ + +int +lws_socks5c_greet(struct lws *wsi, const char **pcce) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + ssize_t plen; + int n; + + /* socks proxy */ + if (!wsi->vhost->socks_proxy_port) + return 0; + + if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) { + *pcce = "socks msg too large"; + return -1; + } + // lwsl_hexdump_notice(pt->serv_buf, plen); + n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen, + MSG_NOSIGNAL); + if (n < 0) { + lwsl_debug("ERROR writing socks greeting\n"); + *pcce = "socks write failed"; + return -1; + } + + lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY, + wsi->context->timeout_secs); + + lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY); + + return 1; +} + +int +lws_socks5c_handle_state(struct lws *wsi, struct lws_pollfd *pollfd, + const char **pcce) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + int conn_mode = 0, pending_timeout = 0; + ssize_t len; + int n; + + /* handle proxy hung up on us */ + + if (pollfd->revents & LWS_POLLHUP) { + lwsl_warn("SOCKS connection %p (fd=%d) dead\n", + (void *)wsi, pollfd->fd); + *pcce = "socks conn dead"; + return LW5CHS_RET_BAIL3; + } + + n = recv(wsi->desc.sockfd, pt->serv_buf, + wsi->context->pt_serv_buf_size, 0); + if (n < 0) { + if (LWS_ERRNO == LWS_EAGAIN) { + lwsl_debug("SOCKS read EAGAIN, retrying\n"); + return LW5CHS_RET_RET0; + } + lwsl_err("ERROR reading from SOCKS socket\n"); + *pcce = "socks recv fail"; + return LW5CHS_RET_BAIL3; + } + + // lwsl_hexdump_warn(sb, n); + + switch (lwsi_state(wsi)) { + + case LRS_WAITING_SOCKS_GREETING_REPLY: + if (pt->serv_buf[0] != SOCKS_VERSION_5) + goto socks_reply_fail; + + if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) { + lwsl_client("SOCKS GR: No Auth Method\n"); + if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT, + &len)) { + lwsl_err("%s: failed to generate connect msg\n", + __func__); + goto socks_send_msg_fail; + } + conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; + pending_timeout = + PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; + goto socks_send; + } + + if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) { + lwsl_client("SOCKS GR: User/Pw Method\n"); + if (lws_socks5c_generate_msg(wsi, + SOCKS_MSG_USERNAME_PASSWORD, + &len)) + goto socks_send_msg_fail; + conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY; + pending_timeout = + PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY; + goto socks_send; + } + goto socks_reply_fail; + + case LRS_WAITING_SOCKS_AUTH_REPLY: + if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 || + pt->serv_buf[1] != + SOCKS_SUBNEGOTIATION_STATUS_SUCCESS) + goto socks_reply_fail; + + lwsl_client("SOCKS password OK, sending connect\n"); + if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) { +socks_send_msg_fail: + *pcce = "socks gen msg fail"; + return LW5CHS_RET_BAIL3; + } + conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; + pending_timeout = + PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; +socks_send: + // lwsl_hexdump_notice(pt->serv_buf, len); + n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len, + MSG_NOSIGNAL); + if (n < 0) { + lwsl_debug("ERROR writing to socks proxy\n"); + *pcce = "socks write fail"; + return LW5CHS_RET_BAIL3; + } + + lws_set_timeout(wsi, pending_timeout, + wsi->context->timeout_secs); + lwsi_set_state(wsi, conn_mode); + break; + +socks_reply_fail: + lwsl_err("%s: socks reply: v%d, err %d\n", __func__, + pt->serv_buf[0], pt->serv_buf[1]); + *pcce = "socks reply fail"; + return LW5CHS_RET_BAIL3; + + case LRS_WAITING_SOCKS_CONNECT_REPLY: + if (pt->serv_buf[0] != SOCKS_VERSION_5 || + pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS) + goto socks_reply_fail; + + lwsl_client("%s: socks connect OK\n", __func__); + +#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) + if (lwsi_role_http(wsi) && + lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, + wsi->vhost->socks_proxy_address)) { + *pcce = "socks connect fail"; + return LW5CHS_RET_BAIL3; + } +#endif + + wsi->c_port = wsi->vhost->socks_proxy_port; + + /* clear his proxy connection timeout */ + lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + return LW5CHS_RET_STARTHS; + default: + break; + } + + return LW5CHS_RET_NOTHING; +} diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index 2c801f4dc..705f1c006 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -738,19 +738,7 @@ lws_create_vhost(struct lws_context *context, } #endif #if defined(LWS_WITH_SOCKS5) - /* socks proxy */ - if (info->socks_proxy_address) { - /* override for backwards compatibility */ - if (info->socks_proxy_port) - vh->socks_proxy_port = info->socks_proxy_port; - lws_set_socks(vh, info->socks_proxy_address); - } else { -#ifdef LWS_HAVE_GETENV - p = getenv("socks_proxy"); - if (p && strlen(p) > 0 && strlen(p) < 95) - lws_set_socks(vh, p); -#endif - } + lws_socks5c_ads_server(vh, info); #endif vh->ka_time = info->ka_time; diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index b98ca7db5..68101c8e2 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -245,78 +245,6 @@ lws_canonical_hostname(struct lws_context *context) } #endif -#if defined(LWS_WITH_SOCKS5) -int -lws_set_socks(struct lws_vhost *vhost, const char *socks) -{ - char *p_at, *p_colon; - char user[96]; - char password[96]; - - if (!socks) - return -1; - - vhost->socks_user[0] = '\0'; - vhost->socks_password[0] = '\0'; - - p_at = strrchr(socks, '@'); - if (p_at) { /* auth is around */ - if ((unsigned int)(p_at - socks) > (sizeof(user) - + sizeof(password) - 2)) { - lwsl_err("Socks auth too long\n"); - goto bail; - } - - p_colon = strchr(socks, ':'); - if (p_colon) { - if ((unsigned int)(p_colon - socks) > (sizeof(user) - - 1) ) { - lwsl_err("Socks user too long\n"); - goto bail; - } - if ((unsigned int)(p_at - p_colon) > (sizeof(password) - - 1) ) { - lwsl_err("Socks password too long\n"); - goto bail; - } - - lws_strncpy(vhost->socks_user, socks, p_colon - socks + 1); - lws_strncpy(vhost->socks_password, p_colon + 1, - p_at - (p_colon + 1) + 1); - } - - lwsl_info(" Socks auth, user: %s, password: %s\n", - vhost->socks_user, vhost->socks_password ); - - socks = p_at + 1; - } - - lws_strncpy(vhost->socks_proxy_address, socks, - sizeof(vhost->socks_proxy_address)); - - p_colon = strchr(vhost->socks_proxy_address, ':'); - if (!p_colon && !vhost->socks_proxy_port) { - lwsl_err("socks_proxy needs to be address:port\n"); - return -1; - } else { - if (p_colon) { - *p_colon = '\0'; - vhost->socks_proxy_port = atoi(p_colon + 1); - } - } - - lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address, - vhost->socks_proxy_port); - - return 0; - -bail: - return -1; -} -#endif - - - int lws_get_count_threads(struct lws_context *context) { diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c index 3e763820f..87de27e36 100644 --- a/lib/roles/http/client/client-handshake.c +++ b/lib/roles/http/client/client-handshake.c @@ -138,26 +138,18 @@ lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback, } #endif #endif + #if defined(LWS_WITH_SOCKS5) - /* socks proxy */ - else if (wsi->vhost->socks_proxy_port) { - n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen, - MSG_NOSIGNAL); - if (n < 0) { - lwsl_debug("ERROR writing socks greeting\n"); - cce = "socks write failed"; - goto failed; - } - - lws_set_timeout(wsi, - PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY, - wsi->context->timeout_secs); - - lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY); - + switch (lws_socks5c_greet(wsi, &cce)) { + case -1: + goto failed; + case 1: return wsi; + default: + break; } #endif + #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) send_hs: @@ -288,8 +280,9 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads, #endif const struct sockaddr *psa = NULL; const char *cce = "", *iface; - ssize_t plen = 0; + uint16_t port = wsi->c_port; lws_sockaddr46 sa46; + ssize_t plen = 0; char ni[48]; int m; @@ -403,7 +396,7 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads, if (wsi->vhost->http.http_proxy_port) { ads = wsi->vhost->http.http_proxy_address; - wsi->c_port = wsi->vhost->http.http_proxy_port; + port = wsi->vhost->http.http_proxy_port; #else if (0) { #endif @@ -413,14 +406,14 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads, /* Priority 2: Connect to SOCK5 Proxy */ } else if (wsi->vhost->socks_proxy_port) { - if (socks_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) { + if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) { cce = "socks msg too large"; goto oom4; } lwsl_client("Sending SOCKS Greeting\n"); ads = wsi->vhost->socks_proxy_address; - wsi->c_port = wsi->vhost->socks_proxy_port; + port = wsi->vhost->socks_proxy_port; #endif } @@ -461,7 +454,7 @@ next_result: &((struct sockaddr_in *) wsi->dns_results_next->ai_addr)->sin_addr, sizeof(struct in_addr)); - sa46.sa6.sin6_port = htons(wsi->c_port); + sa46.sa6.sin6_port = htons(port); ni[0] = '\0'; lws_write_numeric_address(sa46.sa6.sin6_addr.s6_addr, 16, ni, sizeof(ni)); @@ -474,7 +467,7 @@ next_result: ((struct sockaddr_in *)wsi->dns_results_next->ai_addr)-> sin_addr.s_addr; memset(&sa46.sa4.sin_zero, 0, sizeof(sa46.sa4.sin_zero)); - sa46.sa4.sin_port = htons(wsi->c_port); + sa46.sa4.sin_port = htons(port); n = sizeof(struct sockaddr_in); lws_write_numeric_address((uint8_t *)&sa46.sa4.sin_addr.s_addr, 4, ni, sizeof(ni)); @@ -492,7 +485,7 @@ next_result: wsi->dns_results_next->ai_addr)->sin6_scope_id; sa46.sa6.sin6_flowinfo = ((struct sockaddr_in6 *) wsi->dns_results_next->ai_addr)->sin6_flowinfo; - sa46.sa6.sin6_port = htons(wsi->c_port); + sa46.sa6.sin6_port = htons(port); lws_write_numeric_address((uint8_t *)&sa46.sa6.sin6_addr, 16, ni, sizeof(ni)); lwsl_info("%s: %s ipv6 %s\n", __func__, ads, ni); @@ -613,7 +606,7 @@ ads_known: char nads[48]; lws_sa46_write_numeric_address(&sa46, nads, sizeof(nads)); lwsl_info("%s: Connect failed: %s port %d\n", - __func__, nads, wsi->c_port); + __func__, nads, port); #endif goto try_next_result_fds; } @@ -633,7 +626,7 @@ ads_known: conn_good: - lwsl_debug("%s: Connection started %p\n", __func__, wsi->dns_results); + lwsl_info("%s: Connection started %p\n", __func__, wsi->dns_results); /* the tcp connection has happend */ @@ -1371,96 +1364,3 @@ bail1: return NULL; } - -#if defined(LWS_WITH_SOCKS5) -int -socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len) -{ - struct lws_context *context = wsi->context; - struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; - uint8_t *p = pt->serv_buf, *end = &p[context->pt_serv_buf_size]; - ssize_t n, passwd_len; - short net_num; - char *cp; - - switch (type) { - case SOCKS_MSG_GREETING: - if (lws_ptr_diff(end, p) < 4) - return 1; - /* socks version, version 5 only */ - *p++ = SOCKS_VERSION_5; - /* number of methods */ - *p++ = 2; - /* username password method */ - *p++ = SOCKS_AUTH_USERNAME_PASSWORD; - /* no authentication method */ - *p++ = SOCKS_AUTH_NO_AUTH; - break; - - case SOCKS_MSG_USERNAME_PASSWORD: - n = strlen(wsi->vhost->socks_user); - passwd_len = strlen(wsi->vhost->socks_password); - - if (n > 254 || passwd_len > 254) - return 1; - - if (lws_ptr_diff(end, p) < 3 + n + passwd_len) - return 1; - - /* the subnegotiation version */ - *p++ = SOCKS_SUBNEGOTIATION_VERSION_1; - - /* length of the user name */ - *p++ = n; - /* user name */ - memcpy(p, wsi->vhost->socks_user, n); - p += n; - - /* length of the password */ - *p++ = passwd_len; - - /* password */ - memcpy(p, wsi->vhost->socks_password, passwd_len); - p += passwd_len; - break; - - case SOCKS_MSG_CONNECT: - n = strlen(wsi->stash->cis[CIS_ADDRESS]); - - if (n > 254 || lws_ptr_diff(end, p) < 5 + n + 2) - return 1; - - cp = (char *)&net_num; - - /* socks version */ - *p++ = SOCKS_VERSION_5; - /* socks command */ - *p++ = SOCKS_COMMAND_CONNECT; - /* reserved */ - *p++ = 0; - /* address type */ - *p++ = SOCKS_ATYP_DOMAINNAME; - /* length of ---> */ - *p++ = n; - - /* the address we tell SOCKS proxy to connect to */ - memcpy(p, wsi->stash->cis[CIS_ADDRESS], n); - p += n; - - net_num = htons(wsi->c_port); - - /* the port we tell SOCKS proxy to connect to */ - *p++ = cp[0]; - *p++ = cp[1]; - - break; - - default: - return 1; - } - - *msg_len = lws_ptr_diff(p, pt->serv_buf); - - return 0; -} -#endif diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index 61019e19f..fc130e5f0 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -42,10 +42,6 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) const char *cce = NULL; char *sb = p; int n = 0; -#if defined(LWS_WITH_SOCKS5) - int conn_mode = 0, pending_timeout = 0; - ssize_t len; -#endif switch (lwsi_state(wsi)) { @@ -80,110 +76,12 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) case LRS_WAITING_SOCKS_AUTH_REPLY: case LRS_WAITING_SOCKS_CONNECT_REPLY: - /* handle proxy hung up on us */ - - if (pollfd->revents & LWS_POLLHUP) { - lwsl_warn("SOCKS connection %p (fd=%d) dead\n", - (void *)wsi, pollfd->fd); - cce = "socks conn dead"; + switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) { + case LW5CHS_RET_RET0: + return 0; + case LW5CHS_RET_BAIL3: goto bail3; - } - - n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0); - if (n < 0) { - if (LWS_ERRNO == LWS_EAGAIN) { - lwsl_debug("SOCKS read EAGAIN, retrying\n"); - return 0; - } - lwsl_err("ERROR reading from SOCKS socket\n"); - cce = "socks recv fail"; - goto bail3; - } - - switch (lwsi_state(wsi)) { - - case LRS_WAITING_SOCKS_GREETING_REPLY: - if (pt->serv_buf[0] != SOCKS_VERSION_5) - goto socks_reply_fail; - - if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) { - lwsl_client("SOCKS GR: No Auth Method\n"); - if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) - goto socks_send_msg_fail; - conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; - pending_timeout = - PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; - goto socks_send; - } - - if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) { - lwsl_client("SOCKS GR: User/Pw Method\n"); - if (socks_generate_msg(wsi, - SOCKS_MSG_USERNAME_PASSWORD, - &len)) - goto socks_send_msg_fail; - conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY; - pending_timeout = - PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY; - goto socks_send; - } - goto socks_reply_fail; - - case LRS_WAITING_SOCKS_AUTH_REPLY: - if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 || - pt->serv_buf[1] != - SOCKS_SUBNEGOTIATION_STATUS_SUCCESS) - goto socks_reply_fail; - - lwsl_client("SOCKS password OK, sending connect\n"); - if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) { -socks_send_msg_fail: - cce = "socks gen msg fail"; - goto bail3; - } - conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; - pending_timeout = - PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; -socks_send: - n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len, - MSG_NOSIGNAL); - if (n < 0) { - lwsl_debug("ERROR writing to socks proxy\n"); - cce = "socks write fail"; - goto bail3; - } - - lws_set_timeout(wsi, pending_timeout, - context->timeout_secs); - lwsi_set_state(wsi, conn_mode); - break; - -socks_reply_fail: - lwsl_notice("socks reply: v%d, err %d\n", - pt->serv_buf[0], pt->serv_buf[1]); - cce = "socks reply fail"; - goto bail3; - - case LRS_WAITING_SOCKS_CONNECT_REPLY: - if (pt->serv_buf[0] != SOCKS_VERSION_5 || - pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS) - goto socks_reply_fail; - - lwsl_client("socks connect OK\n"); - - /* free stash since we are done with it */ - lws_free_set_NULL(wsi->stash); - if (lws_hdr_simple_create(wsi, - _WSI_TOKEN_CLIENT_PEER_ADDRESS, - wsi->vhost->socks_proxy_address)) { - cce = "socks connect fail"; - goto bail3; - } - - wsi->c_port = wsi->vhost->socks_proxy_port; - - /* clear his proxy connection timeout */ - lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + case LW5CHS_RET_STARTHS: goto start_ws_handshake; default: break;