2 // This file is part of the aMule Project.
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 )
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
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.
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.
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
26 #include "Proxy.h" /* for Interface */
28 #include <common/EventIDs.h>
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"
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
44 //------------------------------------------------------------------------------
46 //------------------------------------------------------------------------------
48 CProxyData::CProxyData()
53 CProxyData::CProxyData(
56 const wxString
&proxyHostName
,
57 unsigned short proxyPort
,
59 const wxString
&userName
,
60 const wxString
&password
)
62 m_proxyEnable(proxyEnable
),
63 m_proxyType(proxyType
),
64 m_proxyHostName(proxyHostName
),
65 m_proxyPort(proxyPort
),
66 m_enablePassword(enablePassword
),
72 void CProxyData::Clear()
74 m_proxyEnable
= false;
75 m_proxyType
= PROXY_NONE
;
76 m_proxyHostName
.Clear();
78 m_enablePassword
= false;
85 #include <typeinfo> // Do_not_auto_remove (NetBSD, older gccs)
89 //------------------------------------------------------------------------------
91 //------------------------------------------------------------------------------
93 CProxyEventHandler::CProxyEventHandler()
97 BEGIN_EVENT_TABLE(CProxyEventHandler
, wxEvtHandler
)
98 EVT_SOCKET(ID_PROXY_SOCKET_EVENT
, CProxyEventHandler::ProxySocketHandler
)
102 // THE one and only Event Handler
104 static CProxyEventHandler g_proxyEventHandler
;
106 void CProxyEventHandler::ProxySocketHandler(wxSocketEvent
& event
)
108 CProxySocket
*sock
= dynamic_cast<CProxySocket
*>(event
.GetSocket());
110 sock
->m_proxyStateMachine
->Schedule(event
.GetSocketEvent());
111 sock
->m_proxyStateMachine
->Clock();
120 // In Asio mode the event handler is:
122 void CProxySocket::OnProxyEvent(int evt
)
124 m_proxyStateMachine
->Schedule(evt
);
125 m_proxyStateMachine
->Clock();
130 //------------------------------------------------------------------------------
131 // CProxyStateMachine
132 //------------------------------------------------------------------------------
134 CProxyStateMachine::CProxyStateMachine(
136 const unsigned int max_states
,
137 const CProxyData
&proxyData
,
138 CProxyCommand proxyCommand
)
140 CStateMachine(NewName(name
, proxyCommand
), max_states
, PROXY_STATE_START
),
141 m_proxyData(proxyData
),
142 m_proxyCommand(proxyCommand
),
144 m_isConnected(false),
149 // Will be initialized at Start()
151 m_proxyClientSocket(NULL
),
152 m_proxyBoundAddress(NULL
),
153 // Temporary variables
159 CProxyStateMachine::~CProxyStateMachine()
161 delete m_peerAddress
;
164 wxString
&CProxyStateMachine::NewName(wxString
&s
, CProxyCommand proxyCommand
)
166 switch (proxyCommand
) {
167 case PROXY_CMD_CONNECT
:
168 s
+= wxT("-CONNECT");
175 case PROXY_CMD_UDP_ASSOCIATE
:
183 bool CProxyStateMachine::Start(const amuleIPV4Address
&peerAddress
, CLibSocket
*proxyClientSocket
)
185 m_proxyClientSocket
= proxyClientSocket
;
186 m_peerAddress
= new amuleIPV4Address(peerAddress
);
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!"));
197 // To run the state machine, return and just let the events start to happen.
201 static const int MULE_SOCKET_DUMMY_VALUE
= MULE_SOCKET_INPUT
+ MULE_SOCKET_OUTPUT
+ MULE_SOCKET_CONNECTION
+ MULE_SOCKET_LOST
;
203 t_sm_state
CProxyStateMachine::HandleEvent(t_sm_event event
)
205 // Default is stay in current state
206 t_sm_state ret
= GetState();
209 case MULE_SOCKET_CONNECTION
:
210 AddDebugLogLineN(logProxy
, wxT("Connection event"));
211 m_isConnected
= true;
214 case MULE_SOCKET_INPUT
:
215 AddDebugLogLineN(logProxy
, wxT("Input event"));
219 case MULE_SOCKET_OUTPUT
:
220 AddDebugLogLineN(logProxy
, wxT("Output event"));
224 case MULE_SOCKET_LOST
:
225 AddDebugLogLineN(logProxy
, wxT("Lost connection event"));
230 case MULE_SOCKET_DUMMY_VALUE
:
231 AddDebugLogLineN(logProxy
, wxT("Dummy event"));
235 AddDebugLogLineN(logProxy
, CFormat(wxT("Unknown event %d")) % event
);
239 // Aborting conditions:
240 // - MULE_SOCKET_LOST event
241 // - More than 10 times on the same state
243 GetClocksInCurrentState() > 10) {
244 ret
= PROXY_STATE_END
;
250 void CProxyStateMachine::AddDummyEvent()
253 CProxySocket
*s
= dynamic_cast<CProxySocket
*>(m_proxyClientSocket
);
254 if (s
) { // should always be
255 CoreNotify_ProxySocketEvent(s
, MULE_SOCKET_DUMMY_VALUE
);
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
);
266 void CProxyStateMachine::ReactivateSocket()
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...
277 if (CDatagramSocketProxy
*udp
= s
->GetUDPSocket()) {
278 // The original socket was a UDP socket
280 // From now on, the UDP socket can be used,
281 // remove the protection.
282 udp
->SetUDPSocketOk();
284 // No need to call RestoreState(), that socket will no longer
285 // be used after proxy negotiation.
287 // The original socket was a TCP socket
289 if (s
->GetProxyState()) { // somehow this gets called twice ?
290 s
->SetProxyState(false);
291 CoreNotify_LibSocketConnect(s
, 0);
293 CoreNotify_LibSocketSend(s
, 0);
295 CoreNotify_LibSocketLost(s
);
299 s
->RestoreEventHandler();
300 wxSocketEvent
e(s
->GetEventHandlerId());
301 e
.m_event
= wxSOCKET_CONNECTION
;
303 wxEvtHandler
*h(s
->GetEventHandler());
304 h
->AddPendingEvent(e
);
305 e
.m_event
= wxSOCKET_OUTPUT
;
306 h
->AddPendingEvent(e
);
308 e
.m_event
= wxSOCKET_LOST
;
309 h
->AddPendingEvent(e
);
316 uint32
CProxyStateMachine::ProxyWrite(CLibSocket
&socket
, const void *buffer
, wxUint32 nbytes
)
318 uint32 written
= socket
.Write(buffer
, nbytes
);
319 /* Set the status of this operation */
321 if (m_proxyClientSocket
->BlocksWrite()) {
324 } else if ((m_lastError
= m_proxyClientSocket
->LastError()) != 0) {
327 AddDebugLogLineN(logProxy
, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes
% written
% m_ok
% m_canSend
);
332 uint32
CProxyStateMachine::ProxyRead(CLibSocket
&socket
, void *buffer
)
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 */
339 if (m_proxyClientSocket
->BlocksRead()) {
341 #ifndef ASIO_SOCKETS // m_canReceive is already assigned later
342 m_canReceive
= false;
344 } else if ((m_lastError
= m_proxyClientSocket
->LastError()) != 0) {
348 // We will get a new event right away if data is left, or when new data gets available.
350 m_canReceive
= false;
352 AddDebugLogLineN(logProxy
, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead
% m_ok
% m_canReceive
);
357 bool CProxyStateMachine::CanReceive() const
362 bool CProxyStateMachine::CanSend() const
367 //------------------------------------------------------------------------------
368 // CSocks5StateMachine
369 //------------------------------------------------------------------------------
372 * The state machine constructor must initialize the array of pointer to member
373 * functions. Don't waste you time trying to statically initialize this, pointer
374 * to member functions require an object to operate on, so this array must be
375 * initialized at run time.
377 CSocks5StateMachine::CSocks5StateMachine(
378 const CProxyData
&proxyData
,
379 CProxyCommand proxyCommand
)
382 wxString(wxT("Socks5")), SOCKS5_MAX_STATES
, proxyData
, proxyCommand
)
384 m_process_state
[ 0] = &CSocks5StateMachine::process_start
;
385 m_state_name
[ 0] = wxT("process_start");
386 m_process_state
[ 1] = &CSocks5StateMachine::process_end
;
387 m_state_name
[ 1] = wxT("process_end");
388 m_process_state
[ 2] = &CSocks5StateMachine::process_send_query_authentication_method
;
389 m_state_name
[ 2] = wxT("process_send_query_authentication_method");
390 m_process_state
[ 3] = &CSocks5StateMachine::process_receive_authentication_method
;
391 m_state_name
[ 3] = wxT("process_receive_authentication_method");
392 m_process_state
[ 4] = &CSocks5StateMachine::process_process_authentication_method
;
393 m_state_name
[ 4] = wxT("process_process_authentication_method");
394 m_process_state
[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi
;
395 m_state_name
[ 5] = wxT("process_send_authentication_gssapi");
396 m_process_state
[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi
;
397 m_state_name
[ 6] = wxT("process_receive_authentication_gssapi");
398 m_process_state
[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi
;
399 m_state_name
[ 7] = wxT("process_process_authentication_gssapi");
400 m_process_state
[ 8] = &CSocks5StateMachine::process_send_authentication_username_password
;
401 m_state_name
[ 8] = wxT("process_send_authentication_username_password");
402 m_process_state
[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password
;
403 m_state_name
[ 9] = wxT("process_receive_authentication_username_password");
404 m_process_state
[10] = &CSocks5StateMachine::process_process_authentication_username_password
;
405 m_state_name
[10] = wxT("process_process_authentication_username_password");
406 m_process_state
[11] = &CSocks5StateMachine::process_send_command_request
;
407 m_state_name
[11] = wxT("process_send_command_request");
408 m_process_state
[12] = &CSocks5StateMachine::process_receive_command_reply
;
409 m_state_name
[12] = wxT("process_receive_command_reply");
410 m_process_state
[13] = &CSocks5StateMachine::process_process_command_reply
;
411 m_state_name
[13] = wxT("process_process_command_reply");
414 void CSocks5StateMachine::process_state(t_sm_state state
, bool entry
)
416 /* Ok, the syntax is terrible, but this is correct. This is a
417 * pointer to a member function. No C equivalent for that. */
418 (this->*m_process_state
[state
])(entry
);
421 #if DEBUG_DUMP_PROXY_MSG
425 case SOCKS5_STATE_START
:
426 case SOCKS5_STATE_END
:
427 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
428 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
429 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
430 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
435 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
436 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
437 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
438 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
442 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
443 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
444 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
445 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
451 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
454 AddDebugLogLineN(logProxy
, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name
[state
] % GetClocksInCurrentState());
459 * Code this such that the next state is only entered when it is able to
460 * perform the operation (read or write). State processing will assume
461 * that it can read or write upon entry of the state. This is done using
462 * CanSend() and CanReceive().
464 t_sm_state
CSocks5StateMachine::next_state(t_sm_event event
)
466 // Default is stay in current state
467 t_sm_state ret
= HandleEvent(event
);
468 switch (GetState()) {
469 case SOCKS5_STATE_START
:
470 if (m_isConnected
&& !m_isLost
&& CanSend()) {
471 ret
= SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
;
475 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
477 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
;
481 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
482 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
;
485 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
488 switch (m_lastReply
) {
489 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
:
490 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
493 case SOCKS5_AUTH_METHOD_GSSAPI
:
494 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
;
497 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
:
498 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
;
501 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS
:
503 ret
= SOCKS5_STATE_END
;
507 AddDebugLogLineN(logProxy
, wxT("Can't send"));
510 ret
= SOCKS5_STATE_END
;
514 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
517 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
;
520 ret
= SOCKS5_STATE_END
;
524 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
527 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
;
530 ret
= SOCKS5_STATE_END
;
534 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
535 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
;
538 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
539 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
;
542 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
543 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
546 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
549 ret
= SOCKS5_STATE_END
;
553 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
556 ret
= SOCKS5_STATE_RECEIVE_COMMAND_REPLY
;
559 ret
= SOCKS5_STATE_END
;
563 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
564 ret
= SOCKS5_STATE_PROCESS_COMMAND_REPLY
;
567 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
568 ret
= SOCKS5_STATE_END
;
571 case SOCKS5_STATE_END
:
580 * So, this is how you do it: the state machine is clocked by the events
581 * that happen inside the event handler. You can add a dummy event whenever
582 * you see that the system will not generate an event. But don't add dummy
583 * events before reads, reads should only be performed after input events.
585 * Maybe it makes sense to add a dummy event before a read if there is no
586 * state change (wait state).
588 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
589 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
590 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
591 * event will be generated. If you feel you will need more clocks than these, use
592 * AddDummyEvent(), but I suggest you review your state machine design first.
594 void CSocks5StateMachine::process_start(bool)
597 void CSocks5StateMachine::process_end(bool)
602 void CSocks5StateMachine::process_send_query_authentication_method(bool entry
)
605 // Prepare the authentication method negotiation packet
606 m_buffer
[0] = SOCKS5_VERSION
;
607 m_buffer
[1] = 1; // Number of supported methods
608 m_buffer
[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
;
610 if (m_proxyData
.m_enablePassword
) {
611 // add SOCKS5_AUTH_METHOD_GSSAPI here if we ever implement
612 // GSS-API authentication
614 m_buffer
[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
;
618 // Send the authentication method negotiation packet
619 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
623 void CSocks5StateMachine::process_receive_authentication_method(bool entry
)
626 // Receive the method selection message
628 ProxyRead(*m_proxyClientSocket
, m_buffer
);
630 /* This is added because there will be no more input events. If the
631 * world was a nice place, we could think about joining the
632 * process_receive and the process_process states here, but some day
633 * we might have to deal with the fact that the i/o operation has been
634 * incomplete, and that we must finish our job the next time we enter
639 void CSocks5StateMachine::process_process_authentication_method(bool entry
)
642 m_lastReply
= m_buffer
[1];
643 m_ok
= m_ok
&& m_buffer
[0] == SOCKS5_VERSION
;
645 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
646 * once when you connect the socket, and after that, only after a
647 * wxSOCKET_WOULDBLOCK error happens. */
651 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
653 // TODO or not TODO? That is the question...
657 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
662 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
667 void CSocks5StateMachine::process_send_authentication_username_password(bool entry
)
670 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
671 unsigned char lenPassword
= m_proxyData
.m_password
.Len();
672 m_packetLenght
= 1 + 1 + lenUser
+ 1 + lenPassword
;
673 unsigned int offsetUser
= 2;
674 unsigned int offsetPassword
= offsetUser
+ lenUser
+ 1;
676 // Prepare username/password buffer
677 m_buffer
[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
;
678 m_buffer
[offsetUser
-1] = lenUser
;
679 memcpy(m_buffer
+offsetUser
, unicode2char(m_proxyData
.m_userName
),
681 m_buffer
[offsetPassword
-1] = lenPassword
;
682 memcpy(m_buffer
+offsetPassword
, unicode2char(m_proxyData
.m_password
),
685 // Send the username/password packet
686 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
690 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry
)
693 // Receive the server's authentication response
695 ProxyRead(*m_proxyClientSocket
, m_buffer
);
700 void CSocks5StateMachine::process_process_authentication_username_password(bool entry
)
703 // Process the server's reply
704 m_lastReply
= m_buffer
[1];
706 m_buffer
[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
&&
707 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
712 void CSocks5StateMachine::process_send_command_request(bool entry
)
715 // Prepare the request command buffer
716 m_buffer
[0] = SOCKS5_VERSION
;
717 switch (m_proxyCommand
) {
718 case PROXY_CMD_CONNECT
:
719 m_buffer
[1] = SOCKS5_CMD_CONNECT
;
723 m_buffer
[1] = SOCKS5_CMD_BIND
;
726 case PROXY_CMD_UDP_ASSOCIATE
:
727 m_buffer
[1] = SOCKS5_CMD_UDP_ASSOCIATE
;
730 m_buffer
[2] = SOCKS5_RSV
;
731 m_buffer
[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
732 PokeUInt32( m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()) );
733 RawPokeUInt16( m_buffer
+8, ENDIAN_HTONS( m_peerAddress
->Service() ) );
735 // Send the command packet
737 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
741 void CSocks5StateMachine::process_receive_command_reply(bool entry
)
744 // The minimum number of bytes to read is 10 in the case of
745 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
747 ProxyRead(*m_proxyClientSocket
, m_buffer
);
752 void CSocks5StateMachine::process_process_command_reply(bool entry
)
755 m_lastReply
= m_buffer
[1];
756 unsigned char addressType
= m_buffer
[3];
757 // Process the server's reply
759 m_buffer
[0] == SOCKS5_VERSION
&&
760 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
763 unsigned int portOffset
= 0;
764 switch(addressType
) {
765 case SOCKS5_ATYP_IPV4_ADDRESS
:
767 const unsigned int addrOffset
= 4;
769 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
770 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
773 case SOCKS5_ATYP_DOMAINNAME
:
775 // Read the domain name
776 const unsigned int addrOffset
= 5;
777 portOffset
= 10 + m_buffer
[4];
778 char c
= m_buffer
[portOffset
];
779 m_buffer
[portOffset
] = 0;
780 m_proxyBoundAddressIPV4
.Hostname(
781 char2unicode(m_buffer
+addrOffset
));
782 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
783 m_buffer
[portOffset
] = c
;
786 case SOCKS5_ATYP_IPV6_ADDRESS
:
790 // IPV6 not yet implemented in wx
791 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
792 // *((uint128 *)(m_buffer+addrOffset)) ));
793 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
798 // Set the packet length at last
799 m_packetLenght
= portOffset
+ 2;
801 m_proxyBoundAddress
->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer
+portOffset
) ) );
807 //------------------------------------------------------------------------------
808 // CSocks4StateMachine
809 //------------------------------------------------------------------------------
811 CSocks4StateMachine::CSocks4StateMachine(
812 const CProxyData
&proxyData
,
813 CProxyCommand proxyCommand
)
816 wxString(wxT("Socks4")), SOCKS4_MAX_STATES
, proxyData
, proxyCommand
)
818 m_process_state
[0] = &CSocks4StateMachine::process_start
;
819 m_state_name
[0] = wxT("process_start");
820 m_process_state
[1] = &CSocks4StateMachine::process_end
;
821 m_state_name
[1] = wxT("process_end");
822 m_process_state
[2] = &CSocks4StateMachine::process_send_command_request
;
823 m_state_name
[2] = wxT("process_send_command_request");
824 m_process_state
[3] = &CSocks4StateMachine::process_receive_command_reply
;
825 m_state_name
[3] = wxT("process_receive_command_reply");
826 m_process_state
[4] = &CSocks4StateMachine::process_process_command_reply
;
827 m_state_name
[4] = wxT("process_process_command_reply");
830 void CSocks4StateMachine::process_state(t_sm_state state
, bool entry
)
832 (this->*m_process_state
[state
])(entry
);
835 #if DEBUG_DUMP_PROXY_MSG
839 case SOCKS4_STATE_START
:
840 case SOCKS4_STATE_END
:
841 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
846 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
850 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
856 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
859 AddDebugLogLineN(logProxy
, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name
[state
] % GetClocksInCurrentState());
863 t_sm_state
CSocks4StateMachine::next_state(t_sm_event event
)
865 // Default is stay in current state
866 t_sm_state ret
= HandleEvent(event
);
867 switch (GetState()) {
868 case SOCKS4_STATE_START
:
869 if (m_isConnected
&& !m_isLost
&& CanSend()) {
870 ret
= SOCKS4_STATE_SEND_COMMAND_REQUEST
;
874 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
877 ret
= SOCKS4_STATE_RECEIVE_COMMAND_REPLY
;
880 ret
= SOCKS4_STATE_END
;
884 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
885 ret
= SOCKS4_STATE_PROCESS_COMMAND_REPLY
;
888 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
889 ret
= SOCKS4_STATE_END
;
892 case SOCKS4_STATE_END
:
900 void CSocks4StateMachine::process_start(bool)
903 void CSocks4StateMachine::process_end(bool)
908 void CSocks4StateMachine::process_send_command_request(bool entry
)
911 // Prepare the request command buffer
912 m_buffer
[0] = SOCKS4_VERSION
;
913 switch (m_proxyCommand
) {
914 case PROXY_CMD_CONNECT
:
915 m_buffer
[1] = SOCKS4_CMD_CONNECT
;
919 m_buffer
[1] = SOCKS4_CMD_BIND
;
922 case PROXY_CMD_UDP_ASSOCIATE
:
927 RawPokeUInt16(m_buffer
+2, ENDIAN_HTONS(m_peerAddress
->Service()));
928 // Special processing for SOCKS4a
929 switch (m_proxyData
.m_proxyType
) {
931 PokeUInt32(m_buffer
+4, StringIPtoUint32(wxT("0.0.0.1")));
935 PokeUInt32(m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()));
938 // Common processing for SOCKS4/SOCKS4a
939 unsigned int offsetUser
= 8;
940 unsigned char lenUser
= 0;
941 if (m_proxyData
.m_enablePassword
) {
942 lenUser
= m_proxyData
.m_userName
.Len();
943 memcpy(m_buffer
+ offsetUser
, unicode2char(m_proxyData
.m_userName
), lenUser
);
945 m_buffer
[offsetUser
+ lenUser
] = 0;
946 // Special processing for SOCKS4a
947 switch (m_proxyData
.m_proxyType
) {
948 case PROXY_SOCKS4a
: {
949 unsigned int offsetDomain
= offsetUser
+ lenUser
+ 1;
950 // The Hostname() method was used here before, but I don't see why we can't use
951 // the IP address which we actually know instead here.
952 wxString
hostname(m_peerAddress
->IPAddress());
953 unsigned char lenDomain
= hostname
.Len();
954 memcpy(m_buffer
+ offsetDomain
,
955 unicode2char(hostname
), lenDomain
);
956 m_buffer
[offsetDomain
+ lenDomain
] = 0;
957 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1 + lenDomain
+ 1;
962 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1;
965 // Send the command packet
966 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
970 void CSocks4StateMachine::process_receive_command_reply(bool entry
)
973 // Receive the server's reply
975 ProxyRead(*m_proxyClientSocket
, m_buffer
);
980 void CSocks4StateMachine::process_process_command_reply(bool entry
)
983 m_lastReply
= m_buffer
[1];
985 // Process the server's reply
987 m_buffer
[0] == SOCKS4_REPLY_CODE
&&
988 m_buffer
[1] == SOCKS4_REPLY_GRANTED
;
991 const unsigned int portOffset
= 2;
992 m_ok
= m_proxyBoundAddressIPV4
.Service(ENDIAN_NTOHS(
993 RawPeekUInt16( m_buffer
+portOffset
) ) );
995 const unsigned int addrOffset
= 4;
997 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
998 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
1004 //------------------------------------------------------------------------------
1005 // CHttpStateMachine
1006 //------------------------------------------------------------------------------
1008 CHttpStateMachine::CHttpStateMachine(
1009 const CProxyData
&proxyData
,
1010 CProxyCommand proxyCommand
)
1013 wxString(wxT("Http")), HTTP_MAX_STATES
, proxyData
, proxyCommand
)
1015 m_process_state
[0] = &CHttpStateMachine::process_start
;
1016 m_state_name
[0] = wxT("process_start");
1017 m_process_state
[1] = &CHttpStateMachine::process_end
;
1018 m_state_name
[1] = wxT("process_end");
1019 m_process_state
[2] = &CHttpStateMachine::process_send_command_request
;
1020 m_state_name
[2] = wxT("process_send_command_request");
1021 m_process_state
[3] = &CHttpStateMachine::process_receive_command_reply
;
1022 m_state_name
[3] = wxT("process_receive_command_reply");
1023 m_process_state
[4] = &CHttpStateMachine::process_process_command_reply
;
1024 m_state_name
[4] = wxT("process_process_command_reply");
1027 void CHttpStateMachine::process_state(t_sm_state state
, bool entry
)
1029 (this->*m_process_state
[state
])(entry
);
1032 #if DEBUG_DUMP_PROXY_MSG
1036 case HTTP_STATE_START
:
1037 case HTTP_STATE_END
:
1038 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1043 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1047 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1053 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
1056 AddDebugLogLineN(logProxy
, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name
[state
] % GetClocksInCurrentState());
1060 t_sm_state
CHttpStateMachine::next_state(t_sm_event event
)
1062 // Default is stay in current state
1063 t_sm_state ret
= HandleEvent(event
);
1064 switch (GetState()) {
1065 case HTTP_STATE_START
:
1066 if (m_isConnected
&& !m_isLost
&& CanSend()) {
1067 ret
= HTTP_STATE_SEND_COMMAND_REQUEST
;
1071 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1074 ret
= HTTP_STATE_RECEIVE_COMMAND_REPLY
;
1077 ret
= HTTP_STATE_END
;
1081 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1082 ret
= HTTP_STATE_PROCESS_COMMAND_REPLY
;
1085 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1086 ret
= HTTP_STATE_END
;
1089 case HTTP_STATE_END
:
1097 void CHttpStateMachine::process_start(bool)
1100 void CHttpStateMachine::process_end(bool)
1105 void CHttpStateMachine::process_send_command_request(bool entry
)
1108 // Prepare the request command buffer
1109 wxString ip
= m_peerAddress
->IPAddress();
1110 uint16 port
= m_peerAddress
->Service();
1112 wxString userPassEncoded
;
1113 if (m_proxyData
.m_enablePassword
) {
1114 userPass
= m_proxyData
.m_userName
+ wxT(":") + m_proxyData
.m_password
;
1116 EncodeBase64(unicode2char(userPass
), userPass
.Length()).Trim();
1120 switch (m_proxyCommand
) {
1121 case PROXY_CMD_CONNECT
:
1123 wxT("CONNECT ") << ip
<< wxT(":") << port
<< wxT(" HTTP/1.1\r\n") <<
1124 wxT("Host: ") << ip
<< wxT(":") << port
<< wxT("\r\n");
1125 if (m_proxyData
.m_enablePassword
) {
1126 msg
<< wxT("Proxy-Authorization: Basic ") << userPassEncoded
<< wxT("\r\n");
1131 case PROXY_CMD_BIND
:
1135 case PROXY_CMD_UDP_ASSOCIATE
:
1140 // Send the command packet
1141 m_packetLenght
= msg
.Len();
1142 memcpy(m_buffer
, unicode2char(msg
), m_packetLenght
+1);
1143 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
1147 void CHttpStateMachine::process_receive_command_reply(bool entry
)
1150 // Receive the server's reply -- Use a large number, but don't
1151 // Expect to get it all. HTTP protocol does not have a fixed length.
1152 m_packetLenght
= PROXY_BUFFER_SIZE
;
1153 ProxyRead(*m_proxyClientSocket
, m_buffer
);
1159 * HTTP Proxy server response should be something like:
1160 * "HTTP/1.1 200 Connection established\r\n\r\n"
1161 * but that may vary. The important thing is the "200"
1162 * code, that means success.
1164 static const char HTTP_AUTH_RESPONSE
[] = "HTTP/";
1165 static const int HTTP_AUTH_RESPONSE_LENGHT
= strlen(HTTP_AUTH_RESPONSE
);
1166 void CHttpStateMachine::process_process_command_reply(bool entry
)
1169 // The position of the first space in the buffer
1171 while (m_buffer
[i
] == ' ') {
1174 // Process the server's reply
1175 m_ok
= !memcmp(m_buffer
+ 0, HTTP_AUTH_RESPONSE
, HTTP_AUTH_RESPONSE_LENGHT
) &&
1176 !memcmp(m_buffer
+ i
, "200", 3);
1181 //------------------------------------------------------------------------------
1183 //------------------------------------------------------------------------------
1185 CProxySocket::CProxySocket(
1186 muleSocketFlags flags
,
1187 const CProxyData
*proxyData
,
1188 CProxyCommand proxyCommand
,
1189 CDatagramSocketProxy
*udpSocket
)
1192 m_proxyStateMachine(NULL
),
1193 m_udpSocket(udpSocket
)
1194 #ifndef ASIO_SOCKETS
1195 ,m_socketEventHandler(NULL
)
1196 ,m_socketEventHandlerId(0)
1197 ,m_savedSocketEventHandler(NULL
)
1198 ,m_savedSocketEventHandlerId(0)
1201 SetProxyData(proxyData
);
1203 switch (m_proxyData
.m_proxyType
) {
1208 m_proxyStateMachine
=
1209 new CSocks5StateMachine(*proxyData
, proxyCommand
);
1214 m_proxyStateMachine
=
1215 new CSocks4StateMachine(*proxyData
, proxyCommand
);
1219 m_proxyStateMachine
=
1220 new CHttpStateMachine(*proxyData
, proxyCommand
);
1229 CProxySocket::~CProxySocket()
1231 delete m_proxyStateMachine
;
1234 void CProxySocket::SetProxyData(const CProxyData
*proxyData
)
1236 m_useProxy
= proxyData
!= NULL
&& proxyData
->m_proxyEnable
;
1238 m_proxyData
= *proxyData
;
1239 m_proxyAddress
.Hostname(m_proxyData
.m_proxyHostName
);
1240 m_proxyAddress
.Service(m_proxyData
.m_proxyPort
);
1242 m_proxyData
.Clear();
1246 bool CProxySocket::Start(const amuleIPV4Address
&peerAddress
)
1249 SetProxyState(true, &peerAddress
);
1252 // Important note! SaveState()/RestoreState() DO NOT save/restore
1253 // the event handler. The method SaveEventHandler() has been created
1256 SetEventHandler(g_proxyEventHandler
, ID_PROXY_SOCKET_EVENT
);
1258 wxSOCKET_CONNECTION_FLAG
|
1259 wxSOCKET_INPUT_FLAG
|
1260 wxSOCKET_OUTPUT_FLAG
|
1261 wxSOCKET_LOST_FLAG
);
1264 Connect(m_proxyAddress
, false);
1265 SetFlags(MULE_SOCKET_NONE
);
1266 return m_proxyStateMachine
->Start(peerAddress
, this);
1269 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand
) const
1273 switch (m_proxyData
.m_proxyType
) {
1279 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1280 proxyCommand
== PROXY_CMD_BIND
||
1281 proxyCommand
== PROXY_CMD_UDP_ASSOCIATE
;
1286 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1287 proxyCommand
== PROXY_CMD_BIND
;
1291 ret
= proxyCommand
== PROXY_CMD_CONNECT
;
1298 //------------------------------------------------------------------------------
1299 // CSocketClientProxy
1300 //------------------------------------------------------------------------------
1302 CSocketClientProxy::CSocketClientProxy(
1303 muleSocketFlags flags
,
1304 const CProxyData
*proxyData
)
1306 CProxySocket(flags
, proxyData
, PROXY_CMD_CONNECT
)
1310 bool CSocketClientProxy::Connect(amuleIPV4Address
&address
, bool wait
)
1312 wxMutexLocker
lock(m_socketLocker
);
1315 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT
)) {
1316 ok
= Start(address
);
1318 ok
= CLibSocket::Connect(address
, wait
);
1324 uint32
CSocketClientProxy::Read(void *buffer
, wxUint32 nbytes
)
1326 wxMutexLocker
lock(m_socketLocker
);
1327 return CProxySocket::Read(buffer
, nbytes
);
1330 uint32
CSocketClientProxy::Write(const void *buffer
, wxUint32 nbytes
)
1332 wxMutexLocker
lock(m_socketLocker
);
1333 return CProxySocket::Write(buffer
, nbytes
);
1336 //------------------------------------------------------------------------------
1337 // CSocketServerProxy
1338 //------------------------------------------------------------------------------
1340 CSocketServerProxy::CSocketServerProxy(
1341 amuleIPV4Address
&address
,
1342 muleSocketFlags flags
,
1345 CLibSocketServer(address
, flags
)
1347 /* Maybe some day when socks6 is out... :) */
1350 //------------------------------------------------------------------------------
1351 // CDatagramSocketProxy
1352 //------------------------------------------------------------------------------
1354 CDatagramSocketProxy::CDatagramSocketProxy(
1355 amuleIPV4Address
&address
, muleSocketFlags flags
, const CProxyData
*proxyData
)
1357 CLibUDPSocket(address
, flags
),
1358 m_proxyTCPSocket(MULE_SOCKET_NOWAIT
, proxyData
, PROXY_CMD_UDP_ASSOCIATE
, this)
1360 m_udpSocketOk
= false;
1361 if ( m_proxyTCPSocket
.GetUseProxy() &&
1362 m_proxyTCPSocket
.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE
)) {
1363 m_proxyTCPSocket
.Start(address
);
1366 m_lastUDPOperation
= UDP_OPERATION_NONE
;
1369 CDatagramSocketProxy::~CDatagramSocketProxy()
1372 // "A UDP association terminates when the TCP connection that the
1373 // UDP ASSOCIATE request arrived terminates."
1376 uint32
CDatagramSocketProxy::RecvFrom(amuleIPV4Address
& addr
, void* buf
, uint32 nBytes
)
1379 wxMutexLocker
lock(m_socketLocker
);
1380 m_lastUDPOperation
= UDP_OPERATION_RECV_FROM
;
1381 if (m_proxyTCPSocket
.GetUseProxy()) {
1382 if (m_udpSocketOk
) {
1383 char *bufUDP
= NULL
;
1384 if (nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
> PROXY_BUFFER_SIZE
) {
1385 bufUDP
= new char[nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
];
1387 bufUDP
= m_proxyTCPSocket
.GetBuffer();
1389 read
= CLibUDPSocket::RecvFrom(
1390 m_proxyTCPSocket
.GetProxyBoundAddress(),
1391 bufUDP
, nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
);
1392 unsigned int offset
;
1393 switch (m_proxyTCPSocket
.GetBuffer()[3]) {
1394 case SOCKS5_ATYP_IPV4_ADDRESS
: {
1395 offset
= PROXY_UDP_OVERHEAD_IPV4
;
1397 amuleIPV4Address
&a
= dynamic_cast<amuleIPV4Address
&>(addr
);
1398 a
.Hostname( PeekUInt32( m_proxyTCPSocket
.GetBuffer()+4 ) );
1399 a
.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket
.GetBuffer()+8) ) );
1400 } catch (const std::bad_cast
& WXUNUSED(e
)) {
1401 AddDebugLogLineN(logProxy
,
1402 wxT("(2)bad_cast exception!"));
1408 case SOCKS5_ATYP_DOMAINNAME
:
1409 offset
= PROXY_UDP_OVERHEAD_DOMAIN_NAME
;
1412 case SOCKS5_ATYP_IPV6_ADDRESS
:
1413 offset
= PROXY_UDP_OVERHEAD_IPV6
;
1421 memcpy(buf
, bufUDP
+ offset
, nBytes
);
1422 // Uncomment here to see the buffer contents on console
1423 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1425 /* Only delete buffer if it was dynamically created */
1426 if (bufUDP
!= m_proxyTCPSocket
.GetBuffer()) {
1427 /* We should use a fixed buffer to avoid
1428 * new/delete it all the time.
1429 * I need an upper bound */
1432 /* There is still one problem pending, fragmentation.
1433 * Either we support it or we have to drop fragmented
1434 * messages. I vote for drop :)
1438 read
= CLibUDPSocket::RecvFrom(addr
, buf
, nBytes
);
1444 uint32
CDatagramSocketProxy::SendTo(const amuleIPV4Address
& addr
, const void* buf
, uint32 nBytes
)
1447 wxMutexLocker
lock(m_socketLocker
);
1448 m_lastUDPOperation
= UDP_OPERATION_SEND_TO
;
1449 m_lastUDPOverhead
= PROXY_UDP_OVERHEAD_IPV4
;
1450 if (m_proxyTCPSocket
.GetUseProxy()) {
1451 if (m_udpSocketOk
) {
1452 m_proxyTCPSocket
.GetBuffer()[0] = SOCKS5_RSV
; // Reserved
1453 m_proxyTCPSocket
.GetBuffer()[1] = SOCKS5_RSV
; // Reserved
1454 m_proxyTCPSocket
.GetBuffer()[2] = 0; // FRAG
1455 m_proxyTCPSocket
.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
1456 PokeUInt32( m_proxyTCPSocket
.GetBuffer()+4, StringIPtoUint32(addr
.IPAddress()));
1457 RawPokeUInt16( m_proxyTCPSocket
.GetBuffer()+8, ENDIAN_HTONS( addr
.Service() ) );
1458 memcpy(m_proxyTCPSocket
.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4
, buf
, nBytes
);
1459 nBytes
+= PROXY_UDP_OVERHEAD_IPV4
;
1460 sent
= CLibUDPSocket::SendTo(
1461 m_proxyTCPSocket
.GetProxyBoundAddress(),
1462 m_proxyTCPSocket
.GetBuffer(), nBytes
);
1463 // Uncomment here to see the buffer contents on console
1464 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1467 sent
= CLibUDPSocket::SendTo(addr
, buf
, nBytes
);
1473 #endif // CLIENT_GUI
1475 /******************************************************************************/
1476 // File_checked_for_headers