mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
socks5: cleanup and add test options
Refactor SOCKS5 client support to be gathered into lib/core-net/socks5-client.c and make that build contingent on LWS_WITH_SOCKS5.
This commit is contained in:
parent
0dd23d7073
commit
6bb116b8d8
8 changed files with 429 additions and 312 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
378
lib/core-net/socks5-client.c
Normal file
378
lib/core-net/socks5-client.c
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue