1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
10 //
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24 //
25 
26 #include "Proxy.h"		/* for Interface		*/
27 
28 #include <common/EventIDs.h>
29 
30 #include "ArchSpecific.h"	/* for ENDIAN_HTONS()		*/
31 #include "Logger.h"		/* for AddDebugLogLineN		*/
32 #include "OtherFunctions.h"	/* for EncodeBase64()		*/
33 #include <common/StringFunctions.h>	/* for unicode2char */
34 #include "GuiEvents.h"
35 
36 // Define it to 1 to debug proxy communication and state machine design. If
37 // enabled messages sent to and received from proxies will be dumped to stdout.
38 // Has effect only in debug-enabled builds.
39 #ifndef DEBUG_DUMP_PROXY_MSG
40 #define DEBUG_DUMP_PROXY_MSG	0
41 #endif
42 
43 
44 //------------------------------------------------------------------------------
45 // CProxyData
46 //------------------------------------------------------------------------------
47 
CProxyData()48 CProxyData::CProxyData()
49 {
50 	Clear();
51 }
52 
CProxyData(bool proxyEnable,CProxyType proxyType,const wxString & proxyHostName,unsigned short proxyPort,bool enablePassword,const wxString & userName,const wxString & password)53 CProxyData::CProxyData(
54 	bool		proxyEnable,
55 	CProxyType	proxyType,
56 	const wxString	&proxyHostName,
57 	unsigned short	proxyPort,
58 	bool		enablePassword,
59 	const wxString	&userName,
60 	const wxString	&password)
61 :
62 m_proxyEnable(proxyEnable),
63 m_proxyType(proxyType),
64 m_proxyHostName(proxyHostName),
65 m_proxyPort(proxyPort),
66 m_enablePassword(enablePassword),
67 m_userName(userName),
68 m_password(password)
69 {
70 }
71 
Clear()72 void CProxyData::Clear()
73 {
74 	m_proxyEnable = false;
75 	m_proxyType = PROXY_NONE;
76 	m_proxyHostName.Clear();
77 	m_proxyPort = 0;
78 	m_enablePassword = false;
79 	m_userName.Clear();
80 	m_password.Clear();
81 }
82 
83 #ifndef CLIENT_GUI
84 
85 #include <typeinfo> // Do_not_auto_remove (NetBSD, older gccs)
86 
87 #ifndef ASIO_SOCKETS
88 
89 //------------------------------------------------------------------------------
90 // ProxyEventHandler
91 //------------------------------------------------------------------------------
92 
CProxyEventHandler()93 CProxyEventHandler::CProxyEventHandler()
94 {
95 }
96 
97 BEGIN_EVENT_TABLE(CProxyEventHandler, wxEvtHandler)
98 	EVT_SOCKET(ID_PROXY_SOCKET_EVENT, CProxyEventHandler::ProxySocketHandler)
99 END_EVENT_TABLE()
100 
101 //
102 // THE one and only Event Handler
103 //
104 static CProxyEventHandler g_proxyEventHandler;
105 
ProxySocketHandler(wxSocketEvent & event)106 void CProxyEventHandler::ProxySocketHandler(wxSocketEvent& event)
107 {
108 	CProxySocket *sock = dynamic_cast<CProxySocket *>(event.GetSocket());
109 	if (sock) {
110 		sock->m_proxyStateMachine->Schedule(event.GetSocketEvent());
111 		sock->m_proxyStateMachine->Clock();
112 	} else {
113 		// we're doomed :)
114 	}
115 }
116 
117 #else
118 
119 //
120 // In Asio mode the event handler is:
121 //
OnProxyEvent(int evt)122 void CProxySocket::OnProxyEvent(int evt)
123 {
124 	m_proxyStateMachine->Schedule(evt);
125 	m_proxyStateMachine->Clock();
126 }
127 
128 #endif
129 
130 //------------------------------------------------------------------------------
131 // CProxyStateMachine
132 //------------------------------------------------------------------------------
133 
CProxyStateMachine(wxString name,const unsigned int max_states,const CProxyData & proxyData,CProxyCommand proxyCommand)134 CProxyStateMachine::CProxyStateMachine(
135 		wxString name,
136 		const unsigned int max_states,
137 		const CProxyData &proxyData,
138 		CProxyCommand proxyCommand)
139 :
140 CStateMachine(NewName(name, proxyCommand), max_states, PROXY_STATE_START),
141 m_proxyData(proxyData),
142 m_proxyCommand(proxyCommand),
143 m_isLost(false),
144 m_isConnected(false),
145 m_canReceive(false),
146 m_canSend(false),
147 m_ok(true),
148 m_lastRead(0),
149 // Will be initialized at Start()
150 m_peerAddress(NULL),
151 m_proxyClientSocket(NULL),
152 m_proxyBoundAddress(NULL),
153 // Temporary variables
154 m_lastReply(0),
155 m_packetLenght(0)
156 {
157 }
158 
~CProxyStateMachine()159 CProxyStateMachine::~CProxyStateMachine()
160 {
161 	delete m_peerAddress;
162 }
163 
NewName(wxString & s,CProxyCommand proxyCommand)164 wxString &CProxyStateMachine::NewName(wxString &s, CProxyCommand proxyCommand)
165 {
166 	switch (proxyCommand) {
167 	case PROXY_CMD_CONNECT:
168 		s += wxT("-CONNECT");
169 		break;
170 
171 	case PROXY_CMD_BIND:
172 		s += wxT("-BIND");
173 		break;
174 
175 	case PROXY_CMD_UDP_ASSOCIATE:
176 		s += wxT("-UDP");
177 		break;
178 	}
179 
180 	return s;
181 }
182 
Start(const amuleIPV4Address & peerAddress,CLibSocket * proxyClientSocket)183 bool CProxyStateMachine::Start(const amuleIPV4Address &peerAddress, CLibSocket *proxyClientSocket)
184 {
185 	m_proxyClientSocket = proxyClientSocket;
186 	m_peerAddress = new amuleIPV4Address(peerAddress);
187 	//try {
188 	//	const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
189 	//	m_peerAddress = new amuleIPV4Address(peer);
190 	//} catch (const std::bad_cast& WXUNUSED(e)) {
191 	//	// Should process other types of wxIPAddres before quitting
192 	//	AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
193 	//	wxFAIL;
194 	//	return false;
195 	//}
196 
197 	// To run the state machine, return and just let the events start to happen.
198 	return true;
199 }
200 
201 static const int MULE_SOCKET_DUMMY_VALUE = MULE_SOCKET_INPUT + MULE_SOCKET_OUTPUT + MULE_SOCKET_CONNECTION + MULE_SOCKET_LOST;
202 
HandleEvent(t_sm_event event)203 t_sm_state CProxyStateMachine::HandleEvent(t_sm_event event)
204 {
205 	// Default is stay in current state
206 	t_sm_state ret = GetState();
207 	switch(event)
208 	{
209 	case MULE_SOCKET_CONNECTION:
210 		AddDebugLogLineN(logProxy, wxT("Connection event"));
211 		m_isConnected = true;
212 		break;
213 
214 	case MULE_SOCKET_INPUT:
215 		AddDebugLogLineN(logProxy, wxT("Input event"));
216 		m_canReceive = true;
217 		break;
218 
219 	case MULE_SOCKET_OUTPUT:
220 		AddDebugLogLineN(logProxy, wxT("Output event"));
221 		m_canSend = true;
222 		break;
223 
224 	case MULE_SOCKET_LOST:
225 		AddDebugLogLineN(logProxy, wxT("Lost connection event"));
226 		m_isLost = true;
227 		m_ok = false;
228 		break;
229 
230 	case MULE_SOCKET_DUMMY_VALUE:
231 		AddDebugLogLineN(logProxy, wxT("Dummy event"));
232 		break;
233 
234 	default:
235 		AddDebugLogLineN(logProxy, CFormat(wxT("Unknown event %d")) % event);
236 		break;
237 	}
238 
239 	// Aborting conditions:
240 	// - MULE_SOCKET_LOST event
241 	// - More than 10 times on the same state
242 	if (	m_isLost ||
243 		GetClocksInCurrentState() > 10) {
244 		ret = PROXY_STATE_END;
245 	}
246 
247 	return ret;
248 }
249 
AddDummyEvent()250 void CProxyStateMachine::AddDummyEvent()
251 {
252 #ifdef ASIO_SOCKETS
253 	CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
254 	if (s) {	// should always be
255 		CoreNotify_ProxySocketEvent(s, MULE_SOCKET_DUMMY_VALUE);
256 	}
257 #else
258 	wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
259 	// Make sure this is an unknown event :)
260 	e.m_event = (wxSocketNotify)(MULE_SOCKET_DUMMY_VALUE);
261 	e.SetEventObject(m_proxyClientSocket);
262 	g_proxyEventHandler.AddPendingEvent(e);
263 #endif
264 }
265 
ReactivateSocket()266 void CProxyStateMachine::ReactivateSocket()
267 {
268 	/*    If proxy is beeing used, then the TCP socket handlers
269 	 * (CServerSocketHandler and CClientTCPSocketHandler) will not
270 	 * receive a wxSOCKET_CONNECTION event, because the connection has
271 	 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
272 	 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
273 	 * necessary to start sending data to the server. */
274 	CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
275 	// If that is not true, we are in serious trouble...
276 	wxASSERT(s);
277 	if (CDatagramSocketProxy *udp = s->GetUDPSocket()) {
278 		// The original socket was a UDP socket
279 		if(m_ok) {
280 			// From now on, the UDP socket can be used,
281 			// remove the protection.
282 			udp->SetUDPSocketOk();
283 		}
284 		// No need to call RestoreState(), that socket will no longer
285 		// be used after proxy negotiation.
286 	} else {
287 		// The original socket was a TCP socket
288 #ifdef ASIO_SOCKETS
289 		if (s->GetProxyState()) {	// somehow this gets called twice ?
290 			s->SetProxyState(false);
291 			CoreNotify_LibSocketConnect(s, 0);
292 			if (m_ok) {
293 				CoreNotify_LibSocketSend(s, 0);
294 			} else {
295 				CoreNotify_LibSocketLost(s);
296 			}
297 		}
298 #else
299 		s->RestoreEventHandler();
300 		wxSocketEvent e(s->GetEventHandlerId());
301 		e.m_event = wxSOCKET_CONNECTION;
302 		e.SetEventObject(s);
303 		wxEvtHandler *h(s->GetEventHandler());
304 		h->AddPendingEvent(e);
305 		e.m_event = wxSOCKET_OUTPUT;
306 		h->AddPendingEvent(e);
307 		if (!m_ok) {
308 			e.m_event = wxSOCKET_LOST;
309 			h->AddPendingEvent(e);
310 		}
311 		s->RestoreState();
312 #endif
313 	}
314 }
315 
ProxyWrite(CLibSocket & socket,const void * buffer,wxUint32 nbytes)316 uint32 CProxyStateMachine::ProxyWrite(CLibSocket &socket, const void *buffer, wxUint32 nbytes)
317 {
318 	uint32 written = socket.Write(buffer, nbytes);
319 	/* Set the status of this operation */
320 	m_ok = true;
321 	if (m_proxyClientSocket->BlocksWrite()) {
322 		m_lastError = 0;
323 		m_canSend = false;
324 	} else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
325 		m_ok = false;
326 	}
327 	AddDebugLogLineN(logProxy, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes % written % m_ok % m_canSend);
328 
329 	return written;
330 }
331 
ProxyRead(CLibSocket & socket,void * buffer)332 uint32 CProxyStateMachine::ProxyRead(CLibSocket &socket, void *buffer)
333 {
334 	/* Always try to read the full buffer. That explicitly demands that
335 	 * the socket has the flag wxSOCKET_NONE. */
336 	m_lastRead = socket.Read(buffer, PROXY_BUFFER_SIZE);
337 	/* Set the status of this operation */
338 	m_ok = true;
339 	if (m_proxyClientSocket->BlocksRead()) {
340 		m_lastError = 0;
341 		m_canReceive = false;
342 	} else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
343 		m_ok = false;
344 	}
345 #ifdef ASIO_SOCKETS
346 	// We will get a new event right away if data is left, or when new data gets available.
347 	// So block for now.
348 	m_canReceive = false;
349 #endif
350 	AddDebugLogLineN(logProxy, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead % m_ok % m_canReceive);
351 
352 	return m_lastRead;
353 }
354 
CanReceive() const355 bool CProxyStateMachine::CanReceive() const
356 {
357 	return m_canReceive;
358 }
359 
CanSend() const360 bool CProxyStateMachine::CanSend() const
361 {
362 	return m_canSend;
363 }
364 
365 //------------------------------------------------------------------------------
366 // CSocks5StateMachine
367 //------------------------------------------------------------------------------
368 
369 /**
370  * The state machine constructor must initialize the array of pointer to member
371  * functions. Don't waste you time trying to statically initialize this, pointer
372  * to member functions require an object to operate on, so this array must be
373  * initialized at run time.
374  */
CSocks5StateMachine(const CProxyData & proxyData,CProxyCommand proxyCommand)375 CSocks5StateMachine::CSocks5StateMachine(
376 	const CProxyData &proxyData,
377 	CProxyCommand proxyCommand)
378 :
379 CProxyStateMachine(
380 	wxString(wxT("Socks5")), SOCKS5_MAX_STATES, proxyData, proxyCommand)
381 {
382 	m_process_state[ 0] = &CSocks5StateMachine::process_start;
383 	m_state_name[ 0]    = wxT("process_start");
384 	m_process_state[ 1] = &CSocks5StateMachine::process_end;
385 	m_state_name[ 1]    = wxT("process_end");
386 	m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
387 	m_state_name[ 2]    = wxT("process_send_query_authentication_method");
388 	m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
389 	m_state_name[ 3]    = wxT("process_receive_authentication_method");
390 	m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
391 	m_state_name[ 4]    = wxT("process_process_authentication_method");
392 	m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
393 	m_state_name[ 5]    = wxT("process_send_authentication_gssapi");
394 	m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
395 	m_state_name[ 6]    = wxT("process_receive_authentication_gssapi");
396 	m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
397 	m_state_name[ 7]    = wxT("process_process_authentication_gssapi");
398 	m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
399 	m_state_name[ 8]    = wxT("process_send_authentication_username_password");
400 	m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
401 	m_state_name[ 9]    = wxT("process_receive_authentication_username_password");
402 	m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
403 	m_state_name[10]    = wxT("process_process_authentication_username_password");
404 	m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
405 	m_state_name[11]    = wxT("process_send_command_request");
406 	m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
407 	m_state_name[12]    = wxT("process_receive_command_reply");
408 	m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
409 	m_state_name[13]    = wxT("process_process_command_reply");
410 }
411 
process_state(t_sm_state state,bool entry)412 void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
413 {
414 	/* Ok, the syntax is terrible, but this is correct. This is a
415 	 * pointer to a member function. No C equivalent for that. */
416 	(this->*m_process_state[state])(entry);
417 
418 #ifdef __DEBUG__
419 #if DEBUG_DUMP_PROXY_MSG
420 	int n = 0;
421 
422 	switch (state) {
423 	case SOCKS5_STATE_START:
424 	case SOCKS5_STATE_END:
425 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
426 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
427 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
428 	case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
429 	default:
430 		n = 0;
431 		break;
432 
433 	case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
434 	case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
435 	case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
436 	case SOCKS5_STATE_SEND_COMMAND_REQUEST:
437 		n = m_packetLenght;
438 		break;
439 
440 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
441 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
442 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
443 	case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
444 		n = m_lastRead;
445 		break;
446 	}
447 
448 	if (entry) {
449 		DumpMem(m_buffer, n, m_state_name[state], m_ok);
450 	}
451 #endif
452 	AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState());
453 #endif // __DEBUG__
454 }
455 
456 /**
457  * Code this such that the next state is only entered when it is able to
458  * perform the operation (read or write). State processing will assume
459  * that it can read or write upon entry of the state. This is done using
460  * CanSend() and CanReceive().
461  */
next_state(t_sm_event event)462 t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
463 {
464 	// Default is stay in current state
465 	t_sm_state ret = HandleEvent(event);
466 	switch (GetState()) {
467 	case SOCKS5_STATE_START:
468 		if (m_isConnected && !m_isLost && CanSend()) {
469 			ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
470 		}
471 		break;
472 
473 	case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
474 		if (CanReceive()) {
475 			ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
476 		}
477 		break;
478 
479 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
480 		ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
481 		break;
482 
483 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
484 		if (m_ok) {
485 			if (CanSend()) {
486 				switch (m_lastReply) {
487 				case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
488 					ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
489 					break;
490 
491 				case SOCKS5_AUTH_METHOD_GSSAPI:
492 					ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
493 					break;
494 
495 				case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
496 					ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
497 					break;
498 
499 				case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
500 				default:
501 					ret = SOCKS5_STATE_END;
502 					break;
503 				}
504 			} else {
505 				AddDebugLogLineN(logProxy, wxT("Can't send"));
506 			}
507 		} else {
508 			ret = SOCKS5_STATE_END;
509 		}
510 		break;
511 
512 	case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
513 		if (m_ok) {
514 			if (CanReceive()) {
515 				ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
516 			}
517 		} else {
518 			ret = SOCKS5_STATE_END;
519 		}
520 		break;
521 
522 	case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
523 		if (m_ok) {
524 			if (CanReceive()) {
525 				ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
526 			}
527 		} else {
528 			ret = SOCKS5_STATE_END;
529 		}
530 		break;
531 
532 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
533 		ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
534 		break;
535 
536 	case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
537 		ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
538 		break;
539 
540 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
541 	case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
542 		if (m_ok) {
543 			if (CanSend()) {
544 				ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
545 			}
546 		} else {
547 			ret = SOCKS5_STATE_END;
548 		}
549 		break;
550 
551 	case SOCKS5_STATE_SEND_COMMAND_REQUEST:
552 		if (m_ok) {
553 			if (CanReceive()) {
554 				ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
555 			}
556 		} else {
557 			ret = SOCKS5_STATE_END;
558 		}
559 		break;
560 
561 	case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
562 		ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
563 		break;
564 
565 	case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
566 		ret = SOCKS5_STATE_END;
567 		break;
568 
569 	case SOCKS5_STATE_END:
570 	default:
571 		break;
572 	}
573 
574 	return ret;
575 }
576 
577 /**
578  *	So, this is how you do it: the state machine is clocked by the events
579  * that happen inside the event handler. You can add a dummy event whenever
580  * you see that the system will not generate an event. But don't add dummy
581  * events before reads, reads should only be performed after input events.
582  *
583  *	Maybe it makes sense to add a dummy event before a read if there is no
584  * state change (wait state).
585  *
586  *	The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
587  * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
588  * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
589  * event will be generated. If you feel you will need more clocks than these, use
590  * AddDummyEvent(), but I suggest you review your state machine design first.
591  */
process_start(bool)592 void CSocks5StateMachine::process_start(bool)
593 {}
594 
process_end(bool)595 void CSocks5StateMachine::process_end(bool)
596 {
597 	ReactivateSocket();
598 }
599 
process_send_query_authentication_method(bool entry)600 void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
601 {
602 	if (entry) {
603 		// Prepare the authentication method negotiation packet
604 		m_buffer[0] = SOCKS5_VERSION;
605 		m_buffer[1] = 1; // Number of supported methods
606 		m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
607 		m_packetLenght = 3;
608 		if (m_proxyData.m_enablePassword) {
609 			// add SOCKS5_AUTH_METHOD_GSSAPI here if we ever implement
610 			// GSS-API authentication
611 			m_buffer[1] = 2;
612 			m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
613 			m_packetLenght = 4;
614 		}
615 
616 		// Send the authentication method negotiation packet
617 		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
618 	}
619 }
620 
process_receive_authentication_method(bool entry)621 void CSocks5StateMachine::process_receive_authentication_method(bool entry)
622 {
623 	if (entry) {
624 		// Receive the method selection message
625 		m_packetLenght = 2;
626 		ProxyRead(*m_proxyClientSocket, m_buffer);
627 	}
628 	/* This is added because there will be no more input events. If the
629 	 * world was a nice place, we could think about joining the
630 	 * process_receive and the process_process states here, but some day
631 	 * we might have to deal with the fact that the i/o operation has been
632 	 * incomplete, and that we must finish our job the next time we enter
633 	 * this state. */
634 	AddDummyEvent();
635 }
636 
process_process_authentication_method(bool entry)637 void CSocks5StateMachine::process_process_authentication_method(bool entry)
638 {
639 	if (entry) {
640 		m_lastReply = m_buffer[1];
641 		m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
642 	}
643 	/* Ok, this one is here because wxSOCKET_OUTPUT events only happen
644 	 * once when you connect the socket, and after that, only after a
645 	 * wxSOCKET_WOULDBLOCK error happens. */
646 	AddDummyEvent();
647 }
648 
process_send_authentication_gssapi(bool)649 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
650 {
651 	// TODO or not TODO? That is the question...
652 	m_ok = false;
653 }
654 
process_receive_authentication_gssapi(bool)655 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
656 {
657 	AddDummyEvent();
658 }
659 
process_process_authentication_gssapi(bool)660 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
661 {
662 	AddDummyEvent();
663 }
664 
process_send_authentication_username_password(bool entry)665 void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
666 {
667 	if (entry) {
668 		unsigned char lenUser = m_proxyData.m_userName.Len();
669 		unsigned char lenPassword = m_proxyData.m_password.Len();
670 		m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
671 		unsigned int offsetUser = 2;
672 		unsigned int offsetPassword = offsetUser + lenUser + 1;
673 
674 		// Prepare username/password buffer
675 		m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
676 		m_buffer[offsetUser-1] = lenUser;
677 		memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
678 			lenUser);
679 		m_buffer[offsetPassword-1] = lenPassword;
680 		memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
681 			lenPassword);
682 
683 		// Send the username/password packet
684 		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
685 	}
686 }
687 
process_receive_authentication_username_password(bool entry)688 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
689 {
690 	if (entry) {
691 		// Receive the server's authentication response
692 		m_packetLenght = 2;
693 		ProxyRead(*m_proxyClientSocket, m_buffer);
694 	}
695 	AddDummyEvent();
696 }
697 
process_process_authentication_username_password(bool entry)698 void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
699 {
700 	if (entry) {
701 		// Process the server's reply
702 		m_lastReply = m_buffer[1];
703 		m_ok =	m_ok &&
704 			m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
705 			m_buffer[1] == SOCKS5_REPLY_SUCCEED;
706 	}
707 	AddDummyEvent();
708 }
709 
process_send_command_request(bool entry)710 void CSocks5StateMachine::process_send_command_request(bool entry)
711 {
712 	if (entry) {
713 		// Prepare the request command buffer
714 		m_buffer[0] = SOCKS5_VERSION;
715 		switch (m_proxyCommand) {
716 		case PROXY_CMD_CONNECT:
717 			m_buffer[1] = SOCKS5_CMD_CONNECT;
718 			break;
719 
720 		case PROXY_CMD_BIND:
721 			m_buffer[1] = SOCKS5_CMD_BIND;
722 			break;
723 
724 		case PROXY_CMD_UDP_ASSOCIATE:
725 			m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
726 			break;
727 		}
728 		m_buffer[2] = SOCKS5_RSV;
729 		m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
730 		PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
731 		RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
732 
733 		// Send the command packet
734 		m_packetLenght = 10;
735 		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
736 	}
737 }
738 
process_receive_command_reply(bool entry)739 void CSocks5StateMachine::process_receive_command_reply(bool entry)
740 {
741 	if (entry) {
742 		// The minimum number of bytes to read is 10 in the case of
743 		// ATYP == SOCKS5_ATYP_IPV4_ADDRESS
744 		m_packetLenght = 10;
745 		ProxyRead(*m_proxyClientSocket, m_buffer);
746 	}
747 	AddDummyEvent();
748 }
749 
process_process_command_reply(bool entry)750 void CSocks5StateMachine::process_process_command_reply(bool entry)
751 {
752 	if (entry) {
753 		m_lastReply = m_buffer[1];
754 		unsigned char addressType = m_buffer[3];
755 		// Process the server's reply
756 		m_ok = m_ok &&
757 			m_buffer[0] == SOCKS5_VERSION &&
758 			m_buffer[1] == SOCKS5_REPLY_SUCCEED;
759 		if (m_ok) {
760 			// Read BND.ADDR
761 			unsigned int portOffset = 0;
762 			switch(addressType) {
763 			case SOCKS5_ATYP_IPV4_ADDRESS:
764 			{
765 				const unsigned int addrOffset = 4;
766 				portOffset = 8;
767 				m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
768 				m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
769 				break;
770 			}
771 			case SOCKS5_ATYP_DOMAINNAME:
772 			{
773 				// Read the domain name
774 				const unsigned int addrOffset = 5;
775 				portOffset = 10 + m_buffer[4];
776 				char c = m_buffer[portOffset];
777 				m_buffer[portOffset] = 0;
778 				m_proxyBoundAddressIPV4.Hostname(
779 					char2unicode(m_buffer+addrOffset));
780 				m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
781 				m_buffer[portOffset] = c;
782 				break;
783 			}
784 			case SOCKS5_ATYP_IPV6_ADDRESS:
785 			{
786 				portOffset = 20;
787 				// TODO
788 				// IPV6 not yet implemented in wx
789 				//m_proxyBoundAddress.Hostname(Uint128toStringIP(
790 				//	*((uint128 *)(m_buffer+addrOffset)) ));
791 				//m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
792 				m_ok = false;
793 				break;
794 			}
795 			}
796 			// Set the packet length at last
797 			m_packetLenght = portOffset + 2;
798 			// Read BND.PORT
799 			m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) ) );
800 		}
801 	}
802 	AddDummyEvent();
803 }
804 
805 //------------------------------------------------------------------------------
806 // CSocks4StateMachine
807 //------------------------------------------------------------------------------
808 
CSocks4StateMachine(const CProxyData & proxyData,CProxyCommand proxyCommand)809 CSocks4StateMachine::CSocks4StateMachine(
810 	const CProxyData &proxyData,
811 	CProxyCommand proxyCommand)
812 :
813 CProxyStateMachine(
814 	wxString(wxT("Socks4")), SOCKS4_MAX_STATES, proxyData, proxyCommand)
815 {
816 	m_process_state[0] = &CSocks4StateMachine::process_start;
817 	m_state_name[0] = wxT("process_start");
818 	m_process_state[1] = &CSocks4StateMachine::process_end;
819 	m_state_name[1] = wxT("process_end");
820 	m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
821 	m_state_name[2] = wxT("process_send_command_request");
822 	m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
823 	m_state_name[3] = wxT("process_receive_command_reply");
824 	m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
825 	m_state_name[4] = wxT("process_process_command_reply");
826 }
827 
process_state(t_sm_state state,bool entry)828 void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
829 {
830 	(this->*m_process_state[state])(entry);
831 
832 #ifdef __DEBUG__
833 #if DEBUG_DUMP_PROXY_MSG
834 	int n = 0;
835 
836 	switch (state) {
837 	case SOCKS4_STATE_START:
838 	case SOCKS4_STATE_END:
839 	case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
840 	default:
841 		n = 0;
842 		break;
843 
844 	case SOCKS4_STATE_SEND_COMMAND_REQUEST:
845 		n = m_packetLenght;
846 		break;
847 
848 	case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
849 		n = m_lastRead;
850 		break;
851 	}
852 
853 	if (entry) {
854 		DumpMem(m_buffer, n, m_state_name[state], m_ok);
855 	}
856 #endif
857 	AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState());
858 #endif // __DEBUG__
859 }
860 
next_state(t_sm_event event)861 t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
862 {
863 	// Default is stay in current state
864 	t_sm_state ret = HandleEvent(event);
865 	switch (GetState()) {
866 	case SOCKS4_STATE_START:
867 		if (m_isConnected && !m_isLost && CanSend()) {
868 			ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
869 		}
870 		break;
871 
872 	case SOCKS4_STATE_SEND_COMMAND_REQUEST:
873 		if (m_ok) {
874 			if (CanReceive()) {
875 				ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
876 			}
877 		} else {
878 			ret = SOCKS4_STATE_END;
879 		}
880 		break;
881 
882 	case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
883 		ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
884 		break;
885 
886 	case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
887 		ret = SOCKS4_STATE_END;
888 		break;
889 
890 	case SOCKS4_STATE_END:
891 	default:
892 		break;
893 	}
894 
895 	return ret;
896 }
897 
process_start(bool)898 void CSocks4StateMachine::process_start(bool)
899 {}
900 
process_end(bool)901 void CSocks4StateMachine::process_end(bool)
902 {
903 	ReactivateSocket();
904 }
905 
process_send_command_request(bool entry)906 void CSocks4StateMachine::process_send_command_request(bool entry)
907 {
908 	if (entry) {
909 		// Prepare the request command buffer
910 		m_buffer[0] = SOCKS4_VERSION;
911 		switch (m_proxyCommand) {
912 		case PROXY_CMD_CONNECT:
913 			m_buffer[1] = SOCKS4_CMD_CONNECT;
914 			break;
915 
916 		case PROXY_CMD_BIND:
917 			m_buffer[1] = SOCKS4_CMD_BIND;
918 			break;
919 
920 		case PROXY_CMD_UDP_ASSOCIATE:
921 			m_ok = false;
922 			return;
923 			break;
924 		}
925 		RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
926 		// Special processing for SOCKS4a
927 		switch (m_proxyData.m_proxyType) {
928 		case PROXY_SOCKS4a:
929 			PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
930 			break;
931 		case PROXY_SOCKS4:
932 		default:
933 			PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
934 			break;
935 		}
936 		// Common processing for SOCKS4/SOCKS4a
937 		unsigned int offsetUser = 8;
938 		unsigned char lenUser = 0;
939 		if (m_proxyData.m_enablePassword) {
940 			lenUser = m_proxyData.m_userName.Len();
941 			memcpy(m_buffer + offsetUser, unicode2char(m_proxyData.m_userName), lenUser);
942 		}
943 		m_buffer[offsetUser + lenUser] = 0;
944 		// Special processing for SOCKS4a
945 		switch (m_proxyData.m_proxyType) {
946 		case PROXY_SOCKS4a: {
947 			unsigned int offsetDomain = offsetUser + lenUser + 1;
948 			// The Hostname() method was used here before, but I don't see why we can't use
949 			// the IP address which we actually know instead here.
950 			wxString hostname(m_peerAddress->IPAddress());
951 			unsigned char lenDomain = hostname.Len();
952 			memcpy(m_buffer + offsetDomain,
953 				unicode2char(hostname), lenDomain);
954 			m_buffer[offsetDomain + lenDomain] = 0;
955 			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
956 			break;
957 		}
958 		case PROXY_SOCKS4:
959 		default:
960 			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
961 			break;
962 		}
963 		// Send the command packet
964 		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
965 	}
966 }
967 
process_receive_command_reply(bool entry)968 void CSocks4StateMachine::process_receive_command_reply(bool entry)
969 {
970 	if (entry) {
971 		// Receive the server's reply
972 		m_packetLenght = 8;
973 		ProxyRead(*m_proxyClientSocket, m_buffer);
974 	}
975 	AddDummyEvent();
976 }
977 
process_process_command_reply(bool entry)978 void CSocks4StateMachine::process_process_command_reply(bool entry)
979 {
980 	if (entry) {
981 		m_lastReply = m_buffer[1];
982 
983 		// Process the server's reply
984 		m_ok = m_ok &&
985 			m_buffer[0] == SOCKS4_REPLY_CODE &&
986 			m_buffer[1] == SOCKS4_REPLY_GRANTED;
987 		if (m_ok) {
988 			// Read BND.PORT
989 			const unsigned int portOffset = 2;
990 			m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(
991 				RawPeekUInt16( m_buffer+portOffset) ) );
992 			// Read BND.ADDR
993 			const unsigned int addrOffset = 4;
994 			m_ok = m_ok &&
995 				m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
996 			m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
997 		}
998 	}
999 	AddDummyEvent();
1000 }
1001 
1002 //------------------------------------------------------------------------------
1003 // CHttpStateMachine
1004 //------------------------------------------------------------------------------
1005 
CHttpStateMachine(const CProxyData & proxyData,CProxyCommand proxyCommand)1006 CHttpStateMachine::CHttpStateMachine(
1007 	const CProxyData &proxyData,
1008 	CProxyCommand proxyCommand)
1009 :
1010 CProxyStateMachine(
1011 	wxString(wxT("Http")), HTTP_MAX_STATES, proxyData, proxyCommand)
1012 {
1013 	m_process_state[0] = &CHttpStateMachine::process_start;
1014 	m_state_name[0] = wxT("process_start");
1015 	m_process_state[1] = &CHttpStateMachine::process_end;
1016 	m_state_name[1] = wxT("process_end");
1017 	m_process_state[2] = &CHttpStateMachine::process_send_command_request;
1018 	m_state_name[2] = wxT("process_send_command_request");
1019 	m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
1020 	m_state_name[3] = wxT("process_receive_command_reply");
1021 	m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
1022 	m_state_name[4] = wxT("process_process_command_reply");
1023 }
1024 
process_state(t_sm_state state,bool entry)1025 void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1026 {
1027 	(this->*m_process_state[state])(entry);
1028 
1029 #ifdef __DEBUG__
1030 #if DEBUG_DUMP_PROXY_MSG
1031 	int n = 0;
1032 
1033 	switch (state) {
1034 	case HTTP_STATE_START:
1035 	case HTTP_STATE_END:
1036 	case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1037 	default:
1038 		n = 0;
1039 		break;
1040 
1041 	case HTTP_STATE_SEND_COMMAND_REQUEST:
1042 		n = m_packetLenght;
1043 		break;
1044 
1045 	case HTTP_STATE_PROCESS_COMMAND_REPLY:
1046 		n = m_lastRead;
1047 		break;
1048 	}
1049 
1050 	if (entry) {
1051 		DumpMem(m_buffer, n, m_state_name[state], m_ok);
1052 	}
1053 #endif
1054 	AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState());
1055 #endif // __DEBUG__
1056 }
1057 
next_state(t_sm_event event)1058 t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1059 {
1060 	// Default is stay in current state
1061 	t_sm_state ret = HandleEvent(event);
1062 	switch (GetState()) {
1063 	case HTTP_STATE_START:
1064 		if (m_isConnected && !m_isLost && CanSend()) {
1065 			ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1066 		}
1067 		break;
1068 
1069 	case HTTP_STATE_SEND_COMMAND_REQUEST:
1070 		if (m_ok) {
1071 			if (CanReceive()) {
1072 				ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1073 			}
1074 		} else {
1075 			ret = HTTP_STATE_END;
1076 		}
1077 		break;
1078 
1079 	case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1080 		ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1081 		break;
1082 
1083 	case HTTP_STATE_PROCESS_COMMAND_REPLY:
1084 		ret = HTTP_STATE_END;
1085 		break;
1086 
1087 	case HTTP_STATE_END:
1088 	default:
1089 		break;
1090 	}
1091 
1092 	return ret;
1093 }
1094 
process_start(bool)1095 void CHttpStateMachine::process_start(bool)
1096 {}
1097 
process_end(bool)1098 void CHttpStateMachine::process_end(bool)
1099 {
1100 	ReactivateSocket();
1101 }
1102 
process_send_command_request(bool entry)1103 void CHttpStateMachine::process_send_command_request(bool entry)
1104 {
1105 	if (entry) {
1106 		// Prepare the request command buffer
1107 		wxString ip = m_peerAddress->IPAddress();
1108 		uint16 port = m_peerAddress->Service();
1109 		wxString userPass;
1110 		wxString userPassEncoded;
1111 		if (m_proxyData.m_enablePassword) {
1112 			userPass = m_proxyData.m_userName + wxT(":") + m_proxyData.m_password;
1113 			userPassEncoded =
1114 				EncodeBase64(unicode2char(userPass), userPass.Length()).Trim();
1115 		}
1116 		wxString msg;
1117 
1118 		switch (m_proxyCommand) {
1119 		case PROXY_CMD_CONNECT:
1120 			msg <<
1121 			wxT("CONNECT ") << ip << wxT(":") << port << wxT(" HTTP/1.1\r\n") <<
1122 			wxT("Host: ")   << ip << wxT(":") << port << wxT("\r\n");
1123 			if (m_proxyData.m_enablePassword) {
1124 				msg << wxT("Proxy-Authorization: Basic ") << userPassEncoded << wxT("\r\n");
1125 			}
1126 			msg << wxT("\r\n");
1127 			break;
1128 
1129 		case PROXY_CMD_BIND:
1130 			m_ok = false;
1131 			break;
1132 
1133 		case PROXY_CMD_UDP_ASSOCIATE:
1134 			m_ok = false;
1135 			return;
1136 			break;
1137 		}
1138 		// Send the command packet
1139 		m_packetLenght = msg.Len();
1140 		memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1141 		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1142 	}
1143 }
1144 
process_receive_command_reply(bool entry)1145 void CHttpStateMachine::process_receive_command_reply(bool entry)
1146 {
1147 	if (entry) {
1148 		// Receive the server's reply -- Use a large number, but don't
1149 		// Expect to get it all. HTTP protocol does not have a fixed length.
1150 		m_packetLenght = PROXY_BUFFER_SIZE;
1151 		ProxyRead(*m_proxyClientSocket, m_buffer);
1152 	}
1153 	AddDummyEvent();
1154 }
1155 
1156 /*
1157  * HTTP Proxy server response should be something like:
1158  * "HTTP/1.1 200 Connection established\r\n\r\n"
1159  * but that may vary. The important thing is the "200"
1160  * code, that means success.
1161  */
1162 static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1163 static const int  HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
process_process_command_reply(bool entry)1164 void CHttpStateMachine::process_process_command_reply(bool entry)
1165 {
1166 	if (entry) {
1167 		// The position of the first space in the buffer
1168 		int i = 8;
1169 		while (m_buffer[i] == ' ') {
1170 			i++;
1171 		}
1172 		// Process the server's reply
1173 		m_ok =	!memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1174 			!memcmp(m_buffer + i, "200", 3);
1175 	}
1176 	AddDummyEvent();
1177 }
1178 
1179 //------------------------------------------------------------------------------
1180 // CProxySocket
1181 //------------------------------------------------------------------------------
1182 
CProxySocket(muleSocketFlags flags,const CProxyData * proxyData,CProxyCommand proxyCommand,CDatagramSocketProxy * udpSocket)1183 CProxySocket::CProxySocket(
1184 	muleSocketFlags flags,
1185 	const CProxyData *proxyData,
1186 	CProxyCommand proxyCommand,
1187 	CDatagramSocketProxy *udpSocket)
1188 :
1189 CLibSocket(flags),
1190 m_proxyStateMachine(NULL),
1191 m_udpSocket(udpSocket)
1192 #ifndef ASIO_SOCKETS
1193 ,m_socketEventHandler(NULL)
1194 ,m_socketEventHandlerId(0)
1195 ,m_savedSocketEventHandler(NULL)
1196 ,m_savedSocketEventHandlerId(0)
1197 #endif
1198 {
1199 	SetProxyData(proxyData);
1200 	if (m_useProxy) {
1201 		switch (m_proxyData.m_proxyType) {
1202 		case PROXY_NONE:
1203 			break;
1204 
1205 		case PROXY_SOCKS5:
1206 			m_proxyStateMachine =
1207 				new CSocks5StateMachine(*proxyData, proxyCommand);
1208 			break;
1209 
1210 		case PROXY_SOCKS4:
1211 		case PROXY_SOCKS4a:
1212 			m_proxyStateMachine =
1213 				new CSocks4StateMachine(*proxyData, proxyCommand);
1214 			break;
1215 
1216 		case PROXY_HTTP:
1217 			m_proxyStateMachine =
1218 				new CHttpStateMachine(*proxyData, proxyCommand);
1219 			break;
1220 
1221 		default:
1222 			break;
1223 		}
1224 	}
1225 }
1226 
~CProxySocket()1227 CProxySocket::~CProxySocket()
1228 {
1229 	delete m_proxyStateMachine;
1230 }
1231 
SetProxyData(const CProxyData * proxyData)1232 void CProxySocket::SetProxyData(const CProxyData *proxyData)
1233 {
1234 	m_useProxy = proxyData != NULL && proxyData->m_proxyEnable;
1235 	if (proxyData) {
1236 		m_proxyData = *proxyData;
1237 		m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1238 		m_proxyAddress.Service(m_proxyData.m_proxyPort);
1239 	} else {
1240 		m_proxyData.Clear();
1241 	}
1242 }
1243 
Start(const amuleIPV4Address & peerAddress)1244 bool CProxySocket::Start(const amuleIPV4Address &peerAddress)
1245 {
1246 #ifdef ASIO_SOCKETS
1247 	SetProxyState(true, &peerAddress);
1248 #else
1249 	SaveState();
1250 	// Important note! SaveState()/RestoreState() DO NOT save/restore
1251 	// the event handler. The method SaveEventHandler() has been created
1252 	// for that.
1253 	SaveEventHandler();
1254 	SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1255 	SetNotify(
1256 		wxSOCKET_CONNECTION_FLAG |
1257 		wxSOCKET_INPUT_FLAG |
1258 		wxSOCKET_OUTPUT_FLAG |
1259 		wxSOCKET_LOST_FLAG);
1260 	Notify(true);
1261 #endif
1262 	Connect(m_proxyAddress, false);
1263 	SetFlags(MULE_SOCKET_NONE);
1264 	return m_proxyStateMachine->Start(peerAddress, this);
1265 }
1266 
ProxyIsCapableOf(CProxyCommand proxyCommand) const1267 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1268 {
1269 	bool ret = false;
1270 
1271 	switch (m_proxyData.m_proxyType) {
1272 	case PROXY_NONE:
1273 		ret = false;
1274 		break;
1275 
1276 	case PROXY_SOCKS5:
1277 		ret =	proxyCommand == PROXY_CMD_CONNECT ||
1278 			proxyCommand == PROXY_CMD_BIND ||
1279 			proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1280 		break;
1281 
1282 	case PROXY_SOCKS4:
1283 	case PROXY_SOCKS4a:
1284 		ret =	proxyCommand == PROXY_CMD_CONNECT ||
1285 			proxyCommand == PROXY_CMD_BIND;
1286 		break;
1287 
1288 	case PROXY_HTTP:
1289 		ret =	proxyCommand == PROXY_CMD_CONNECT;
1290 		break;
1291 	}
1292 
1293 	return ret;
1294 }
1295 
1296 //------------------------------------------------------------------------------
1297 // CSocketClientProxy
1298 //------------------------------------------------------------------------------
1299 
CSocketClientProxy(muleSocketFlags flags,const CProxyData * proxyData)1300 CSocketClientProxy::CSocketClientProxy(
1301 	muleSocketFlags flags,
1302 	const CProxyData *proxyData)
1303 :
1304 CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1305 {
1306 }
1307 
Connect(amuleIPV4Address & address,bool wait)1308 bool CSocketClientProxy::Connect(amuleIPV4Address &address, bool wait)
1309 {
1310 	wxMutexLocker lock(m_socketLocker);
1311 	bool ok;
1312 
1313 	if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1314 		ok = Start(address);
1315 	} else {
1316 		ok = CLibSocket::Connect(address, wait);
1317 	}
1318 
1319 	return ok;
1320 }
1321 
Read(void * buffer,wxUint32 nbytes)1322 uint32 CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1323 {
1324 	wxMutexLocker lock(m_socketLocker);
1325 	return CProxySocket::Read(buffer, nbytes);
1326 }
1327 
Write(const void * buffer,wxUint32 nbytes)1328 uint32 CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1329 {
1330 	wxMutexLocker lock(m_socketLocker);
1331 	return CProxySocket::Write(buffer, nbytes);
1332 }
1333 
1334 //------------------------------------------------------------------------------
1335 // CSocketServerProxy
1336 //------------------------------------------------------------------------------
1337 
CSocketServerProxy(amuleIPV4Address & address,muleSocketFlags flags,const CProxyData *)1338 CSocketServerProxy::CSocketServerProxy(
1339 	amuleIPV4Address &address,
1340 	muleSocketFlags flags,
1341 	const CProxyData *)
1342 :
1343 CLibSocketServer(address, flags)
1344 {
1345 	/* Maybe some day when socks6 is out... :) */
1346 }
1347 
1348 //------------------------------------------------------------------------------
1349 // CDatagramSocketProxy
1350 //------------------------------------------------------------------------------
1351 
CDatagramSocketProxy(amuleIPV4Address & address,muleSocketFlags flags,const CProxyData * proxyData)1352 CDatagramSocketProxy::CDatagramSocketProxy(
1353 	amuleIPV4Address &address, muleSocketFlags flags, const CProxyData *proxyData)
1354 :
1355 CLibUDPSocket(address, flags),
1356 m_proxyTCPSocket(MULE_SOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1357 {
1358 	m_udpSocketOk = false;
1359 	if (	m_proxyTCPSocket.GetUseProxy() &&
1360 		m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1361 			m_proxyTCPSocket.Start(address);
1362 	} else {
1363 	}
1364 	m_lastUDPOperation = UDP_OPERATION_NONE;
1365 }
1366 
~CDatagramSocketProxy()1367 CDatagramSocketProxy::~CDatagramSocketProxy()
1368 {
1369 	// From RFC-1928:
1370 	// "A UDP association terminates when the TCP connection that the
1371 	// UDP ASSOCIATE request arrived terminates."
1372 }
1373 
RecvFrom(amuleIPV4Address & addr,void * buf,uint32 nBytes)1374 uint32 CDatagramSocketProxy::RecvFrom(amuleIPV4Address& addr, void* buf, uint32 nBytes)
1375 {
1376 	uint32 read = 0;
1377 	wxMutexLocker lock(m_socketLocker);
1378 	m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1379 	if (m_proxyTCPSocket.GetUseProxy()) {
1380 		if (m_udpSocketOk) {
1381 			char *bufUDP = NULL;
1382 			if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1383 				bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1384 			} else {
1385 				bufUDP = m_proxyTCPSocket.GetBuffer();
1386 			}
1387 			read = CLibUDPSocket::RecvFrom(
1388 				m_proxyTCPSocket.GetProxyBoundAddress(),
1389 				bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1390 			unsigned int offset;
1391 			switch (m_proxyTCPSocket.GetBuffer()[3]) {
1392 			case SOCKS5_ATYP_IPV4_ADDRESS: {
1393 				offset = PROXY_UDP_OVERHEAD_IPV4;
1394 				try {
1395 					amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1396 					a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1397 					a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) ) );
1398 				} catch (const std::bad_cast& WXUNUSED(e)) {
1399 					AddDebugLogLineN(logProxy,
1400 						wxT("(2)bad_cast exception!"));
1401 					wxFAIL;
1402 				}
1403 			}
1404 				break;
1405 
1406 			case SOCKS5_ATYP_DOMAINNAME:
1407 				offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1408 				break;
1409 
1410 			case SOCKS5_ATYP_IPV6_ADDRESS:
1411 				offset = PROXY_UDP_OVERHEAD_IPV6;
1412 				break;
1413 
1414 			default:
1415 				/* Error! */
1416 				offset = 0;
1417 				break;
1418 			}
1419 			memcpy(buf, bufUDP + offset, nBytes);
1420 			// Uncomment here to see the buffer contents on console
1421 			// DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1422 
1423 			/* Only delete buffer if it was dynamically created */
1424 			if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1425 				/* We should use a fixed buffer to avoid
1426 				 * new/delete it all the time.
1427 				 * I need an upper bound */
1428 				delete [] bufUDP;
1429 			}
1430 			/* There is still one problem pending, fragmentation.
1431 			 * Either we support it or we have to drop fragmented
1432 			 * messages. I vote for drop :)
1433 			 */
1434 		}
1435 	} else {
1436 		read = CLibUDPSocket::RecvFrom(addr, buf, nBytes);
1437 	}
1438 
1439 	return read;
1440 }
1441 
SendTo(const amuleIPV4Address & addr,const void * buf,uint32 nBytes)1442 uint32 CDatagramSocketProxy::SendTo(const amuleIPV4Address& addr, const void* buf, uint32 nBytes)
1443 {
1444 	uint32 sent = 0;
1445 	wxMutexLocker lock(m_socketLocker);
1446 	m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1447 	m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1448 	if (m_proxyTCPSocket.GetUseProxy()) {
1449 		if (m_udpSocketOk) {
1450 			m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV;	// Reserved
1451 			m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV;	// Reserved
1452 			m_proxyTCPSocket.GetBuffer()[2] = 0;		// FRAG
1453 			m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1454 			PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1455 			RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
1456 			memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1457 			nBytes += PROXY_UDP_OVERHEAD_IPV4;
1458 			sent = CLibUDPSocket::SendTo(
1459 				m_proxyTCPSocket.GetProxyBoundAddress(),
1460 				m_proxyTCPSocket.GetBuffer(), nBytes);
1461 			// Uncomment here to see the buffer contents on console
1462 			// DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1463 		}
1464 	} else {
1465 		sent = CLibUDPSocket::SendTo(addr, buf, nBytes);
1466 	}
1467 
1468 	return sent;
1469 }
1470 
1471 #endif // CLIENT_GUI
1472 
1473 /******************************************************************************/
1474 // File_checked_for_headers
1475