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 //------------------------------------------------------------------------------
38 //------------------------------------------------------------------------------
40 CProxyData::CProxyData()
45 CProxyData::CProxyData(
48 const wxString
&proxyHostName
,
49 unsigned short proxyPort
,
51 const wxString
&userName
,
52 const wxString
&password
)
54 m_proxyEnable(proxyEnable
),
55 m_proxyType(proxyType
),
56 m_proxyHostName(proxyHostName
),
57 m_proxyPort(proxyPort
),
59 * The flag m_enablePassword is currently not used. The first
60 * authentication method tryed is No-Authentication, the second
61 * is username/password. If there is no username/password in
62 * CProxyData, a NULL username/password is sent. That will probably
63 * lead to a failure, but at least we tryed. Maybe this behaviour
64 * could be altered later.
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)
87 //------------------------------------------------------------------------------
89 //------------------------------------------------------------------------------
91 CProxyEventHandler::CProxyEventHandler()
95 BEGIN_EVENT_TABLE(CProxyEventHandler
, wxEvtHandler
)
96 EVT_SOCKET(ID_PROXY_SOCKET_EVENT
, CProxyEventHandler::ProxySocketHandler
)
100 // THE one and only Event Handler
102 static CProxyEventHandler g_proxyEventHandler
;
104 void CProxyEventHandler::ProxySocketHandler(wxSocketEvent
& event
)
106 CProxySocket
*sock
= dynamic_cast<CProxySocket
*>(event
.GetSocket());
108 sock
->m_proxyStateMachine
->Schedule(event
.GetSocketEvent());
109 sock
->m_proxyStateMachine
->Clock();
116 // In Asio mode the event handler is:
118 void CProxySocket::OnProxyEvent(int evt
)
120 m_proxyStateMachine
->Schedule(evt
);
121 m_proxyStateMachine
->Clock();
124 //------------------------------------------------------------------------------
125 // CProxyStateMachine
126 //------------------------------------------------------------------------------
128 CProxyStateMachine::CProxyStateMachine(
130 const unsigned int max_states
,
131 const CProxyData
&proxyData
,
132 CProxyCommand proxyCommand
)
134 CStateMachine(NewName(name
, proxyCommand
), max_states
, PROXY_STATE_START
),
135 m_proxyData(proxyData
),
136 m_proxyCommand(proxyCommand
),
138 m_isConnected(false),
143 // Will be initialized at Start()
145 m_proxyClientSocket(NULL
),
146 m_proxyBoundAddress(NULL
),
147 // Temporary variables
153 CProxyStateMachine::~CProxyStateMachine()
155 delete m_peerAddress
;
158 wxString
&CProxyStateMachine::NewName(wxString
&s
, CProxyCommand proxyCommand
)
160 switch (proxyCommand
) {
161 case PROXY_CMD_CONNECT
:
162 s
+= wxT("-CONNECT");
169 case PROXY_CMD_UDP_ASSOCIATE
:
177 bool CProxyStateMachine::Start(const amuleIPV4Address
&peerAddress
, CLibSocket
*proxyClientSocket
)
179 m_proxyClientSocket
= proxyClientSocket
;
180 m_peerAddress
= new amuleIPV4Address(peerAddress
);
182 // const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
183 // m_peerAddress = new amuleIPV4Address(peer);
184 //} catch (const std::bad_cast& WXUNUSED(e)) {
185 // // Should process other types of wxIPAddres before quitting
186 // AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
191 // To run the state machine, return and just let the events start to happen.
195 static const int MULE_SOCKET_DUMMY_VALUE
= MULE_SOCKET_INPUT
+ MULE_SOCKET_OUTPUT
+ MULE_SOCKET_CONNECTION
+ MULE_SOCKET_LOST
;
197 t_sm_state
CProxyStateMachine::HandleEvent(t_sm_event event
)
199 // Default is stay in current state
200 t_sm_state ret
= GetState();
203 case MULE_SOCKET_CONNECTION
:
204 AddDebugLogLineN(logProxy
, wxT("Connection event"));
205 m_isConnected
= true;
208 case MULE_SOCKET_INPUT
:
209 AddDebugLogLineN(logProxy
, wxT("Input event"));
213 case MULE_SOCKET_OUTPUT
:
214 AddDebugLogLineN(logProxy
, wxT("Output event"));
218 case MULE_SOCKET_LOST
:
219 AddDebugLogLineN(logProxy
, wxT("Lost connection event"));
224 case MULE_SOCKET_DUMMY_VALUE
:
225 AddDebugLogLineN(logProxy
, wxT("Dummy event"));
229 AddDebugLogLineN(logProxy
, CFormat(wxT("Unknown event %d")) % event
);
233 // Aborting conditions:
234 // - MULE_SOCKET_LOST event
235 // - More than 10 times on the same state
237 GetClocksInCurrentState() > 10) {
238 ret
= PROXY_STATE_END
;
244 void CProxyStateMachine::AddDummyEvent()
247 CProxySocket
*s
= dynamic_cast<CProxySocket
*>(m_proxyClientSocket
);
248 if (s
) { // should always be
249 CoreNotify_ProxySocketEvent(s
, MULE_SOCKET_DUMMY_VALUE
);
252 wxSocketEvent
e(ID_PROXY_SOCKET_EVENT
);
253 // Make sure this is an unknown event :)
254 e
.m_event
= (wxSocketNotify
)(MULE_SOCKET_DUMMY_VALUE
);
255 e
.SetEventObject(m_proxyClientSocket
);
256 g_proxyEventHandler
.AddPendingEvent(e
);
260 void CProxyStateMachine::ReactivateSocket()
262 /* If proxy is beeing used, then the TCP socket handlers
263 * (CServerSocketHandler and CClientTCPSocketHandler) will not
264 * receive a wxSOCKET_CONNECTION event, because the connection has
265 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
266 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
267 * necessary to start sending data to the server. */
268 CProxySocket
*s
= dynamic_cast<CProxySocket
*>(m_proxyClientSocket
);
269 // If that is not true, we are in serious trouble...
271 if (CDatagramSocketProxy
*udp
= s
->GetUDPSocket()) {
272 // The original socket was a UDP socket
274 // From now on, the UDP socket can be used,
275 // remove the protection.
276 udp
->SetUDPSocketOk();
278 // No need to call RestoreState(), that socket will no longer
279 // be used after proxy negotiation.
281 // The original socket was a TCP socket
283 if (s
->GetProxyState()) { // somehow this gets called twice ?
284 s
->SetProxyState(false);
285 CoreNotify_LibSocketConnect(s
, 0);
287 CoreNotify_LibSocketSend(s
, 0);
289 CoreNotify_LibSocketLost(s
);
293 s
->RestoreEventHandler();
294 wxSocketEvent
e(s
->GetEventHandlerId());
295 e
.m_event
= wxSOCKET_CONNECTION
;
297 wxEvtHandler
*h(s
->GetEventHandler());
298 h
->AddPendingEvent(e
);
299 e
.m_event
= wxSOCKET_OUTPUT
;
300 h
->AddPendingEvent(e
);
302 e
.m_event
= wxSOCKET_LOST
;
303 h
->AddPendingEvent(e
);
310 uint32
CProxyStateMachine::ProxyWrite(CLibSocket
&socket
, const void *buffer
, wxUint32 nbytes
)
312 uint32 written
= socket
.Write(buffer
, nbytes
);
313 /* Set the status of this operation */
315 if (m_proxyClientSocket
->BlocksWrite()) {
318 } else if ((m_lastError
= m_proxyClientSocket
->LastError()) != 0) {
321 AddDebugLogLineN(logProxy
, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes
% written
% m_ok
% m_canSend
);
326 uint32
CProxyStateMachine::ProxyRead(CLibSocket
&socket
, void *buffer
)
328 /* Always try to read the full buffer. That explicitly demands that
329 * the socket has the flag wxSOCKET_NONE. */
330 m_lastRead
= socket
.Read(buffer
, PROXY_BUFFER_SIZE
);
331 /* Set the status of this operation */
333 if (m_proxyClientSocket
->BlocksRead()) {
335 m_canReceive
= false;
336 } else if ((m_lastError
= m_proxyClientSocket
->LastError()) != 0) {
340 // We will get a new event right away if data is left, or when new data gets available.
342 m_canReceive
= false;
344 AddDebugLogLineN(logProxy
, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead
% m_ok
% m_canReceive
);
349 bool CProxyStateMachine::CanReceive() const
354 bool CProxyStateMachine::CanSend() const
359 //------------------------------------------------------------------------------
360 // CSocks5StateMachine
361 //------------------------------------------------------------------------------
364 * The state machine constructor must initialize the array of pointer to member
365 * functions. Don't waste you time trying to statically initialize this, pointer
366 * to member functions require an object to operate on, so this array must be
367 * initialized at run time.
369 CSocks5StateMachine::CSocks5StateMachine(
370 const CProxyData
&proxyData
,
371 CProxyCommand proxyCommand
)
374 wxString(wxT("Socks5")), SOCKS5_MAX_STATES
, proxyData
, proxyCommand
)
376 m_process_state
[ 0] = &CSocks5StateMachine::process_start
;
377 m_state_name
[ 0] = wxT("process_start");
378 m_process_state
[ 1] = &CSocks5StateMachine::process_end
;
379 m_state_name
[ 1] = wxT("process_end");
380 m_process_state
[ 2] = &CSocks5StateMachine::process_send_query_authentication_method
;
381 m_state_name
[ 2] = wxT("process_send_query_authentication_method");
382 m_process_state
[ 3] = &CSocks5StateMachine::process_receive_authentication_method
;
383 m_state_name
[ 3] = wxT("process_receive_authentication_method");
384 m_process_state
[ 4] = &CSocks5StateMachine::process_process_authentication_method
;
385 m_state_name
[ 4] = wxT("process_process_authentication_method");
386 m_process_state
[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi
;
387 m_state_name
[ 5] = wxT("process_send_authentication_gssapi");
388 m_process_state
[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi
;
389 m_state_name
[ 6] = wxT("process_receive_authentication_gssapi");
390 m_process_state
[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi
;
391 m_state_name
[ 7] = wxT("process_process_authentication_gssapi");
392 m_process_state
[ 8] = &CSocks5StateMachine::process_send_authentication_username_password
;
393 m_state_name
[ 8] = wxT("process_send_authentication_username_password");
394 m_process_state
[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password
;
395 m_state_name
[ 9] = wxT("process_receive_authentication_username_password");
396 m_process_state
[10] = &CSocks5StateMachine::process_process_authentication_username_password
;
397 m_state_name
[10] = wxT("process_process_authentication_username_password");
398 m_process_state
[11] = &CSocks5StateMachine::process_send_command_request
;
399 m_state_name
[11] = wxT("process_send_command_request");
400 m_process_state
[12] = &CSocks5StateMachine::process_receive_command_reply
;
401 m_state_name
[12] = wxT("process_receive_command_reply");
402 m_process_state
[13] = &CSocks5StateMachine::process_process_command_reply
;
403 m_state_name
[13] = wxT("process_process_command_reply");
406 void CSocks5StateMachine::process_state(t_sm_state state
, bool entry
)
408 /* Ok, the syntax is terrible, but this is correct. This is a
409 * pointer to a member function. No C equivalent for that. */
410 (this->*m_process_state
[state
])(entry
);
415 case SOCKS5_STATE_START
:
416 case SOCKS5_STATE_END
:
417 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
418 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
419 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
420 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
425 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
426 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
427 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
428 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
432 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
433 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
434 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
435 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
441 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
443 AddDebugLogLineN(logProxy
,
444 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
450 * Code this such that the next state is only entered when it is able to
451 * perform the operation (read or write). State processing will assume
452 * that it can read or write upon entry of the state. This is done using
453 * CanSend() and CanReceive().
455 t_sm_state
CSocks5StateMachine::next_state(t_sm_event event
)
457 // Default is stay in current state
458 t_sm_state ret
= HandleEvent(event
);
459 switch (GetState()) {
460 case SOCKS5_STATE_START
:
461 if (m_isConnected
&& !m_isLost
&& CanSend()) {
462 ret
= SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
;
466 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
468 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
;
472 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
473 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
;
476 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
479 switch (m_lastReply
) {
480 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
:
481 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
484 case SOCKS5_AUTH_METHOD_GSSAPI
:
485 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
;
488 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
:
489 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
;
492 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS
:
494 ret
= SOCKS5_STATE_END
;
498 AddDebugLogLineN(logProxy
, wxT("Can't send"));
501 ret
= SOCKS5_STATE_END
;
505 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
508 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
;
511 ret
= SOCKS5_STATE_END
;
515 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
518 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
;
521 ret
= SOCKS5_STATE_END
;
525 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
526 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
;
529 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
530 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
;
533 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
534 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
537 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
540 ret
= SOCKS5_STATE_END
;
544 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
547 ret
= SOCKS5_STATE_RECEIVE_COMMAND_REPLY
;
550 ret
= SOCKS5_STATE_END
;
554 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
555 ret
= SOCKS5_STATE_PROCESS_COMMAND_REPLY
;
558 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
559 ret
= SOCKS5_STATE_END
;
562 case SOCKS5_STATE_END
:
571 * So, this is how you do it: the state machine is clocked by the events
572 * that happen inside the event handler. You can add a dummy event whenever
573 * you see that the system will not generate an event. But don't add dummy
574 * events before reads, reads should only be performed after input events.
576 * Maybe it makes sense to add a dummy event before a read if there is no
577 * state change (wait state).
579 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
580 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
581 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
582 * event will be generated. If you feel you will need more clocks than these, use
583 * AddDummyEvent(), but I suggest you review your state machine design first.
585 void CSocks5StateMachine::process_start(bool)
588 void CSocks5StateMachine::process_end(bool)
593 void CSocks5StateMachine::process_send_query_authentication_method(bool entry
)
596 // Prepare the authentication method negotiation packet
597 m_buffer
[0] = SOCKS5_VERSION
;
598 m_buffer
[1] = 2; // Number of supported methods
599 //m_buffer[1] = 3; // Number of supported methods
600 m_buffer
[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
;
601 m_buffer
[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
;
602 m_buffer
[4] = SOCKS5_AUTH_METHOD_GSSAPI
;
604 //m_packetLenght = 5;
606 // Send the authentication method negotiation packet
607 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
611 void CSocks5StateMachine::process_receive_authentication_method(bool entry
)
614 // Receive the method selection message
616 ProxyRead(*m_proxyClientSocket
, m_buffer
);
618 /* This is added because there will be no more input events. If the
619 * world was a nice place, we could think about joining the
620 * process_receive and the process_process states here, but some day
621 * we might have to deal with the fact that the i/o operation has been
622 * incomplete, and that we must finish our job the next time we enter
627 void CSocks5StateMachine::process_process_authentication_method(bool entry
)
630 m_lastReply
= m_buffer
[1];
631 m_ok
= m_ok
&& m_buffer
[0] == SOCKS5_VERSION
;
633 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
634 * once when you connect the socket, and after that, only after a
635 * wxSOCKET_WOULDBLOCK error happens. */
639 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
641 // TODO or not TODO? That is the question...
645 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
650 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
655 void CSocks5StateMachine::process_send_authentication_username_password(bool entry
)
658 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
659 unsigned char lenPassword
= m_proxyData
.m_password
.Len();
660 m_packetLenght
= 1 + 1 + lenUser
+ 1 + lenPassword
;
661 unsigned int offsetUser
= 2;
662 unsigned int offsetPassword
= offsetUser
+ lenUser
+ 1;
664 // Prepare username/password buffer
665 m_buffer
[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
;
666 m_buffer
[offsetUser
-1] = lenUser
;
667 memcpy(m_buffer
+offsetUser
, unicode2char(m_proxyData
.m_userName
),
669 m_buffer
[offsetPassword
-1] = lenPassword
;
670 memcpy(m_buffer
+offsetPassword
, unicode2char(m_proxyData
.m_password
),
673 // Send the username/password packet
674 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
678 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry
)
681 // Receive the server's authentication response
683 ProxyRead(*m_proxyClientSocket
, m_buffer
);
688 void CSocks5StateMachine::process_process_authentication_username_password(bool entry
)
691 // Process the server's reply
692 m_lastReply
= m_buffer
[1];
694 m_buffer
[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
&&
695 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
700 void CSocks5StateMachine::process_send_command_request(bool entry
)
703 // Prepare the request command buffer
704 m_buffer
[0] = SOCKS5_VERSION
;
705 switch (m_proxyCommand
) {
706 case PROXY_CMD_CONNECT
:
707 m_buffer
[1] = SOCKS5_CMD_CONNECT
;
711 m_buffer
[1] = SOCKS5_CMD_BIND
;
714 case PROXY_CMD_UDP_ASSOCIATE
:
715 m_buffer
[1] = SOCKS5_CMD_UDP_ASSOCIATE
;
718 m_buffer
[2] = SOCKS5_RSV
;
719 m_buffer
[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
720 PokeUInt32( m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()) );
721 RawPokeUInt16( m_buffer
+8, ENDIAN_HTONS( m_peerAddress
->Service() ) );
723 // Send the command packet
725 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
729 void CSocks5StateMachine::process_receive_command_reply(bool entry
)
732 // The minimum number of bytes to read is 10 in the case of
733 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
735 ProxyRead(*m_proxyClientSocket
, m_buffer
);
740 void CSocks5StateMachine::process_process_command_reply(bool entry
)
743 m_lastReply
= m_buffer
[1];
744 unsigned char addressType
= m_buffer
[3];
745 // Process the server's reply
747 m_buffer
[0] == SOCKS5_VERSION
&&
748 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
751 unsigned int portOffset
= 0;
752 switch(addressType
) {
753 case SOCKS5_ATYP_IPV4_ADDRESS
:
755 const unsigned int addrOffset
= 4;
757 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
758 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
761 case SOCKS5_ATYP_DOMAINNAME
:
763 // Read the domain name
764 const unsigned int addrOffset
= 5;
765 portOffset
= 10 + m_buffer
[4];
766 char c
= m_buffer
[portOffset
];
767 m_buffer
[portOffset
] = 0;
768 m_proxyBoundAddressIPV4
.Hostname(
769 char2unicode(m_buffer
+addrOffset
));
770 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
771 m_buffer
[portOffset
] = c
;
774 case SOCKS5_ATYP_IPV6_ADDRESS
:
778 // IPV6 not yet implemented in wx
779 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
780 // *((uint128 *)(m_buffer+addrOffset)) ));
781 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
786 // Set the packet length at last
787 m_packetLenght
= portOffset
+ 2;
789 m_proxyBoundAddress
->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer
+portOffset
) ) );
795 //------------------------------------------------------------------------------
796 // CSocks4StateMachine
797 //------------------------------------------------------------------------------
799 CSocks4StateMachine::CSocks4StateMachine(
800 const CProxyData
&proxyData
,
801 CProxyCommand proxyCommand
)
804 wxString(wxT("Socks4")), SOCKS4_MAX_STATES
, proxyData
, proxyCommand
)
806 m_process_state
[0] = &CSocks4StateMachine::process_start
;
807 m_state_name
[0] = wxT("process_start");
808 m_process_state
[1] = &CSocks4StateMachine::process_end
;
809 m_state_name
[1] = wxT("process_end");
810 m_process_state
[2] = &CSocks4StateMachine::process_send_command_request
;
811 m_state_name
[2] = wxT("process_send_command_request");
812 m_process_state
[3] = &CSocks4StateMachine::process_receive_command_reply
;
813 m_state_name
[3] = wxT("process_receive_command_reply");
814 m_process_state
[4] = &CSocks4StateMachine::process_process_command_reply
;
815 m_state_name
[4] = wxT("process_process_command_reply");
818 void CSocks4StateMachine::process_state(t_sm_state state
, bool entry
)
820 (this->*m_process_state
[state
])(entry
);
825 case SOCKS4_STATE_START
:
826 case SOCKS4_STATE_END
:
827 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
832 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
836 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
842 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
844 AddDebugLogLineN(logProxy
,
845 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
850 t_sm_state
CSocks4StateMachine::next_state(t_sm_event event
)
852 // Default is stay in current state
853 t_sm_state ret
= HandleEvent(event
);
854 switch (GetState()) {
855 case SOCKS4_STATE_START
:
856 if (m_isConnected
&& !m_isLost
&& CanSend()) {
857 ret
= SOCKS4_STATE_SEND_COMMAND_REQUEST
;
861 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
864 ret
= SOCKS4_STATE_RECEIVE_COMMAND_REPLY
;
867 ret
= SOCKS4_STATE_END
;
871 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
872 ret
= SOCKS4_STATE_PROCESS_COMMAND_REPLY
;
875 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
876 ret
= SOCKS4_STATE_END
;
879 case SOCKS4_STATE_END
:
887 void CSocks4StateMachine::process_start(bool)
890 void CSocks4StateMachine::process_end(bool)
895 void CSocks4StateMachine::process_send_command_request(bool entry
)
898 // Prepare the request command buffer
899 m_buffer
[0] = SOCKS4_VERSION
;
900 switch (m_proxyCommand
) {
901 case PROXY_CMD_CONNECT
:
902 m_buffer
[1] = SOCKS4_CMD_CONNECT
;
906 m_buffer
[1] = SOCKS4_CMD_BIND
;
909 case PROXY_CMD_UDP_ASSOCIATE
:
914 RawPokeUInt16(m_buffer
+2, ENDIAN_HTONS(m_peerAddress
->Service()));
915 // Special processing for SOCKS4a
916 switch (m_proxyData
.m_proxyType
) {
918 PokeUInt32(m_buffer
+4, StringIPtoUint32(wxT("0.0.0.1")));
922 PokeUInt32(m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()));
925 // Common processing for SOCKS4/SOCKS4a
926 unsigned int offsetUser
= 8;
927 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
928 memcpy(m_buffer
+ offsetUser
,
929 unicode2char(m_proxyData
.m_userName
), lenUser
);
930 m_buffer
[offsetUser
+ lenUser
] = 0;
931 // Special processing for SOCKS4a
932 switch (m_proxyData
.m_proxyType
) {
933 case PROXY_SOCKS4a
: {
934 unsigned int offsetDomain
= offsetUser
+ lenUser
+ 1;
935 // The Hostname() method was used here before, but I don't see why we can't use
936 // the IP address which we actually know instead here.
937 wxString
hostname(m_peerAddress
->IPAddress());
938 unsigned char lenDomain
= hostname
.Len();
939 memcpy(m_buffer
+ offsetDomain
,
940 unicode2char(hostname
), lenDomain
);
941 m_buffer
[offsetDomain
+ lenDomain
] = 0;
942 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1 + lenDomain
+ 1;
947 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1;
950 // Send the command packet
951 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
955 void CSocks4StateMachine::process_receive_command_reply(bool entry
)
958 // Receive the server's reply
960 ProxyRead(*m_proxyClientSocket
, m_buffer
);
965 void CSocks4StateMachine::process_process_command_reply(bool entry
)
968 m_lastReply
= m_buffer
[1];
970 // Process the server's reply
972 m_buffer
[0] == SOCKS4_REPLY_CODE
&&
973 m_buffer
[1] == SOCKS4_REPLY_GRANTED
;
976 const unsigned int portOffset
= 2;
977 m_ok
= m_proxyBoundAddressIPV4
.Service(ENDIAN_NTOHS(
978 RawPeekUInt16( m_buffer
+portOffset
) ) );
980 const unsigned int addrOffset
= 4;
982 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
983 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
989 //------------------------------------------------------------------------------
991 //------------------------------------------------------------------------------
993 CHttpStateMachine::CHttpStateMachine(
994 const CProxyData
&proxyData
,
995 CProxyCommand proxyCommand
)
998 wxString(wxT("Http")), HTTP_MAX_STATES
, proxyData
, proxyCommand
)
1000 m_process_state
[0] = &CHttpStateMachine::process_start
;
1001 m_state_name
[0] = wxT("process_start");
1002 m_process_state
[1] = &CHttpStateMachine::process_end
;
1003 m_state_name
[1] = wxT("process_end");
1004 m_process_state
[2] = &CHttpStateMachine::process_send_command_request
;
1005 m_state_name
[2] = wxT("process_send_command_request");
1006 m_process_state
[3] = &CHttpStateMachine::process_receive_command_reply
;
1007 m_state_name
[3] = wxT("process_receive_command_reply");
1008 m_process_state
[4] = &CHttpStateMachine::process_process_command_reply
;
1009 m_state_name
[4] = wxT("process_process_command_reply");
1012 void CHttpStateMachine::process_state(t_sm_state state
, bool entry
)
1014 (this->*m_process_state
[state
])(entry
);
1019 case HTTP_STATE_START
:
1020 case HTTP_STATE_END
:
1021 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1026 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1030 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1036 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
1038 AddDebugLogLineN(logProxy
,
1039 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
1044 t_sm_state
CHttpStateMachine::next_state(t_sm_event event
)
1046 // Default is stay in current state
1047 t_sm_state ret
= HandleEvent(event
);
1048 switch (GetState()) {
1049 case HTTP_STATE_START
:
1050 if (m_isConnected
&& !m_isLost
&& CanSend()) {
1051 ret
= HTTP_STATE_SEND_COMMAND_REQUEST
;
1055 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1058 ret
= HTTP_STATE_RECEIVE_COMMAND_REPLY
;
1061 ret
= HTTP_STATE_END
;
1065 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1066 ret
= HTTP_STATE_PROCESS_COMMAND_REPLY
;
1069 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1070 ret
= HTTP_STATE_END
;
1073 case HTTP_STATE_END
:
1081 void CHttpStateMachine::process_start(bool)
1084 void CHttpStateMachine::process_end(bool)
1089 void CHttpStateMachine::process_send_command_request(bool entry
)
1092 // Prepare the request command buffer
1093 wxString ip
= m_peerAddress
->IPAddress();
1094 uint16 port
= m_peerAddress
->Service();
1096 wxString userPassEncoded
;
1097 if (m_proxyData
.m_enablePassword
) {
1098 userPass
= m_proxyData
.m_userName
+ wxT(":") + m_proxyData
.m_password
;
1100 EncodeBase64(unicode2char(userPass
), userPass
.Length());
1104 switch (m_proxyCommand
) {
1105 case PROXY_CMD_CONNECT
:
1107 wxT("CONNECT ") << ip
<< wxT(":") << port
<< wxT(" HTTP/1.1\r\n") <<
1108 wxT("Host: ") << ip
<< wxT(":") << port
<< wxT("\r\n");
1109 if (m_proxyData
.m_enablePassword
) {
1111 wxT("Authorization: Basic ") << userPassEncoded
<< wxT("\r\n") <<
1112 wxT("Proxy-Authorization: Basic ") << userPassEncoded
<< wxT("\r\n");
1117 case PROXY_CMD_BIND
:
1121 case PROXY_CMD_UDP_ASSOCIATE
:
1126 // Send the command packet
1127 m_packetLenght
= msg
.Len();
1128 memcpy(m_buffer
, unicode2char(msg
), m_packetLenght
+1);
1129 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
1133 void CHttpStateMachine::process_receive_command_reply(bool entry
)
1136 // Receive the server's reply -- Use a large number, but don't
1137 // Expect to get it all. HTTP protocol does not have a fixed length.
1138 m_packetLenght
= PROXY_BUFFER_SIZE
;
1139 ProxyRead(*m_proxyClientSocket
, m_buffer
);
1145 * HTTP Proxy server response should be something like:
1146 * "HTTP/1.1 200 Connection established\r\n\r\n"
1147 * but that may vary. The important thing is the "200"
1148 * code, that means success.
1150 static const char HTTP_AUTH_RESPONSE
[] = "HTTP/";
1151 static const int HTTP_AUTH_RESPONSE_LENGHT
= strlen(HTTP_AUTH_RESPONSE
);
1152 void CHttpStateMachine::process_process_command_reply(bool entry
)
1155 // The position of the first space in the buffer
1157 while (m_buffer
[i
] == ' ') {
1160 // Process the server's reply
1161 m_ok
= !memcmp(m_buffer
+ 0, HTTP_AUTH_RESPONSE
, HTTP_AUTH_RESPONSE_LENGHT
) &&
1162 !memcmp(m_buffer
+ i
, "200", 3);
1167 //------------------------------------------------------------------------------
1169 //------------------------------------------------------------------------------
1171 CProxySocket::CProxySocket(
1172 muleSocketFlags flags
,
1173 const CProxyData
*proxyData
,
1174 CProxyCommand proxyCommand
,
1175 CDatagramSocketProxy
*udpSocket
)
1178 m_proxyStateMachine(NULL
),
1179 m_udpSocket(udpSocket
),
1180 m_socketEventHandler(NULL
),
1181 m_socketEventHandlerId(0),
1182 m_savedSocketEventHandler(NULL
),
1183 m_savedSocketEventHandlerId(0)
1185 SetProxyData(proxyData
);
1187 switch (m_proxyData
.m_proxyType
) {
1192 m_proxyStateMachine
=
1193 new CSocks5StateMachine(*proxyData
, proxyCommand
);
1198 m_proxyStateMachine
=
1199 new CSocks4StateMachine(*proxyData
, proxyCommand
);
1203 m_proxyStateMachine
=
1204 new CHttpStateMachine(*proxyData
, proxyCommand
);
1213 CProxySocket::~CProxySocket()
1215 delete m_proxyStateMachine
;
1218 void CProxySocket::SetProxyData(const CProxyData
*proxyData
)
1220 m_useProxy
= proxyData
!= NULL
&& proxyData
->m_proxyEnable
;
1222 m_proxyData
= *proxyData
;
1223 m_proxyAddress
.Hostname(m_proxyData
.m_proxyHostName
);
1224 m_proxyAddress
.Service(m_proxyData
.m_proxyPort
);
1226 m_proxyData
.Clear();
1230 bool CProxySocket::Start(const amuleIPV4Address
&peerAddress
)
1233 SetProxyState(true, &peerAddress
);
1236 // Important note! SaveState()/RestoreState() DO NOT save/restore
1237 // the event handler. The method SaveEventHandler() has been created
1240 SetEventHandler(g_proxyEventHandler
, ID_PROXY_SOCKET_EVENT
);
1242 wxSOCKET_CONNECTION_FLAG
|
1243 wxSOCKET_INPUT_FLAG
|
1244 wxSOCKET_OUTPUT_FLAG
|
1245 wxSOCKET_LOST_FLAG
);
1248 Connect(m_proxyAddress
, false);
1249 SetFlags(MULE_SOCKET_NONE
);
1250 return m_proxyStateMachine
->Start(peerAddress
, this);
1253 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand
) const
1257 switch (m_proxyData
.m_proxyType
) {
1263 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1264 proxyCommand
== PROXY_CMD_BIND
||
1265 proxyCommand
== PROXY_CMD_UDP_ASSOCIATE
;
1270 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1271 proxyCommand
== PROXY_CMD_BIND
;
1275 ret
= proxyCommand
== PROXY_CMD_CONNECT
;
1282 //------------------------------------------------------------------------------
1283 // CSocketClientProxy
1284 //------------------------------------------------------------------------------
1286 CSocketClientProxy::CSocketClientProxy(
1287 muleSocketFlags flags
,
1288 const CProxyData
*proxyData
)
1290 CProxySocket(flags
, proxyData
, PROXY_CMD_CONNECT
)
1294 bool CSocketClientProxy::Connect(amuleIPV4Address
&address
, bool wait
)
1296 wxMutexLocker
lock(m_socketLocker
);
1299 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT
)) {
1300 ok
= Start(address
);
1302 ok
= CLibSocket::Connect(address
, wait
);
1308 uint32
CSocketClientProxy::Read(void *buffer
, wxUint32 nbytes
)
1310 wxMutexLocker
lock(m_socketLocker
);
1311 return CProxySocket::Read(buffer
, nbytes
);
1314 uint32
CSocketClientProxy::Write(const void *buffer
, wxUint32 nbytes
)
1316 wxMutexLocker
lock(m_socketLocker
);
1317 return CProxySocket::Write(buffer
, nbytes
);
1320 //------------------------------------------------------------------------------
1321 // CSocketServerProxy
1322 //------------------------------------------------------------------------------
1324 CSocketServerProxy::CSocketServerProxy(
1325 amuleIPV4Address
&address
,
1326 muleSocketFlags flags
,
1329 CLibSocketServer(address
, flags
)
1331 /* Maybe some day when socks6 is out... :) */
1334 //------------------------------------------------------------------------------
1335 // CDatagramSocketProxy
1336 //------------------------------------------------------------------------------
1338 CDatagramSocketProxy::CDatagramSocketProxy(
1339 amuleIPV4Address
&address
, muleSocketFlags flags
, const CProxyData
*proxyData
)
1341 CLibUDPSocket(address
, flags
),
1342 m_proxyTCPSocket(MULE_SOCKET_NOWAIT
, proxyData
, PROXY_CMD_UDP_ASSOCIATE
, this)
1344 m_udpSocketOk
= false;
1345 if ( m_proxyTCPSocket
.GetUseProxy() &&
1346 m_proxyTCPSocket
.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE
)) {
1347 m_proxyTCPSocket
.Start(address
);
1350 m_lastUDPOperation
= UDP_OPERATION_NONE
;
1353 CDatagramSocketProxy::~CDatagramSocketProxy()
1356 // "A UDP association terminates when the TCP connection that the
1357 // UDP ASSOCIATE request arrived terminates."
1360 uint32
CDatagramSocketProxy::RecvFrom(amuleIPV4Address
& addr
, void* buf
, uint32 nBytes
)
1363 wxMutexLocker
lock(m_socketLocker
);
1364 m_lastUDPOperation
= UDP_OPERATION_RECV_FROM
;
1365 if (m_proxyTCPSocket
.GetUseProxy()) {
1366 if (m_udpSocketOk
) {
1367 char *bufUDP
= NULL
;
1368 if (nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
> PROXY_BUFFER_SIZE
) {
1369 bufUDP
= new char[nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
];
1371 bufUDP
= m_proxyTCPSocket
.GetBuffer();
1373 read
= CLibUDPSocket::RecvFrom(
1374 m_proxyTCPSocket
.GetProxyBoundAddress(),
1375 bufUDP
, nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
);
1376 unsigned int offset
;
1377 switch (m_proxyTCPSocket
.GetBuffer()[3]) {
1378 case SOCKS5_ATYP_IPV4_ADDRESS
: {
1379 offset
= PROXY_UDP_OVERHEAD_IPV4
;
1381 amuleIPV4Address
&a
= dynamic_cast<amuleIPV4Address
&>(addr
);
1382 a
.Hostname( PeekUInt32( m_proxyTCPSocket
.GetBuffer()+4 ) );
1383 a
.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket
.GetBuffer()+8) ) );
1384 } catch (const std::bad_cast
& WXUNUSED(e
)) {
1385 AddDebugLogLineN(logProxy
,
1386 wxT("(2)bad_cast exception!"));
1392 case SOCKS5_ATYP_DOMAINNAME
:
1393 offset
= PROXY_UDP_OVERHEAD_DOMAIN_NAME
;
1396 case SOCKS5_ATYP_IPV6_ADDRESS
:
1397 offset
= PROXY_UDP_OVERHEAD_IPV6
;
1405 memcpy(buf
, bufUDP
+ offset
, nBytes
);
1406 // Uncomment here to see the buffer contents on console
1407 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1409 /* Only delete buffer if it was dynamically created */
1410 if (bufUDP
!= m_proxyTCPSocket
.GetBuffer()) {
1411 /* We should use a fixed buffer to avoid
1412 * new/delete it all the time.
1413 * I need an upper bound */
1416 /* There is still one problem pending, fragmentation.
1417 * Either we support it or we have to drop fragmented
1418 * messages. I vote for drop :)
1422 read
= CLibUDPSocket::RecvFrom(addr
, buf
, nBytes
);
1428 uint32
CDatagramSocketProxy::SendTo(const amuleIPV4Address
& addr
, const void* buf
, uint32 nBytes
)
1431 wxMutexLocker
lock(m_socketLocker
);
1432 m_lastUDPOperation
= UDP_OPERATION_SEND_TO
;
1433 m_lastUDPOverhead
= PROXY_UDP_OVERHEAD_IPV4
;
1434 if (m_proxyTCPSocket
.GetUseProxy()) {
1435 if (m_udpSocketOk
) {
1436 m_proxyTCPSocket
.GetBuffer()[0] = SOCKS5_RSV
; // Reserved
1437 m_proxyTCPSocket
.GetBuffer()[1] = SOCKS5_RSV
; // Reserved
1438 m_proxyTCPSocket
.GetBuffer()[2] = 0; // FRAG
1439 m_proxyTCPSocket
.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
1440 PokeUInt32( m_proxyTCPSocket
.GetBuffer()+4, StringIPtoUint32(addr
.IPAddress()));
1441 RawPokeUInt16( m_proxyTCPSocket
.GetBuffer()+8, ENDIAN_HTONS( addr
.Service() ) );
1442 memcpy(m_proxyTCPSocket
.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4
, buf
, nBytes
);
1443 nBytes
+= PROXY_UDP_OVERHEAD_IPV4
;
1444 sent
= CLibUDPSocket::SendTo(
1445 m_proxyTCPSocket
.GetProxyBoundAddress(),
1446 m_proxyTCPSocket
.GetBuffer(), nBytes
);
1447 // Uncomment here to see the buffer contents on console
1448 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1451 sent
= CLibUDPSocket::SendTo(addr
, buf
, nBytes
);
1457 #endif // CLIENT_GUI
1459 /******************************************************************************/
1460 // File_checked_for_headers