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