1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci *
24d4afb5ceSopenharmony_ci * Socks5 Client -related helpers
25d4afb5ceSopenharmony_ci */
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#include "private-lib-core.h"
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_ciint
30d4afb5ceSopenharmony_cilws_set_socks(struct lws_vhost *vhost, const char *socks)
31d4afb5ceSopenharmony_ci{
32d4afb5ceSopenharmony_ci	char *p_at, *p_colon;
33d4afb5ceSopenharmony_ci	char user[96];
34d4afb5ceSopenharmony_ci	char password[96];
35d4afb5ceSopenharmony_ci
36d4afb5ceSopenharmony_ci	if (!socks)
37d4afb5ceSopenharmony_ci		return -1;
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci	vhost->socks_user[0] = '\0';
40d4afb5ceSopenharmony_ci	vhost->socks_password[0] = '\0';
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_ci	p_at = strrchr(socks, '@');
43d4afb5ceSopenharmony_ci	if (p_at) { /* auth is around */
44d4afb5ceSopenharmony_ci		if (lws_ptr_diff_size_t(p_at, socks) > (sizeof(user) +
45d4afb5ceSopenharmony_ci							sizeof(password) - 2)) {
46d4afb5ceSopenharmony_ci			lwsl_vhost_err(vhost, "auth too long");
47d4afb5ceSopenharmony_ci			goto bail;
48d4afb5ceSopenharmony_ci		}
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci		p_colon = strchr(socks, ':');
51d4afb5ceSopenharmony_ci		if (p_colon) {
52d4afb5ceSopenharmony_ci			if (lws_ptr_diff_size_t(p_colon, socks) >
53d4afb5ceSopenharmony_ci							     sizeof(user) - 1) {
54d4afb5ceSopenharmony_ci				lwsl_vhost_err(vhost, "user too long");
55d4afb5ceSopenharmony_ci				goto bail;
56d4afb5ceSopenharmony_ci			}
57d4afb5ceSopenharmony_ci			if (lws_ptr_diff_size_t(p_at, p_colon) >
58d4afb5ceSopenharmony_ci						         sizeof(password) - 1) {
59d4afb5ceSopenharmony_ci				lwsl_vhost_err(vhost, "pw too long");
60d4afb5ceSopenharmony_ci				goto bail;
61d4afb5ceSopenharmony_ci			}
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci			lws_strncpy(vhost->socks_user, socks,
64d4afb5ceSopenharmony_ci				    lws_ptr_diff_size_t(p_colon, socks) + 1);
65d4afb5ceSopenharmony_ci			lws_strncpy(vhost->socks_password, p_colon + 1,
66d4afb5ceSopenharmony_ci				lws_ptr_diff_size_t(p_at, (p_colon + 1)) + 1);
67d4afb5ceSopenharmony_ci		}
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci		lwsl_vhost_info(vhost, " Socks auth, user: %s, password: %s",
70d4afb5ceSopenharmony_ci				       vhost->socks_user,
71d4afb5ceSopenharmony_ci				       vhost->socks_password);
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci		socks = p_at + 1;
74d4afb5ceSopenharmony_ci	}
75d4afb5ceSopenharmony_ci
76d4afb5ceSopenharmony_ci	lws_strncpy(vhost->socks_proxy_address, socks,
77d4afb5ceSopenharmony_ci		    sizeof(vhost->socks_proxy_address));
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci	p_colon = strchr(vhost->socks_proxy_address, ':');
80d4afb5ceSopenharmony_ci	if (!p_colon && !vhost->socks_proxy_port) {
81d4afb5ceSopenharmony_ci		lwsl_vhost_err(vhost, "socks_proxy needs to be address:port");
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci		return -1;
84d4afb5ceSopenharmony_ci	}
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci	if (p_colon) {
87d4afb5ceSopenharmony_ci		*p_colon = '\0';
88d4afb5ceSopenharmony_ci		vhost->socks_proxy_port = (unsigned int)atoi(p_colon + 1);
89d4afb5ceSopenharmony_ci	}
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	lwsl_vhost_debug(vhost, "Connections via Socks5 %s:%u",
92d4afb5ceSopenharmony_ci				vhost->socks_proxy_address,
93d4afb5ceSopenharmony_ci				vhost->socks_proxy_port);
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ci	return 0;
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_cibail:
98d4afb5ceSopenharmony_ci	return -1;
99d4afb5ceSopenharmony_ci}
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ciint
102d4afb5ceSopenharmony_cilws_socks5c_generate_msg(struct lws *wsi, enum socks_msg_type type,
103d4afb5ceSopenharmony_ci			 ssize_t *msg_len)
104d4afb5ceSopenharmony_ci{
105d4afb5ceSopenharmony_ci	struct lws_context *context = wsi->a.context;
106d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
107d4afb5ceSopenharmony_ci	uint8_t *p = pt->serv_buf, *end = &p[context->pt_serv_buf_size];
108d4afb5ceSopenharmony_ci	ssize_t n, passwd_len;
109d4afb5ceSopenharmony_ci	short net_num;
110d4afb5ceSopenharmony_ci	char *cp;
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci	switch (type) {
113d4afb5ceSopenharmony_ci	case SOCKS_MSG_GREETING:
114d4afb5ceSopenharmony_ci		if (lws_ptr_diff(end, p) < 4)
115d4afb5ceSopenharmony_ci			return 1;
116d4afb5ceSopenharmony_ci		/* socks version, version 5 only */
117d4afb5ceSopenharmony_ci		*p++ = SOCKS_VERSION_5;
118d4afb5ceSopenharmony_ci		/* number of methods */
119d4afb5ceSopenharmony_ci		*p++ = 2;
120d4afb5ceSopenharmony_ci		/* username password method */
121d4afb5ceSopenharmony_ci		*p++ = SOCKS_AUTH_USERNAME_PASSWORD;
122d4afb5ceSopenharmony_ci		/* no authentication method */
123d4afb5ceSopenharmony_ci		*p++ = SOCKS_AUTH_NO_AUTH;
124d4afb5ceSopenharmony_ci		break;
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	case SOCKS_MSG_USERNAME_PASSWORD:
127d4afb5ceSopenharmony_ci		n = (ssize_t)strlen(wsi->a.vhost->socks_user);
128d4afb5ceSopenharmony_ci		passwd_len = (ssize_t)strlen(wsi->a.vhost->socks_password);
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci		if (n > 254 || passwd_len > 254)
131d4afb5ceSopenharmony_ci			return 1;
132d4afb5ceSopenharmony_ci
133d4afb5ceSopenharmony_ci		if (lws_ptr_diff(end, p) < 3 + n + passwd_len)
134d4afb5ceSopenharmony_ci			return 1;
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_ci		/* the subnegotiation version */
137d4afb5ceSopenharmony_ci		*p++ = SOCKS_SUBNEGOTIATION_VERSION_1;
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci		/* length of the user name */
140d4afb5ceSopenharmony_ci		*p++ = (uint8_t)n;
141d4afb5ceSopenharmony_ci		/* user name */
142d4afb5ceSopenharmony_ci		memcpy(p, wsi->a.vhost->socks_user, (size_t)n);
143d4afb5ceSopenharmony_ci		p += (uint8_t)n;
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ci		/* length of the password */
146d4afb5ceSopenharmony_ci		*p++ = (uint8_t)passwd_len;
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci		/* password */
149d4afb5ceSopenharmony_ci		memcpy(p, wsi->a.vhost->socks_password, (size_t)passwd_len);
150d4afb5ceSopenharmony_ci		p += passwd_len;
151d4afb5ceSopenharmony_ci		break;
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	case SOCKS_MSG_CONNECT:
154d4afb5ceSopenharmony_ci		n = (ssize_t)strlen(wsi->stash->cis[CIS_ADDRESS]);
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci		if (n > 254 || lws_ptr_diff(end, p) < 5 + n + 2)
157d4afb5ceSopenharmony_ci			return 1;
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci		cp = (char *)&net_num;
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci		/* socks version */
162d4afb5ceSopenharmony_ci		*p++ = SOCKS_VERSION_5;
163d4afb5ceSopenharmony_ci		/* socks command */
164d4afb5ceSopenharmony_ci		*p++ = SOCKS_COMMAND_CONNECT;
165d4afb5ceSopenharmony_ci		/* reserved */
166d4afb5ceSopenharmony_ci		*p++ = 0;
167d4afb5ceSopenharmony_ci		/* address type */
168d4afb5ceSopenharmony_ci		*p++ = SOCKS_ATYP_DOMAINNAME;
169d4afb5ceSopenharmony_ci		/* length of ---> */
170d4afb5ceSopenharmony_ci		*p++ = (uint8_t)n;
171d4afb5ceSopenharmony_ci
172d4afb5ceSopenharmony_ci		/* the address we tell SOCKS proxy to connect to */
173d4afb5ceSopenharmony_ci		memcpy(p, wsi->stash->cis[CIS_ADDRESS], (size_t)n);
174d4afb5ceSopenharmony_ci		p += n;
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci		net_num = (short)htons(wsi->c_port);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci		/* the port we tell SOCKS proxy to connect to */
179d4afb5ceSopenharmony_ci		*p++ = (uint8_t)cp[0];
180d4afb5ceSopenharmony_ci		*p++ = (uint8_t)cp[1];
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci		break;
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	default:
185d4afb5ceSopenharmony_ci		return 1;
186d4afb5ceSopenharmony_ci	}
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci	*msg_len = lws_ptr_diff(p, pt->serv_buf);
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	return 0;
191d4afb5ceSopenharmony_ci}
192d4afb5ceSopenharmony_ci
193d4afb5ceSopenharmony_ciint
194d4afb5ceSopenharmony_cilws_socks5c_ads_server(struct lws_vhost *vh,
195d4afb5ceSopenharmony_ci		      const struct lws_context_creation_info *info)
196d4afb5ceSopenharmony_ci{
197d4afb5ceSopenharmony_ci	/* socks proxy */
198d4afb5ceSopenharmony_ci	if (info->socks_proxy_address) {
199d4afb5ceSopenharmony_ci		/* override for backwards compatibility */
200d4afb5ceSopenharmony_ci		if (info->socks_proxy_port)
201d4afb5ceSopenharmony_ci			vh->socks_proxy_port = info->socks_proxy_port;
202d4afb5ceSopenharmony_ci		lws_set_socks(vh, info->socks_proxy_address);
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci		return 0;
205d4afb5ceSopenharmony_ci	}
206d4afb5ceSopenharmony_ci#ifdef LWS_HAVE_GETENV
207d4afb5ceSopenharmony_ci	{
208d4afb5ceSopenharmony_ci		char *p = getenv("socks_proxy");
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci		if (p && strlen(p) > 0 && strlen(p) < 95)
211d4afb5ceSopenharmony_ci			lws_set_socks(vh, p);
212d4afb5ceSopenharmony_ci	}
213d4afb5ceSopenharmony_ci#endif
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci	return 0;
216d4afb5ceSopenharmony_ci}
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci/*
219d4afb5ceSopenharmony_ci * Returns 0 = nothing for caller to do, 1 = return wsi, -1 = goto failed
220d4afb5ceSopenharmony_ci */
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ciint
223d4afb5ceSopenharmony_cilws_socks5c_greet(struct lws *wsi, const char **pcce)
224d4afb5ceSopenharmony_ci{
225d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
226d4afb5ceSopenharmony_ci	ssize_t plen;
227d4afb5ceSopenharmony_ci	int n;
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	/* socks proxy */
230d4afb5ceSopenharmony_ci	if (!wsi->a.vhost->socks_proxy_port)
231d4afb5ceSopenharmony_ci		return 0;
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci	if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) {
234d4afb5ceSopenharmony_ci		*pcce = "socks msg too large";
235d4afb5ceSopenharmony_ci		return -1;
236d4afb5ceSopenharmony_ci	}
237d4afb5ceSopenharmony_ci	// lwsl_hexdump_notice(pt->serv_buf, plen);
238d4afb5ceSopenharmony_ci	n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf, (size_t)plen,
239d4afb5ceSopenharmony_ci		      MSG_NOSIGNAL);
240d4afb5ceSopenharmony_ci	if (n < 0) {
241d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "ERROR writing socks greeting");
242d4afb5ceSopenharmony_ci		*pcce = "socks write failed";
243d4afb5ceSopenharmony_ci		return -1;
244d4afb5ceSopenharmony_ci	}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
247d4afb5ceSopenharmony_ci			(int)wsi->a.context->timeout_secs);
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_ci	lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);
250d4afb5ceSopenharmony_ci
251d4afb5ceSopenharmony_ci	return 1;
252d4afb5ceSopenharmony_ci}
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ciint
255d4afb5ceSopenharmony_cilws_socks5c_handle_state(struct lws *wsi, struct lws_pollfd *pollfd,
256d4afb5ceSopenharmony_ci			 const char **pcce)
257d4afb5ceSopenharmony_ci{
258d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
259d4afb5ceSopenharmony_ci	int conn_mode = 0, pending_timeout = 0;
260d4afb5ceSopenharmony_ci	ssize_t len;
261d4afb5ceSopenharmony_ci	int n;
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci	/* handle proxy hung up on us */
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci	if (pollfd->revents & LWS_POLLHUP) {
266d4afb5ceSopenharmony_ci		lwsl_wsi_warn(wsi, "SOCKS fd=%d dead", pollfd->fd);
267d4afb5ceSopenharmony_ci		*pcce = "socks conn dead";
268d4afb5ceSopenharmony_ci		return LW5CHS_RET_BAIL3;
269d4afb5ceSopenharmony_ci	}
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	n = (int)recv(wsi->desc.sockfd, (void *)pt->serv_buf,
272d4afb5ceSopenharmony_ci		 wsi->a.context->pt_serv_buf_size, 0);
273d4afb5ceSopenharmony_ci	if (n < 0) {
274d4afb5ceSopenharmony_ci		if (LWS_ERRNO == LWS_EAGAIN) {
275d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "SOCKS read EAGAIN, retrying");
276d4afb5ceSopenharmony_ci			return LW5CHS_RET_RET0;
277d4afb5ceSopenharmony_ci		}
278d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "ERROR reading from SOCKS socket");
279d4afb5ceSopenharmony_ci		*pcce = "socks recv fail";
280d4afb5ceSopenharmony_ci		return LW5CHS_RET_BAIL3;
281d4afb5ceSopenharmony_ci	}
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_ci	// lwsl_hexdump_warn(pt->serv_buf, n);
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	switch (lwsi_state(wsi)) {
286d4afb5ceSopenharmony_ci
287d4afb5ceSopenharmony_ci	case LRS_WAITING_SOCKS_GREETING_REPLY:
288d4afb5ceSopenharmony_ci		if (pt->serv_buf[0] != SOCKS_VERSION_5)
289d4afb5ceSopenharmony_ci			goto socks_reply_fail;
290d4afb5ceSopenharmony_ci
291d4afb5ceSopenharmony_ci		if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) {
292d4afb5ceSopenharmony_ci			lwsl_wsi_client(wsi, "SOCKS GR: No Auth Method");
293d4afb5ceSopenharmony_ci			if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT,
294d4afb5ceSopenharmony_ci						     &len)) {
295d4afb5ceSopenharmony_ci				lwsl_wsi_err(wsi, "generate connect msg fail");
296d4afb5ceSopenharmony_ci				goto socks_send_msg_fail;
297d4afb5ceSopenharmony_ci			}
298d4afb5ceSopenharmony_ci			conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
299d4afb5ceSopenharmony_ci			pending_timeout =
300d4afb5ceSopenharmony_ci			   PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
301d4afb5ceSopenharmony_ci			goto socks_send;
302d4afb5ceSopenharmony_ci		}
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_ci		if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) {
305d4afb5ceSopenharmony_ci			lwsl_wsi_client(wsi, "SOCKS GR: User/Pw Method");
306d4afb5ceSopenharmony_ci			if (lws_socks5c_generate_msg(wsi,
307d4afb5ceSopenharmony_ci					   SOCKS_MSG_USERNAME_PASSWORD,
308d4afb5ceSopenharmony_ci					   &len))
309d4afb5ceSopenharmony_ci				goto socks_send_msg_fail;
310d4afb5ceSopenharmony_ci			conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY;
311d4afb5ceSopenharmony_ci			pending_timeout =
312d4afb5ceSopenharmony_ci			      PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
313d4afb5ceSopenharmony_ci			goto socks_send;
314d4afb5ceSopenharmony_ci		}
315d4afb5ceSopenharmony_ci		goto socks_reply_fail;
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci	case LRS_WAITING_SOCKS_AUTH_REPLY:
318d4afb5ceSopenharmony_ci		if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 ||
319d4afb5ceSopenharmony_ci		    pt->serv_buf[1] !=
320d4afb5ceSopenharmony_ci				    SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
321d4afb5ceSopenharmony_ci			goto socks_reply_fail;
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci		lwsl_wsi_client(wsi, "SOCKS password OK, sending connect");
324d4afb5ceSopenharmony_ci		if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) {
325d4afb5ceSopenharmony_cisocks_send_msg_fail:
326d4afb5ceSopenharmony_ci			*pcce = "socks gen msg fail";
327d4afb5ceSopenharmony_ci			return LW5CHS_RET_BAIL3;
328d4afb5ceSopenharmony_ci		}
329d4afb5ceSopenharmony_ci		conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
330d4afb5ceSopenharmony_ci		pending_timeout =
331d4afb5ceSopenharmony_ci			   PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
332d4afb5ceSopenharmony_cisocks_send:
333d4afb5ceSopenharmony_ci		// lwsl_hexdump_notice(pt->serv_buf, len);
334d4afb5ceSopenharmony_ci		n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf,
335d4afb5ceSopenharmony_ci			      (size_t)len, MSG_NOSIGNAL);
336d4afb5ceSopenharmony_ci		if (n < 0) {
337d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "ERROR writing to socks proxy");
338d4afb5ceSopenharmony_ci			*pcce = "socks write fail";
339d4afb5ceSopenharmony_ci			return LW5CHS_RET_BAIL3;
340d4afb5ceSopenharmony_ci		}
341d4afb5ceSopenharmony_ci
342d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, (enum pending_timeout)pending_timeout,
343d4afb5ceSopenharmony_ci				(int)wsi->a.context->timeout_secs);
344d4afb5ceSopenharmony_ci		lwsi_set_state(wsi, (lws_wsi_state_t)conn_mode);
345d4afb5ceSopenharmony_ci		break;
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_cisocks_reply_fail:
348d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "socks reply: v%d, err %d",
349d4afb5ceSopenharmony_ci			     pt->serv_buf[0], pt->serv_buf[1]);
350d4afb5ceSopenharmony_ci		*pcce = "socks reply fail";
351d4afb5ceSopenharmony_ci		return LW5CHS_RET_BAIL3;
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci	case LRS_WAITING_SOCKS_CONNECT_REPLY:
354d4afb5ceSopenharmony_ci		if (pt->serv_buf[0] != SOCKS_VERSION_5 ||
355d4afb5ceSopenharmony_ci		    pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS)
356d4afb5ceSopenharmony_ci			goto socks_reply_fail;
357d4afb5ceSopenharmony_ci
358d4afb5ceSopenharmony_ci		lwsl_wsi_client(wsi, "socks connect OK");
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
361d4afb5ceSopenharmony_ci		if (lwsi_role_http(wsi) &&
362d4afb5ceSopenharmony_ci		    lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
363d4afb5ceSopenharmony_ci					  wsi->a.vhost->socks_proxy_address)) {
364d4afb5ceSopenharmony_ci			*pcce = "socks connect fail";
365d4afb5ceSopenharmony_ci			return LW5CHS_RET_BAIL3;
366d4afb5ceSopenharmony_ci		}
367d4afb5ceSopenharmony_ci#endif
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_ci		wsi->c_port = (uint16_t)wsi->a.vhost->socks_proxy_port;
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci		/* clear his proxy connection timeout */
372d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
373d4afb5ceSopenharmony_ci		return LW5CHS_RET_STARTHS;
374d4afb5ceSopenharmony_ci	default:
375d4afb5ceSopenharmony_ci		break;
376d4afb5ceSopenharmony_ci	}
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci	return LW5CHS_RET_NOTHING;
379d4afb5ceSopenharmony_ci}
380