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