1 /*
2 * Copyright (c) 2013-2020, The PurpleI2P Project
3 *
4 * This file is part of Purple i2pd project and licensed under BSD3
5 *
6 * See full license text in LICENSE file at top of project tree
7 */
8 
9 #include <cstring>
10 #include <cassert>
11 #include <string>
12 #include <atomic>
13 #include "SOCKS.h"
14 #include "Identity.h"
15 #include "Streaming.h"
16 #include "Destination.h"
17 #include "ClientContext.h"
18 #include "I2PEndian.h"
19 #include "I2PTunnel.h"
20 #include "I2PService.h"
21 #include "util.h"
22 
23 namespace i2p
24 {
25 namespace proxy
26 {
27 	static const size_t socks_buffer_size = 8192;
28 	static const size_t max_socks_hostname_size = 255; // Limit for socks5 and bad idea to traverse
29 
30 	static const size_t SOCKS_FORWARDER_BUFFER_SIZE = 8192;
31 
32 	static const size_t SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE = 8;
33 
34 	struct SOCKSDnsAddress
35 	{
36 		uint8_t size;
37 		char value[max_socks_hostname_size];
FromStringi2p::proxy::SOCKSDnsAddress38 		void FromString (const std::string& str)
39 		{
40 			size = str.length();
41 			if (str.length() > max_socks_hostname_size) size = max_socks_hostname_size;
42 			memcpy(value,str.c_str(),size);
43 		}
ToStringi2p::proxy::SOCKSDnsAddress44 		std::string ToString() { return std::string(value, size); }
push_backi2p::proxy::SOCKSDnsAddress45 		void push_back (char c) { value[size++] = c; }
46 	};
47 
48 	class SOCKSServer;
49 	class SOCKSHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<SOCKSHandler>
50 	{
51 		private:
52 
53 			enum state
54 			{
55 				GET_SOCKSV,
56 				GET_COMMAND,
57 				GET_PORT,
58 				GET_IPV4,
59 				GET4_IDENT,
60 				GET4A_HOST,
61 				GET5_AUTHNUM,
62 				GET5_AUTH,
63 				GET5_REQUESTV,
64 				GET5_GETRSV,
65 				GET5_GETADDRTYPE,
66 				GET5_IPV6,
67 				GET5_HOST_SIZE,
68 				GET5_HOST,
69 				READY,
70 				UPSTREAM_RESOLVE,
71 				UPSTREAM_CONNECT,
72 				UPSTREAM_HANDSHAKE
73 			};
74 			enum authMethods
75 			{
76 				AUTH_NONE = 0, //No authentication, skip to next step
77 				AUTH_GSSAPI = 1, //GSSAPI authentication
78 				AUTH_USERPASSWD = 2, //Username and password
79 				AUTH_UNACCEPTABLE = 0xff //No acceptable method found
80 			};
81 			enum addrTypes
82 			{
83 				ADDR_IPV4 = 1, //IPv4 address (4 octets)
84 				ADDR_DNS = 3, // DNS name (up to 255 octets)
85 				ADDR_IPV6 = 4 //IPV6 address (16 octets)
86 			};
87 			enum errTypes
88 			{
89 				SOCKS5_OK = 0, // No error for SOCKS5
90 				SOCKS5_GEN_FAIL = 1, // General server failure
91 				SOCKS5_RULE_DENIED = 2, // Connection disallowed by ruleset
92 				SOCKS5_NET_UNREACH = 3, // Network unreachable
93 				SOCKS5_HOST_UNREACH = 4, // Host unreachable
94 				SOCKS5_CONN_REFUSED = 5, // Connection refused by the peer
95 				SOCKS5_TTL_EXPIRED = 6, // TTL Expired
96 				SOCKS5_CMD_UNSUP = 7, // Command unsupported
97 				SOCKS5_ADDR_UNSUP = 8, // Address type unsupported
98 				SOCKS4_OK = 90, // No error for SOCKS4
99 				SOCKS4_FAIL = 91, // Failed establishing connecting or not allowed
100 				SOCKS4_IDENTD_MISSING = 92, // Couldn't connect to the identd server
101 				SOCKS4_IDENTD_DIFFER = 93 // The ID reported by the application and by identd differ
102 			};
103 			enum cmdTypes
104 			{
105 				CMD_CONNECT = 1, // TCP Connect
106 				CMD_BIND = 2, // TCP Bind
107 				CMD_UDP = 3 // UDP associate
108 			};
109 			enum socksVersions
110 			{
111 				SOCKS4 = 4, // SOCKS4
112 				SOCKS5 = 5 // SOCKS5
113 			};
114 			union address
115 			{
116 				uint32_t ip;
117 				SOCKSDnsAddress dns;
118 				uint8_t ipv6[16];
119 			};
120 
121 			void EnterState(state nstate, uint8_t parseleft = 1);
122 			bool HandleData(uint8_t *sock_buff, std::size_t len);
123 			bool ValidateSOCKSRequest();
124 			void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
125 			void Terminate();
126 			void AsyncSockRead();
127 			boost::asio::const_buffers_1 GenerateSOCKS5SelectAuth(authMethods method);
128 			boost::asio::const_buffers_1 GenerateSOCKS4Response(errTypes error, uint32_t ip, uint16_t port);
129 			boost::asio::const_buffers_1 GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port);
130 			boost::asio::const_buffers_1 GenerateUpstreamRequest();
131 			bool Socks5ChooseAuth();
132 			void SocksRequestFailed(errTypes error);
133 			void SocksRequestSuccess();
134 			void SentSocksFailed(const boost::system::error_code & ecode);
135 			void SentSocksDone(const boost::system::error_code & ecode);
136 			void SentSocksResponse(const boost::system::error_code & ecode);
137 			void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
138 			void ForwardSOCKS();
139 
140 			void SocksUpstreamSuccess();
141 			void AsyncUpstreamSockRead();
142 			void SendUpstreamRequest();
143 			void HandleUpstreamData(uint8_t * buff, std::size_t len);
144 			void HandleUpstreamSockSend(const boost::system::error_code & ecode, std::size_t bytes_transfered);
145 			void HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
146 			void HandleUpstreamConnected(const boost::system::error_code & ecode,
147 			boost::asio::ip::tcp::resolver::iterator itr);
148 			void HandleUpstreamResolved(const boost::system::error_code & ecode,
149 				boost::asio::ip::tcp::resolver::iterator itr);
150 
151 			boost::asio::ip::tcp::resolver m_proxy_resolver;
152 			uint8_t m_sock_buff[socks_buffer_size];
153 			std::shared_ptr<boost::asio::ip::tcp::socket> m_sock, m_upstreamSock;
154 			std::shared_ptr<i2p::stream::Stream> m_stream;
155 			uint8_t *m_remaining_data; //Data left to be sent
156 			uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded
157 			uint8_t m_response[7+max_socks_hostname_size];
158 			uint8_t m_upstream_response[SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE];
159 			uint8_t m_upstream_request[14+max_socks_hostname_size];
160 			std::size_t m_upstream_response_len;
161 			address m_address; //Address
162 			std::size_t m_remaining_data_len; //Size of the data left to be sent
163 			uint32_t m_4aip; //Used in 4a requests
164 			uint16_t m_port;
165 			uint8_t m_command;
166 			uint8_t m_parseleft; //Octets left to parse
167 			authMethods m_authchosen; //Authentication chosen
168 			addrTypes m_addrtype; //Address type chosen
169 			socksVersions m_socksv; //Socks version
170 			cmdTypes m_cmd; // Command requested
171 			state m_state;
172 			const bool m_UseUpstreamProxy; // do we want to use the upstream proxy for non i2p addresses?
173 			const std::string m_UpstreamProxyAddress;
174 			const uint16_t m_UpstreamProxyPort;
175 
176 		public:
177 
SOCKSHandler(SOCKSServer * parent,std::shared_ptr<boost::asio::ip::tcp::socket> sock,const std::string & upstreamAddr,const uint16_t upstreamPort,const bool useUpstream)178 			SOCKSHandler(SOCKSServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock, const std::string & upstreamAddr, const uint16_t upstreamPort, const bool useUpstream) :
179 				I2PServiceHandler(parent),
180 				m_proxy_resolver(parent->GetService()),
181 				m_sock(sock), m_stream(nullptr),
182 				m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4),
183 				m_UseUpstreamProxy(useUpstream),
184 				m_UpstreamProxyAddress(upstreamAddr),
185 				m_UpstreamProxyPort(upstreamPort)
186 				{ m_address.ip = 0; EnterState(GET_SOCKSV); }
187 
~SOCKSHandler()188 			~SOCKSHandler() { Terminate(); }
Handle()189 			void Handle() { AsyncSockRead(); }
190 	};
191 
AsyncSockRead()192 	void SOCKSHandler::AsyncSockRead()
193 	{
194 		LogPrint(eLogDebug, "SOCKS: Async sock read");
195 		if (m_sock) {
196 			m_sock->async_receive(boost::asio::buffer(m_sock_buff, socks_buffer_size),
197 				std::bind(&SOCKSHandler::HandleSockRecv, shared_from_this(),
198 				std::placeholders::_1, std::placeholders::_2));
199 		} else {
200 			LogPrint(eLogError,"SOCKS: No socket for read");
201 		}
202 	}
203 
Terminate()204 	void SOCKSHandler::Terminate()
205 	{
206 		if (Kill()) return;
207 		if (m_sock)
208 		{
209 			LogPrint(eLogDebug, "SOCKS: Closing socket");
210 			m_sock->close();
211 			m_sock = nullptr;
212 		}
213 		if (m_upstreamSock)
214 		{
215 			LogPrint(eLogDebug, "SOCKS: Closing upstream socket");
216 			m_upstreamSock->close();
217 			m_upstreamSock = nullptr;
218 		}
219 		if (m_stream)
220 		{
221 			LogPrint(eLogDebug, "SOCKS: Closing stream");
222 			m_stream.reset ();
223 		}
224 		Done(shared_from_this());
225 	}
226 
GenerateSOCKS4Response(SOCKSHandler::errTypes error,uint32_t ip,uint16_t port)227 	boost::asio::const_buffers_1 SOCKSHandler::GenerateSOCKS4Response(SOCKSHandler::errTypes error, uint32_t ip, uint16_t port)
228 	{
229 		assert(error >= SOCKS4_OK);
230 		m_response[0] = '\x00';           // version
231 		m_response[1] = error;            // response code
232 		htobe16buf(m_response + 2, port); // port
233 		htobe32buf(m_response + 4, ip);   // IP
234 		return boost::asio::const_buffers_1(m_response,8);
235 	}
236 
GenerateSOCKS5Response(SOCKSHandler::errTypes error,SOCKSHandler::addrTypes type,const SOCKSHandler::address & addr,uint16_t port)237 	boost::asio::const_buffers_1 SOCKSHandler::GenerateSOCKS5Response(SOCKSHandler::errTypes error, SOCKSHandler::addrTypes type, const SOCKSHandler::address &addr, uint16_t port)
238 	{
239 		size_t size = 6;        // header + port
240 		assert(error <= SOCKS5_ADDR_UNSUP);
241 		m_response[0] = '\x05'; // version
242 		m_response[1] = error;  // response code
243 		m_response[2] = '\x00'; // reserved
244 		m_response[3] = type;   // address type
245 		switch (type)
246 		{
247 			case ADDR_IPV4:
248 				size += 4;
249 				htobe32buf(m_response + 4, addr.ip);
250 				htobe16buf(m_response + size - 2, port);
251 				break;
252 			case ADDR_IPV6:
253 				size += 16;
254 				memcpy(m_response + 4, addr.ipv6, 16);
255 				htobe16buf(m_response + size - 2, port);
256 				break;
257 			case ADDR_DNS:
258 				std::string address(addr.dns.value, addr.dns.size);
259 				if(address.substr(addr.dns.size - 4, 4) == ".i2p") // overwrite if requested address inside I2P
260 				{
261 					m_response[3] = ADDR_IPV4;
262 					size += 4;
263 					memset(m_response + 4, 0, 6); // six HEX zeros
264 				}
265 				else
266 				{
267 					size += (1 + addr.dns.size); /* name length + resolved address */
268 					m_response[4] = addr.dns.size;
269 					memcpy(m_response + 5, addr.dns.value, addr.dns.size);
270 					htobe16buf(m_response + size - 2, port);
271 				}
272 				break;
273 		}
274 		return boost::asio::const_buffers_1(m_response, size);
275 	}
276 
GenerateUpstreamRequest()277 	boost::asio::const_buffers_1 SOCKSHandler::GenerateUpstreamRequest()
278 	{
279 		size_t upstreamRequestSize = 0;
280 		// TODO: negotiate with upstream
281 		// SOCKS 4a
282 		m_upstream_request[0] = '\x04'; //version
283 		m_upstream_request[1] = m_cmd;
284 		htobe16buf(m_upstream_request + 2, m_port);
285 		m_upstream_request[4] = 0;
286 		m_upstream_request[5] = 0;
287 		m_upstream_request[6] = 0;
288 		m_upstream_request[7] = 1;
289 		// user id
290 		m_upstream_request[8] = 'i';
291 		m_upstream_request[9] = '2';
292 		m_upstream_request[10] = 'p';
293 		m_upstream_request[11] = 'd';
294 		m_upstream_request[12] = 0;
295 		upstreamRequestSize += 13;
296 		if (m_address.dns.size <= max_socks_hostname_size - ( upstreamRequestSize + 1) ) {
297 			// bounds check okay
298 			memcpy(m_upstream_request + upstreamRequestSize, m_address.dns.value, m_address.dns.size);
299 			upstreamRequestSize += m_address.dns.size;
300 			// null terminate
301 			m_upstream_request[++upstreamRequestSize] = 0;
302 		} else {
303 			LogPrint(eLogError, "SOCKS: BUG!!! m_addr.dns.sizs > max_socks_hostname - ( upstreamRequestSize + 1 ) )");
304 		}
305 		return boost::asio::const_buffers_1(m_upstream_request, upstreamRequestSize);
306 	}
307 
Socks5ChooseAuth()308 	bool SOCKSHandler::Socks5ChooseAuth()
309 	{
310 		m_response[0] = '\x05'; // Version
311 		m_response[1] = m_authchosen; // Response code
312 		boost::asio::const_buffers_1 response(m_response, 2);
313 		if (m_authchosen == AUTH_UNACCEPTABLE)
314 		{
315 			LogPrint(eLogWarning, "SOCKS: v5 authentication negotiation failed");
316 			boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksFailed, shared_from_this(), std::placeholders::_1));
317 			return false;
318 		}
319 		else
320 		{
321 			LogPrint(eLogDebug, "SOCKS: v5 choosing authentication method: ", m_authchosen);
322 			boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksResponse, shared_from_this(), std::placeholders::_1));
323 			return true;
324 		}
325 	}
326 
327 	/* All hope is lost beyond this point */
SocksRequestFailed(SOCKSHandler::errTypes error)328 	void SOCKSHandler::SocksRequestFailed(SOCKSHandler::errTypes error)
329 	{
330 		boost::asio::const_buffers_1 response(nullptr,0);
331 		assert(error != SOCKS4_OK && error != SOCKS5_OK);
332 		switch (m_socksv)
333 		{
334 			case SOCKS4:
335 				LogPrint(eLogWarning, "SOCKS: v4 request failed: ", error);
336 				if (error < SOCKS4_OK) error = SOCKS4_FAIL; // Transparently map SOCKS5 errors
337 				response = GenerateSOCKS4Response(error, m_4aip, m_port);
338 			break;
339 			case SOCKS5:
340 				LogPrint(eLogWarning, "SOCKS: v5 request failed: ", error);
341 				response = GenerateSOCKS5Response(error, m_addrtype, m_address, m_port);
342 			break;
343 		}
344 		boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksFailed,
345 			shared_from_this(), std::placeholders::_1));
346 	}
347 
SocksRequestSuccess()348 	void SOCKSHandler::SocksRequestSuccess()
349 	{
350 		boost::asio::const_buffers_1 response(nullptr,0);
351 		// TODO: this should depend on things like the command type and callbacks may change
352 		switch (m_socksv)
353 		{
354 			case SOCKS4:
355 				LogPrint(eLogInfo, "SOCKS: v4 connection success");
356 				response = GenerateSOCKS4Response(SOCKS4_OK, m_4aip, m_port);
357 			break;
358 			case SOCKS5:
359 				LogPrint(eLogInfo, "SOCKS: v5 connection success");
360 				auto s = i2p::client::context.GetAddressBook().ToAddress(GetOwner()->GetLocalDestination()->GetIdentHash());
361 				address ad; ad.dns.FromString(s);
362 				// HACK only 16 bits passed in port as SOCKS5 doesn't allow for more
363 				response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, ad, m_stream->GetRecvStreamID());
364 			break;
365 		}
366 		boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksDone, shared_from_this(), std::placeholders::_1));
367 	}
368 
EnterState(SOCKSHandler::state nstate,uint8_t parseleft)369 	void SOCKSHandler::EnterState(SOCKSHandler::state nstate, uint8_t parseleft) {
370 		switch (nstate)
371 		{
372 			case GET_PORT: parseleft = 2; break;
373 			case GET_IPV4: m_addrtype = ADDR_IPV4; m_address.ip = 0; parseleft = 4; break;
374 			case GET4_IDENT: m_4aip = m_address.ip; break;
375 			case GET4A_HOST:
376 			case GET5_HOST: m_addrtype = ADDR_DNS; m_address.dns.size = 0; break;
377 			case GET5_IPV6: m_addrtype = ADDR_IPV6; parseleft = 16; break;
378 			default:;
379 		}
380 		m_parseleft = parseleft;
381 		m_state = nstate;
382 	}
383 
ValidateSOCKSRequest()384 	bool SOCKSHandler::ValidateSOCKSRequest()
385 	{
386 		if ( m_cmd != CMD_CONNECT )
387 		{
388 			// TODO: we need to support binds and other shit!
389 			LogPrint(eLogError, "SOCKS: Unsupported command: ", m_cmd);
390 			SocksRequestFailed(SOCKS5_CMD_UNSUP);
391 			return false;
392 		}
393 		// TODO: we may want to support other address types!
394 		if ( m_addrtype != ADDR_DNS )
395 		{
396 			switch (m_socksv)
397 			{
398 				case SOCKS5:
399 					LogPrint(eLogError, "SOCKS: v5 unsupported address type: ", m_addrtype);
400 				break;
401 				case SOCKS4:
402 					LogPrint(eLogError, "SOCKS: Request with v4a rejected because it's actually SOCKS4");
403 				break;
404 			}
405 			SocksRequestFailed(SOCKS5_ADDR_UNSUP);
406 			return false;
407 		}
408 		return true;
409 	}
410 
HandleData(uint8_t * sock_buff,std::size_t len)411 	bool SOCKSHandler::HandleData(uint8_t *sock_buff, std::size_t len)
412 	{
413 		assert(len); // This should always be called with a least a byte left to parse
414 		while (len > 0)
415 		{
416 			switch (m_state)
417 			{
418 				case GET_SOCKSV:
419 					m_socksv = (SOCKSHandler::socksVersions) *sock_buff;
420 					switch (*sock_buff)
421 					{
422 						case SOCKS4:
423 							EnterState(GET_COMMAND); //Initialize the parser at the right position
424 						break;
425 						case SOCKS5:
426 							EnterState(GET5_AUTHNUM); //Initialize the parser at the right position
427 						break;
428 						default:
429 							LogPrint(eLogError, "SOCKS: Rejected invalid version: ", ((int)*sock_buff));
430 							Terminate();
431 							return false;
432 					}
433 				break;
434 				case GET5_AUTHNUM:
435 					EnterState(GET5_AUTH, *sock_buff);
436 				break;
437 				case GET5_AUTH:
438 					m_parseleft --;
439 					if (*sock_buff == AUTH_NONE)
440 						m_authchosen = AUTH_NONE;
441 					if ( m_parseleft == 0 )
442 					{
443 						if (!Socks5ChooseAuth()) return false;
444 						EnterState(GET5_REQUESTV);
445 					}
446 				break;
447 				case GET_COMMAND:
448 					switch (*sock_buff)
449 					{
450 						case CMD_CONNECT:
451 						case CMD_BIND:
452 						break;
453 						case CMD_UDP:
454 							if (m_socksv == SOCKS5) break;
455 #if (__cplusplus >= 201703L) // C++ 17 or higher
456 							[[fallthrough]];
457 #endif
458 						default:
459 							LogPrint(eLogError, "SOCKS: Invalid command: ", ((int)*sock_buff));
460 							SocksRequestFailed(SOCKS5_GEN_FAIL);
461 							return false;
462 					}
463 					m_cmd = (SOCKSHandler::cmdTypes)*sock_buff;
464 					switch (m_socksv)
465 					{
466 						case SOCKS5: EnterState(GET5_GETRSV); break;
467 						case SOCKS4: EnterState(GET_PORT); break;
468 					}
469 				break;
470 				case GET_PORT:
471 					m_port = (m_port << 8)|((uint16_t)*sock_buff);
472 					m_parseleft--;
473 					if (m_parseleft == 0)
474 					{
475 						switch (m_socksv)
476 						{
477 							case SOCKS5: EnterState(READY); break;
478 							case SOCKS4: EnterState(GET_IPV4); break;
479 						}
480 					}
481 				break;
482 				case GET_IPV4:
483 					m_address.ip = (m_address.ip << 8)|((uint32_t)*sock_buff);
484 					m_parseleft--;
485 					if (m_parseleft == 0)
486 					{
487 						switch (m_socksv)
488 						{
489 							case SOCKS5: EnterState(GET_PORT); break;
490 							case SOCKS4: EnterState(GET4_IDENT); m_4aip = m_address.ip; break;
491 						}
492 					}
493 				break;
494 				case GET4_IDENT:
495 					if (!*sock_buff)
496 					{
497 						if( m_4aip == 0 || m_4aip > 255 )
498 							EnterState(READY);
499 						else
500 							EnterState(GET4A_HOST);
501 					}
502 				break;
503 				case GET4A_HOST:
504 					if (!*sock_buff)
505 					{
506 						EnterState(READY);
507 						break;
508 					}
509 					if (m_address.dns.size >= max_socks_hostname_size)
510 					{
511 						LogPrint(eLogError, "SOCKS: v4a req failed: destination is too large");
512 						SocksRequestFailed(SOCKS4_FAIL);
513 						return false;
514 					}
515 					m_address.dns.push_back(*sock_buff);
516 				break;
517 				case GET5_REQUESTV:
518 					if (*sock_buff != SOCKS5)
519 					{
520 						LogPrint(eLogError,"SOCKS: v5 rejected unknown request version: ", ((int)*sock_buff));
521 						SocksRequestFailed(SOCKS5_GEN_FAIL);
522 						return false;
523 					}
524 					EnterState(GET_COMMAND);
525 				break;
526 				case GET5_GETRSV:
527 					if ( *sock_buff != 0 )
528 					{
529 						LogPrint(eLogError, "SOCKS: v5 unknown reserved field: ", ((int)*sock_buff));
530 						SocksRequestFailed(SOCKS5_GEN_FAIL);
531 						return false;
532 					}
533 					EnterState(GET5_GETADDRTYPE);
534 				break;
535 				case GET5_GETADDRTYPE:
536 					switch (*sock_buff)
537 					{
538 						case ADDR_IPV4: EnterState(GET_IPV4); break;
539 						case ADDR_IPV6: EnterState(GET5_IPV6); break;
540 						case ADDR_DNS : EnterState(GET5_HOST_SIZE); break;
541 						default:
542 							LogPrint(eLogError, "SOCKS: v5 unknown address type: ", ((int)*sock_buff));
543 							SocksRequestFailed(SOCKS5_GEN_FAIL);
544 							return false;
545 					}
546 				break;
547 				case GET5_IPV6:
548 					m_address.ipv6[16-m_parseleft] = *sock_buff;
549 					m_parseleft--;
550 					if (m_parseleft == 0) EnterState(GET_PORT);
551 				break;
552 				case GET5_HOST_SIZE:
553 					EnterState(GET5_HOST, *sock_buff);
554 				break;
555 				case GET5_HOST:
556 					m_address.dns.push_back(*sock_buff);
557 					m_parseleft--;
558 					if (m_parseleft == 0) EnterState(GET_PORT);
559 				break;
560 				default:
561 					LogPrint(eLogError, "SOCKS: Parse state?? ", m_state);
562 					Terminate();
563 					return false;
564 			}
565 			sock_buff++;
566 			len--;
567 			if (m_state == READY)
568 			{
569 				m_remaining_data_len = len;
570 				m_remaining_data = sock_buff;
571 				return ValidateSOCKSRequest();
572 			}
573 		}
574 		return true;
575 	}
576 
HandleSockRecv(const boost::system::error_code & ecode,std::size_t len)577 	void SOCKSHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
578 	{
579 		LogPrint(eLogDebug, "SOCKS: Received ", len, " bytes");
580 		if(ecode)
581 		{
582 			LogPrint(eLogWarning, "SOCKS: Recv got error: ", ecode);
583 			Terminate();
584 			return;
585 		}
586 
587 		if (HandleData(m_sock_buff, len))
588 		{
589 			if (m_state == READY)
590 			{
591 				const std::string addr = m_address.dns.ToString();
592 				LogPrint(eLogInfo, "SOCKS: Requested ", addr, ":" , m_port);
593 				const size_t addrlen = addr.size();
594 				// does it end with .i2p?
595 				if ( addr.rfind(".i2p") == addrlen - 4) {
596 					// yes it does, make an i2p session
597 					GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete,
598 							shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port);
599 				} else if (m_UseUpstreamProxy) {
600 					// forward it to upstream proxy
601 					ForwardSOCKS();
602 				} else {
603 					// no upstream proxy
604 					SocksRequestFailed(SOCKS5_ADDR_UNSUP);
605 				}
606 			}
607 			else
608 				AsyncSockRead();
609 		}
610 	}
611 
SentSocksFailed(const boost::system::error_code & ecode)612 	void SOCKSHandler::SentSocksFailed(const boost::system::error_code & ecode)
613 	{
614 		if (ecode)
615 			LogPrint (eLogError, "SOCKS: Closing socket after sending failure because: ", ecode.message ());
616 		Terminate();
617 	}
618 
SentSocksDone(const boost::system::error_code & ecode)619 	void SOCKSHandler::SentSocksDone(const boost::system::error_code & ecode)
620 	{
621 		if (!ecode)
622 		{
623 			if (Kill()) return;
624 			LogPrint (eLogInfo, "SOCKS: New I2PTunnel connection");
625 			auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, m_stream);
626 			GetOwner()->AddHandler (connection);
627 			connection->I2PConnect (m_remaining_data,m_remaining_data_len);
628 			Done(shared_from_this());
629 		}
630 		else
631 		{
632 			LogPrint (eLogError, "SOCKS: Closing socket after completion reply because: ", ecode.message ());
633 			Terminate();
634 		}
635 	}
636 
SentSocksResponse(const boost::system::error_code & ecode)637 	void SOCKSHandler::SentSocksResponse(const boost::system::error_code & ecode)
638 	{
639 		if (ecode)
640 		{
641 			LogPrint (eLogError, "SOCKS: Closing socket after sending reply because: ", ecode.message ());
642 			Terminate();
643 		}
644 	}
645 
HandleStreamRequestComplete(std::shared_ptr<i2p::stream::Stream> stream)646 	void SOCKSHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
647 	{
648 		if (stream)
649 		{
650 			m_stream = stream;
651 			SocksRequestSuccess();
652 		}
653 		else
654 		{
655 			LogPrint (eLogError, "SOCKS: Error when creating the stream, check the previous warnings for more info");
656 			SocksRequestFailed(SOCKS5_HOST_UNREACH);
657 		}
658 	}
659 
ForwardSOCKS()660 	void SOCKSHandler::ForwardSOCKS()
661 	{
662 		LogPrint(eLogInfo, "SOCKS: Forwarding to upstream");
663 		EnterState(UPSTREAM_RESOLVE);
664 		boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort));
665 		m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(),
666 			std::placeholders::_1, std::placeholders::_2));
667 	}
668 
AsyncUpstreamSockRead()669 	void SOCKSHandler::AsyncUpstreamSockRead()
670 	{
671 		LogPrint(eLogDebug, "SOCKS: Async upstream sock read");
672 		if (m_upstreamSock) {
673 			m_upstreamSock->async_read_some(boost::asio::buffer(m_upstream_response, SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE),
674 				std::bind(&SOCKSHandler::HandleUpstreamSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
675 		} else {
676 			LogPrint(eLogError, "SOCKS: No upstream socket for read");
677 			SocksRequestFailed(SOCKS5_GEN_FAIL);
678 		}
679 	}
680 
HandleUpstreamSockRecv(const boost::system::error_code & ecode,std::size_t bytes_transfered)681 	void SOCKSHandler::HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered)
682 	{
683 		if (ecode) {
684 			if (m_state == UPSTREAM_HANDSHAKE ) {
685 				// we are trying to handshake but it failed
686 				SocksRequestFailed(SOCKS5_NET_UNREACH);
687 			} else {
688 				LogPrint(eLogError, "SOCKS: Bad state when reading from upstream: ", (int) m_state);
689 			}
690 			return;
691 		}
692 		HandleUpstreamData(m_upstream_response, bytes_transfered);
693 	}
694 
SocksUpstreamSuccess()695 	void SOCKSHandler::SocksUpstreamSuccess()
696 	{
697 		LogPrint(eLogInfo, "SOCKS: Upstream success");
698 		boost::asio::const_buffers_1 response(nullptr, 0);
699 		switch (m_socksv)
700 		{
701 			case SOCKS4:
702 				LogPrint(eLogInfo, "SOCKS: v4 connection success");
703 				response = GenerateSOCKS4Response(SOCKS4_OK, m_4aip, m_port);
704 			break;
705 			case SOCKS5:
706 				LogPrint(eLogInfo, "SOCKS: v5 connection success");
707 				//HACK only 16 bits passed in port as SOCKS5 doesn't allow for more
708 				response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, m_address, m_port);
709 			break;
710 		}
711 		m_sock->send(response);
712 		auto forwarder = std::make_shared<i2p::client::TCPIPPipe>(GetOwner(), m_sock, m_upstreamSock);
713 		m_upstreamSock = nullptr;
714 		m_sock = nullptr;
715 		GetOwner()->AddHandler(forwarder);
716 		forwarder->Start();
717 		Terminate();
718 
719 	}
720 
HandleUpstreamData(uint8_t * dataptr,std::size_t len)721 	void SOCKSHandler::HandleUpstreamData(uint8_t * dataptr, std::size_t len)
722 	{
723 		if (m_state == UPSTREAM_HANDSHAKE) {
724 			m_upstream_response_len += len;
725 			// handle handshake data
726 			if (m_upstream_response_len < SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) {
727 				// too small, continue reading
728 				AsyncUpstreamSockRead();
729 			} else if (len == SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) {
730 				// just right
731 				uint8_t resp = m_upstream_response[1];
732 				if (resp == SOCKS4_OK) {
733 					// we have connected !
734 					SocksUpstreamSuccess();
735 				} else {
736 					// upstream failure
737 					LogPrint(eLogError, "SOCKS: Upstream proxy failure: ", (int) resp);
738 					// TODO: runtime error?
739 					SocksRequestFailed(SOCKS5_GEN_FAIL);
740 				}
741 			} else {
742 				// too big
743 				SocksRequestFailed(SOCKS5_GEN_FAIL);
744 			}
745 		} else {
746 			// invalid state
747 			LogPrint(eLogError, "SOCKS: Invalid state reading from upstream: ", (int) m_state);
748 		}
749 	}
750 
SendUpstreamRequest()751 	void SOCKSHandler::SendUpstreamRequest()
752 	{
753 		LogPrint(eLogInfo, "SOCKS: Negotiating with upstream proxy");
754 		EnterState(UPSTREAM_HANDSHAKE);
755 		if (m_upstreamSock) {
756 			boost::asio::write(*m_upstreamSock, GenerateUpstreamRequest());
757 			AsyncUpstreamSockRead();
758 		} else {
759 			LogPrint(eLogError, "SOCKS: No upstream socket to send handshake to");
760 		}
761 	}
762 
HandleUpstreamConnected(const boost::system::error_code & ecode,boost::asio::ip::tcp::resolver::iterator itr)763 	void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr)
764 	{
765 		if (ecode) {
766 			LogPrint(eLogWarning, "SOCKS: Could not connect to upstream proxy: ", ecode.message());
767 			SocksRequestFailed(SOCKS5_NET_UNREACH);
768 			return;
769 		}
770 		LogPrint(eLogInfo, "SOCKS: Connected to upstream proxy");
771 		SendUpstreamRequest();
772 	}
773 
HandleUpstreamResolved(const boost::system::error_code & ecode,boost::asio::ip::tcp::resolver::iterator itr)774 	void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr)
775 	{
776 		if (ecode) {
777 			// error resolving
778 			LogPrint(eLogWarning, "SOCKS: Upstream proxy", m_UpstreamProxyAddress, " not resolved: ", ecode.message());
779 			SocksRequestFailed(SOCKS5_NET_UNREACH);
780 			return;
781 		}
782 		LogPrint(eLogInfo, "SOCKS: Upstream proxy resolved");
783 		EnterState(UPSTREAM_CONNECT);
784 		auto & service = GetOwner()->GetService();
785 		m_upstreamSock = std::make_shared<boost::asio::ip::tcp::socket>(service);
786 		boost::asio::async_connect(*m_upstreamSock, itr,
787 			std::bind(&SOCKSHandler::HandleUpstreamConnected,
788 			shared_from_this(), std::placeholders::_1, std::placeholders::_2));
789 	}
790 
SOCKSServer(const std::string & name,const std::string & address,int port,bool outEnable,const std::string & outAddress,uint16_t outPort,std::shared_ptr<i2p::client::ClientDestination> localDestination)791 	SOCKSServer::SOCKSServer(const std::string& name, const std::string& address, int port,
792 		bool outEnable, const std::string& outAddress, uint16_t outPort,
793 		std::shared_ptr<i2p::client::ClientDestination> localDestination) :
794 			TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), m_Name (name)
795 	{
796 		m_UseUpstreamProxy = false;
797 		if (outAddress.length() > 0 && outEnable)
798 			SetUpstreamProxy(outAddress, outPort);
799 	}
800 
CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)801 	std::shared_ptr<i2p::client::I2PServiceHandler> SOCKSServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
802 	{
803 		return std::make_shared<SOCKSHandler> (this, socket, m_UpstreamProxyAddress, m_UpstreamProxyPort, m_UseUpstreamProxy);
804 	}
805 
SetUpstreamProxy(const std::string & addr,const uint16_t port)806 	void SOCKSServer::SetUpstreamProxy(const std::string & addr, const uint16_t port)
807 	{
808 		m_UpstreamProxyAddress = addr;
809 		m_UpstreamProxyPort = port;
810 		m_UseUpstreamProxy = true;
811 	}
812 }
813 }
814