2 // This file is part of the aMule Project.
4 // Copyright (c) 2004-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2004-2008 Marcelo 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
27 #include "Proxy.h" /* for Interface */
29 #include <common/EventIDs.h>
31 #include "ArchSpecific.h" /* for ENDIAN_HTONS() */
32 #include "Logger.h" /* for AddDebugLogLineM */
33 #include "OtherFunctions.h" /* for EncodeBase64() */
34 #include <common/StringFunctions.h> /* for unicode2char */
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());
112 sock
->m_proxyStateMachine
->Clock();
115 //------------------------------------------------------------------------------
116 // CProxyStateMachine
117 //------------------------------------------------------------------------------
119 CProxyStateMachine::CProxyStateMachine(
121 const unsigned int max_states
,
122 const CProxyData
&proxyData
,
123 CProxyCommand proxyCommand
)
125 CStateMachine(NewName(name
, proxyCommand
), max_states
, PROXY_STATE_START
),
126 m_proxyData(proxyData
),
127 m_proxyCommand(proxyCommand
),
129 m_isConnected(false),
135 // Will be initialized at Start()
137 m_proxyClientSocket(NULL
),
138 m_proxyBoundAddress(NULL
),
139 // Temporary variables
145 CProxyStateMachine::~CProxyStateMachine()
147 delete m_peerAddress
;
150 wxString
&CProxyStateMachine::NewName(wxString
&s
, CProxyCommand proxyCommand
)
152 switch (proxyCommand
) {
153 case PROXY_CMD_CONNECT
:
154 s
+= wxT("-CONNECT");
161 case PROXY_CMD_UDP_ASSOCIATE
:
169 bool CProxyStateMachine::Start(const wxIPaddress
&peerAddress
, wxSocketClient
*proxyClientSocket
)
171 m_proxyClientSocket
= proxyClientSocket
;
173 const wxIPV4address
&peer
= dynamic_cast<const wxIPV4address
&>(peerAddress
);
174 m_peerAddress
= new amuleIPV4Address(peer
);
175 } catch (const std::bad_cast
& WXUNUSED(e
)) {
176 // Should process other types of wxIPAddres before quitting
177 AddDebugLogLineM(false, logProxy
, wxT("(1)bad_cast exception!"));
182 // To run the state machine, return and just let the events start to happen.
186 t_sm_state
CProxyStateMachine::HandleEvent(t_sm_event event
)
188 // Default is stay in current state
189 t_sm_state ret
= GetState();
192 case wxSOCKET_CONNECTION
:
193 AddDebugLogLineM(false, logProxy
, wxT("Connection event"));
194 m_isConnected
= true;
198 AddDebugLogLineM(false, logProxy
, wxT("Input event"));
202 case wxSOCKET_OUTPUT
:
203 AddDebugLogLineM(false, logProxy
, wxT("Output event"));
208 AddDebugLogLineM(false, logProxy
, wxT("Lost connection event"));
214 AddDebugLogLineM(false, logProxy
, wxT("Unknown event"));
218 // Aborting conditions:
219 // - wxSOCKET_LOST event
220 // - More than 10 times on the same state
222 GetClocksInCurrentState() > 10) {
223 ret
= PROXY_STATE_END
;
229 void CProxyStateMachine::AddDummyEvent()
231 wxSocketEvent
e(ID_PROXY_SOCKET_EVENT
);
232 // Make sure this is an unknown event :)
233 e
.m_event
= (wxSocketNotify
)(
234 wxSOCKET_INPUT
+ wxSOCKET_OUTPUT
+
235 wxSOCKET_CONNECTION
+ wxSOCKET_LOST
);
236 e
.SetEventObject(m_proxyClientSocket
);
237 g_proxyEventHandler
.AddPendingEvent(e
);
241 * Notice! These includes are here as long as it is impossible to retrieve
242 * the event handler from the socket. They should be removed. For now,
243 * please leave it here.
246 void CProxyStateMachine::ReactivateSocket()
248 /* If proxy is beeing used, then the TCP socket handlers
249 * (CServerSocketHandler and CClientTCPSocketHandler) will not
250 * receive a wxSOCKET_CONNECTION event, because the connection has
251 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
252 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
253 * necessary to start sending data to the server. */
254 CProxySocket
*s
= dynamic_cast<CProxySocket
*>(m_proxyClientSocket
);
255 // If that is not true, we are in serious trouble...
257 if (CDatagramSocketProxy
*udp
= s
->GetUDPSocket()) {
258 // The original socket was an UDP socket
260 // From now on, the UDP socket can be used,
261 // remove the protection.
262 udp
->SetUDPSocketOk();
264 // No need to call RestoreState(), that socket will no longer
265 // be used after proxy negotiation.
267 // The original socket was a TCP socket
268 s
->RestoreEventHandler();
269 wxSocketEvent
e(s
->GetEventHandlerId());
270 e
.m_event
= wxSOCKET_CONNECTION
;
272 wxEvtHandler
*h(s
->GetEventHandler());
273 h
->AddPendingEvent(e
);
274 e
.m_event
= wxSOCKET_OUTPUT
;
275 h
->AddPendingEvent(e
);
277 e
.m_event
= wxSOCKET_LOST
;
278 h
->AddPendingEvent(e
);
284 wxSocketBase
&CProxyStateMachine::ProxyWrite(wxSocketBase
&socket
, const void *buffer
, wxUint32 nbytes
)
286 wxSocketBase
&ret
= socket
.Write(buffer
, nbytes
);
287 m_lastWritten
= m_proxyClientSocket
->LastCount();
288 /* Set the status of this operation */
289 m_lastError
= wxSOCKET_NOERROR
;
290 m_ok
= !m_proxyClientSocket
->Error();
292 m_lastError
= m_proxyClientSocket
->LastError();
293 m_ok
= m_lastError
== wxSOCKET_WOULDBLOCK
;
302 wxSocketBase
&CProxyStateMachine::ProxyRead(wxSocketBase
&socket
, void *buffer
)
304 /* Always try to read the full buffer. That explicitly demands that
305 * the socket has the flag wxSOCKET_NONE. */
306 wxSocketBase
&ret
= socket
.Read(buffer
, PROXY_BUFFER_SIZE
);
307 m_lastRead
= m_proxyClientSocket
->LastCount();
308 /* Set the status of this operation */
309 m_lastError
= wxSOCKET_NOERROR
;
310 m_ok
= !m_proxyClientSocket
->Error();
312 m_lastError
= m_proxyClientSocket
->LastError();
313 m_ok
= m_lastError
== wxSOCKET_WOULDBLOCK
;
315 m_canReceive
= false;
322 //------------------------------------------------------------------------------
323 // CSocks5StateMachine
324 //------------------------------------------------------------------------------
327 * The state machine constructor must initialize the array of pointer to member
328 * functions. Don't waste you time trying to statically initialize this, pointer
329 * to member functions require an object to operate on, so this array must be
330 * initialized at run time.
332 CSocks5StateMachine::CSocks5StateMachine(
333 const CProxyData
&proxyData
,
334 CProxyCommand proxyCommand
)
337 wxString(wxT("Socks5")), SOCKS5_MAX_STATES
, proxyData
, proxyCommand
)
339 m_process_state
[ 0] = &CSocks5StateMachine::process_start
;
340 m_state_name
[ 0] = wxT("process_start");
341 m_process_state
[ 1] = &CSocks5StateMachine::process_end
;
342 m_state_name
[ 1] = wxT("process_end");
343 m_process_state
[ 2] = &CSocks5StateMachine::process_send_query_authentication_method
;
344 m_state_name
[ 2] = wxT("process_send_query_authentication_method");
345 m_process_state
[ 3] = &CSocks5StateMachine::process_receive_authentication_method
;
346 m_state_name
[ 3] = wxT("process_receive_authentication_method");
347 m_process_state
[ 4] = &CSocks5StateMachine::process_process_authentication_method
;
348 m_state_name
[ 4] = wxT("process_process_authentication_method");
349 m_process_state
[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi
;
350 m_state_name
[ 5] = wxT("process_send_authentication_gssapi");
351 m_process_state
[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi
;
352 m_state_name
[ 6] = wxT("process_receive_authentication_gssapi");
353 m_process_state
[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi
;
354 m_state_name
[ 7] = wxT("process_process_authentication_gssapi");
355 m_process_state
[ 8] = &CSocks5StateMachine::process_send_authentication_username_password
;
356 m_state_name
[ 8] = wxT("process_send_authentication_username_password");
357 m_process_state
[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password
;
358 m_state_name
[ 9] = wxT("process_receive_authentication_username_password");
359 m_process_state
[10] = &CSocks5StateMachine::process_process_authentication_username_password
;
360 m_state_name
[10] = wxT("process_process_authentication_username_password");
361 m_process_state
[11] = &CSocks5StateMachine::process_send_command_request
;
362 m_state_name
[11] = wxT("process_send_command_request");
363 m_process_state
[12] = &CSocks5StateMachine::process_receive_command_reply
;
364 m_state_name
[12] = wxT("process_receive_command_reply");
365 m_process_state
[13] = &CSocks5StateMachine::process_process_command_reply
;
366 m_state_name
[13] = wxT("process_process_command_reply");
369 void CSocks5StateMachine::process_state(t_sm_state state
, bool entry
)
371 /* Ok, the syntax is terrible, but this is correct. This is a
372 * pointer to a member function. No C equivalent for that. */
373 (this->*m_process_state
[state
])(entry
);
378 case SOCKS5_STATE_START
:
379 case SOCKS5_STATE_END
:
380 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
381 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
382 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
383 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
388 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
389 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
390 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
391 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
395 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
396 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
397 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
398 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
404 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
406 AddDebugLogLineM(false, logProxy
,
407 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
413 * Code this such that the next state is only entered when it is able to
414 * perform the operation (read or write). State processing will assume
415 * that it can read or write upon entry of the state. This is done using
416 * CanSend() and CanReceive(). On daemon, these functions always return
417 * true, because sockets are blocking.
419 t_sm_state
CSocks5StateMachine::next_state(t_sm_event event
)
421 // Default is stay in current state
422 t_sm_state ret
= HandleEvent(event
);
423 switch (GetState()) {
424 case SOCKS5_STATE_START
:
425 if (m_isConnected
&& !m_isLost
&& CanSend()) {
426 ret
= SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
;
430 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
432 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
;
436 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
437 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
;
440 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
443 switch (m_lastReply
) {
444 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
:
445 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
448 case SOCKS5_AUTH_METHOD_GSSAPI
:
449 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
;
452 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
:
453 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
;
456 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS
:
458 ret
= SOCKS5_STATE_END
;
462 AddDebugLogLineM(false, logProxy
, wxT("Cant send"));
465 ret
= SOCKS5_STATE_END
;
469 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
472 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
;
475 ret
= SOCKS5_STATE_END
;
479 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
482 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
;
485 ret
= SOCKS5_STATE_END
;
489 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
490 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
;
493 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
494 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
;
497 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
498 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
501 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
504 ret
= SOCKS5_STATE_END
;
508 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
511 ret
= SOCKS5_STATE_RECEIVE_COMMAND_REPLY
;
514 ret
= SOCKS5_STATE_END
;
518 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
519 ret
= SOCKS5_STATE_PROCESS_COMMAND_REPLY
;
522 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
523 ret
= SOCKS5_STATE_END
;
526 case SOCKS5_STATE_END
:
535 * So, this is how you do it: the state machine is clocked by the events
536 * that happen inside the event handler. You can add a dummy event whenever
537 * you see that the system will not generate an event. But don't add dummy
538 * events before reads, reads should only be performed after input events.
540 * Maybe it makes sense to add a dummy event before a read if there is no
541 * state change (wait state).
543 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
544 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
545 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
546 * event will be generated. If you feel you will need more clocks than these, use
547 * AddDummyEvent(), but I suggest you review your state machine design first.
549 void CSocks5StateMachine::process_start(bool entry
)
556 void CSocks5StateMachine::process_end(bool)
561 void CSocks5StateMachine::process_send_query_authentication_method(bool entry
)
564 // Prepare the authentication method negotiation packet
565 m_buffer
[0] = SOCKS5_VERSION
;
566 m_buffer
[1] = 2; // Number of supported methods
567 //m_buffer[1] = 3; // Number of supported methods
568 m_buffer
[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
;
569 m_buffer
[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
;
570 m_buffer
[4] = SOCKS5_AUTH_METHOD_GSSAPI
;
572 //m_packetLenght = 5;
574 // Send the authentication method negotiation packet
575 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
579 void CSocks5StateMachine::process_receive_authentication_method(bool entry
)
582 // Receive the method selection message
584 ProxyRead(*m_proxyClientSocket
, m_buffer
);
586 /* This is added because there will be no more input events. If the
587 * world was a nice place, we could think about joining the
588 * process_receive and the process_process states here, but some day
589 * we might have to deal with the fact that the i/o operation has been
590 * incomplete, and that we must finish our job the next time we enter
595 void CSocks5StateMachine::process_process_authentication_method(bool entry
)
598 m_lastReply
= m_buffer
[1];
599 m_ok
= m_ok
&& m_buffer
[0] == SOCKS5_VERSION
;
601 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
602 * once when you connect the socket, and after that, only after a
603 * wxSOCKET_WOULDBLOCK error happens. */
607 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
609 // TODO or not TODO? That is the question...
613 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
618 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
623 void CSocks5StateMachine::process_send_authentication_username_password(bool entry
)
626 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
627 unsigned char lenPassword
= m_proxyData
.m_password
.Len();
628 m_packetLenght
= 1 + 1 + lenUser
+ 1 + lenPassword
;
629 unsigned int offsetUser
= 2;
630 unsigned int offsetPassword
= offsetUser
+ lenUser
+ 1;
632 // Prepare username/password buffer
633 m_buffer
[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
;
634 m_buffer
[offsetUser
-1] = lenUser
;
635 memcpy(m_buffer
+offsetUser
, unicode2char(m_proxyData
.m_userName
),
637 m_buffer
[offsetPassword
-1] = lenPassword
;
638 memcpy(m_buffer
+offsetPassword
, unicode2char(m_proxyData
.m_password
),
641 // Send the username/password packet
642 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
646 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry
)
649 // Receive the server's authentication response
651 ProxyRead(*m_proxyClientSocket
, m_buffer
);
656 void CSocks5StateMachine::process_process_authentication_username_password(bool entry
)
659 // Process the server's reply
660 m_lastReply
= m_buffer
[1];
662 m_buffer
[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
&&
663 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
668 void CSocks5StateMachine::process_send_command_request(bool entry
)
671 // Prepare the request command buffer
672 m_buffer
[0] = SOCKS5_VERSION
;
673 switch (m_proxyCommand
) {
674 case PROXY_CMD_CONNECT
:
675 m_buffer
[1] = SOCKS5_CMD_CONNECT
;
679 m_buffer
[1] = SOCKS5_CMD_BIND
;
682 case PROXY_CMD_UDP_ASSOCIATE
:
683 m_buffer
[1] = SOCKS5_CMD_UDP_ASSOCIATE
;
686 m_buffer
[2] = SOCKS5_RSV
;
687 m_buffer
[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
688 PokeUInt32( m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()) );
689 RawPokeUInt16( m_buffer
+8, ENDIAN_HTONS( m_peerAddress
->Service() ) );
691 // Send the command packet
693 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
697 void CSocks5StateMachine::process_receive_command_reply(bool entry
)
700 // The minimum number of bytes to read is 10 in the case of
701 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
703 ProxyRead(*m_proxyClientSocket
, m_buffer
);
708 void CSocks5StateMachine::process_process_command_reply(bool entry
)
711 m_lastReply
= m_buffer
[1];
712 unsigned char addressType
= m_buffer
[3];
713 // Process the server's reply
715 m_buffer
[0] == SOCKS5_VERSION
&&
716 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
719 unsigned int portOffset
= 0;
720 switch(addressType
) {
721 case SOCKS5_ATYP_IPV4_ADDRESS
:
723 const unsigned int addrOffset
= 4;
725 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
726 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
729 case SOCKS5_ATYP_DOMAINNAME
:
731 // Read the domain name
732 const unsigned int addrOffset
= 5;
733 portOffset
= 10 + m_buffer
[4];
734 char c
= m_buffer
[portOffset
];
735 m_buffer
[portOffset
] = 0;
736 m_proxyBoundAddressIPV4
.Hostname(
737 char2unicode(m_buffer
+addrOffset
));
738 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
739 m_buffer
[portOffset
] = c
;
742 case SOCKS5_ATYP_IPV6_ADDRESS
:
746 // IPV6 not yet implemented in wx
747 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
748 // *((uint128 *)(m_buffer+addrOffset)) ));
749 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
754 // Set the packet length at last
755 m_packetLenght
= portOffset
+ 2;
757 m_proxyBoundAddress
->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer
+portOffset
) ) );
763 //------------------------------------------------------------------------------
764 // CSocks4StateMachine
765 //------------------------------------------------------------------------------
767 CSocks4StateMachine::CSocks4StateMachine(
768 const CProxyData
&proxyData
,
769 CProxyCommand proxyCommand
)
772 wxString(wxT("Socks4")), SOCKS4_MAX_STATES
, proxyData
, proxyCommand
)
774 m_process_state
[0] = &CSocks4StateMachine::process_start
;
775 m_state_name
[0] = wxT("process_start");
776 m_process_state
[1] = &CSocks4StateMachine::process_end
;
777 m_state_name
[1] = wxT("process_end");
778 m_process_state
[2] = &CSocks4StateMachine::process_send_command_request
;
779 m_state_name
[2] = wxT("process_send_command_request");
780 m_process_state
[3] = &CSocks4StateMachine::process_receive_command_reply
;
781 m_state_name
[3] = wxT("process_receive_command_reply");
782 m_process_state
[4] = &CSocks4StateMachine::process_process_command_reply
;
783 m_state_name
[4] = wxT("process_process_command_reply");
786 void CSocks4StateMachine::process_state(t_sm_state state
, bool entry
)
788 (this->*m_process_state
[state
])(entry
);
793 case SOCKS4_STATE_START
:
794 case SOCKS4_STATE_END
:
795 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
800 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
804 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
810 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
812 AddDebugLogLineM(false, logProxy
,
813 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
818 t_sm_state
CSocks4StateMachine::next_state(t_sm_event event
)
820 // Default is stay in current state
821 t_sm_state ret
= HandleEvent(event
);
822 switch (GetState()) {
823 case SOCKS4_STATE_START
:
824 if (m_isConnected
&& !m_isLost
&& CanSend()) {
825 ret
= SOCKS4_STATE_SEND_COMMAND_REQUEST
;
829 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
832 ret
= SOCKS4_STATE_RECEIVE_COMMAND_REPLY
;
835 ret
= SOCKS4_STATE_END
;
839 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
840 ret
= SOCKS4_STATE_PROCESS_COMMAND_REPLY
;
843 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
844 ret
= SOCKS4_STATE_END
;
847 case SOCKS4_STATE_END
:
855 void CSocks4StateMachine::process_start(bool entry
)
862 void CSocks4StateMachine::process_end(bool)
867 void CSocks4StateMachine::process_send_command_request(bool entry
)
870 // Prepare the request command buffer
871 m_buffer
[0] = SOCKS4_VERSION
;
872 switch (m_proxyCommand
) {
873 case PROXY_CMD_CONNECT
:
874 m_buffer
[1] = SOCKS4_CMD_CONNECT
;
878 m_buffer
[1] = SOCKS4_CMD_BIND
;
881 case PROXY_CMD_UDP_ASSOCIATE
:
886 RawPokeUInt16(m_buffer
+2, ENDIAN_HTONS(m_peerAddress
->Service()));
887 // Special processing for SOCKS4a
888 switch (m_proxyData
.m_proxyType
) {
890 PokeUInt32(m_buffer
+4, StringIPtoUint32(wxT("0.0.0.1")));
894 PokeUInt32(m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()));
897 // Common processing for SOCKS4/SOCKS4a
898 unsigned int offsetUser
= 8;
899 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
900 memcpy(m_buffer
+ offsetUser
,
901 unicode2char(m_proxyData
.m_userName
), lenUser
);
902 m_buffer
[offsetUser
+ lenUser
] = 0;
903 // Special processing for SOCKS4a
904 switch (m_proxyData
.m_proxyType
) {
905 case PROXY_SOCKS4a
: {
906 unsigned int offsetDomain
= offsetUser
+ lenUser
+ 1;
907 unsigned char lenDomain
= m_peerAddress
->Hostname().Len();
908 memcpy(m_buffer
+ offsetDomain
,
909 unicode2char(m_peerAddress
->Hostname()), lenDomain
);
910 m_buffer
[offsetDomain
+ lenDomain
] = 0;
911 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1 + lenDomain
+ 1;
916 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1;
919 // Send the command packet
920 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
924 void CSocks4StateMachine::process_receive_command_reply(bool entry
)
927 // Receive the server's reply
929 ProxyRead(*m_proxyClientSocket
, m_buffer
);
934 void CSocks4StateMachine::process_process_command_reply(bool entry
)
937 m_lastReply
= m_buffer
[1];
939 // Process the server's reply
941 m_buffer
[0] == SOCKS4_REPLY_CODE
&&
942 m_buffer
[1] == SOCKS4_REPLY_GRANTED
;
945 const unsigned int portOffset
= 2;
946 m_ok
= m_proxyBoundAddressIPV4
.Service(ENDIAN_NTOHS(
947 RawPeekUInt16( m_buffer
+portOffset
) ) );
949 const unsigned int addrOffset
= 4;
951 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
952 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
958 //------------------------------------------------------------------------------
960 //------------------------------------------------------------------------------
962 CHttpStateMachine::CHttpStateMachine(
963 const CProxyData
&proxyData
,
964 CProxyCommand proxyCommand
)
967 wxString(wxT("Http")), HTTP_MAX_STATES
, proxyData
, proxyCommand
)
969 m_process_state
[0] = &CHttpStateMachine::process_start
;
970 m_state_name
[0] = wxT("process_start");
971 m_process_state
[1] = &CHttpStateMachine::process_end
;
972 m_state_name
[1] = wxT("process_end");
973 m_process_state
[2] = &CHttpStateMachine::process_send_command_request
;
974 m_state_name
[2] = wxT("process_send_command_request");
975 m_process_state
[3] = &CHttpStateMachine::process_receive_command_reply
;
976 m_state_name
[3] = wxT("process_receive_command_reply");
977 m_process_state
[4] = &CHttpStateMachine::process_process_command_reply
;
978 m_state_name
[4] = wxT("process_process_command_reply");
981 void CHttpStateMachine::process_state(t_sm_state state
, bool entry
)
983 (this->*m_process_state
[state
])(entry
);
988 case HTTP_STATE_START
:
990 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
995 case HTTP_STATE_SEND_COMMAND_REQUEST
:
999 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1005 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
1007 AddDebugLogLineM(false, logProxy
,
1008 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
1013 t_sm_state
CHttpStateMachine::next_state(t_sm_event event
)
1015 // Default is stay in current state
1016 t_sm_state ret
= HandleEvent(event
);
1017 switch (GetState()) {
1018 case HTTP_STATE_START
:
1019 if (m_isConnected
&& !m_isLost
&& CanSend()) {
1020 ret
= HTTP_STATE_SEND_COMMAND_REQUEST
;
1024 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1027 ret
= HTTP_STATE_RECEIVE_COMMAND_REPLY
;
1030 ret
= HTTP_STATE_END
;
1034 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1035 ret
= HTTP_STATE_PROCESS_COMMAND_REPLY
;
1038 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1039 ret
= HTTP_STATE_END
;
1042 case HTTP_STATE_END
:
1050 void CHttpStateMachine::process_start(bool entry
)
1057 void CHttpStateMachine::process_end(bool)
1062 void CHttpStateMachine::process_send_command_request(bool entry
)
1065 // Prepare the request command buffer
1066 wxString ip
= m_peerAddress
->IPAddress();
1067 uint16 port
= m_peerAddress
->Service();
1069 wxString userPassEncoded
;
1070 if (m_proxyData
.m_enablePassword
) {
1071 userPass
= m_proxyData
.m_userName
+ wxT(":") + m_proxyData
.m_password
;
1073 EncodeBase64(unicode2char(userPass
), PROXY_BUFFER_SIZE
);
1077 switch (m_proxyCommand
) {
1078 case PROXY_CMD_CONNECT
:
1080 wxT("CONNECT ") << ip
<< wxT(":") << port
<< wxT(" HTTP/1.1\r\n") <<
1081 wxT("Host: ") << ip
<< wxT(":") << port
<< wxT("\r\n");
1082 if (m_proxyData
.m_enablePassword
) {
1084 wxT("Authorization: Basic ") << userPassEncoded
<< wxT("\r\n") <<
1085 wxT("Proxy-Authorization: Basic ") << userPassEncoded
<< wxT("\r\n");
1091 case PROXY_CMD_BIND
:
1095 case PROXY_CMD_UDP_ASSOCIATE
:
1100 // Send the command packet
1101 m_packetLenght
= msg
.Len();
1102 memcpy(m_buffer
, unicode2char(msg
), m_packetLenght
+1);
1103 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
1107 void CHttpStateMachine::process_receive_command_reply(bool entry
)
1110 // Receive the server's reply -- Use a large number, but don't
1111 // Expect to get it all. HTTP protocol does not have a fixed length.
1112 m_packetLenght
= PROXY_BUFFER_SIZE
;
1113 ProxyRead(*m_proxyClientSocket
, m_buffer
);
1119 * HTTP Proxy server response should be something like:
1120 * "HTTP/1.1 200 Connection established\r\n\r\n"
1121 * but that may vary. The important thing is the "200"
1122 * code, that means success.
1124 static const char HTTP_AUTH_RESPONSE
[] = "HTTP/";
1125 static const int HTTP_AUTH_RESPONSE_LENGHT
= strlen(HTTP_AUTH_RESPONSE
);
1126 void CHttpStateMachine::process_process_command_reply(bool entry
)
1129 // The position of the first space in the buffer
1131 while (m_buffer
[i
] == ' ') {
1134 // Process the server's reply
1135 m_ok
= !memcmp(m_buffer
+ 0, HTTP_AUTH_RESPONSE
, HTTP_AUTH_RESPONSE_LENGHT
) &&
1136 !memcmp(m_buffer
+ i
, "200", 3);
1141 //------------------------------------------------------------------------------
1143 //------------------------------------------------------------------------------
1145 CProxySocket::CProxySocket(
1146 wxSocketFlags flags
,
1147 const CProxyData
*proxyData
,
1148 CProxyCommand proxyCommand
,
1149 CDatagramSocketProxy
*udpSocket
)
1151 wxSocketClient(flags
),
1152 m_proxyStateMachine(NULL
),
1153 m_udpSocket(udpSocket
),
1154 m_socketEventHandler(NULL
),
1155 m_socketEventHandlerId(0),
1156 m_savedSocketEventHandler(NULL
),
1157 m_savedSocketEventHandlerId(0)
1159 SetProxyData(proxyData
);
1161 switch (m_proxyData
.m_proxyType
) {
1166 m_proxyStateMachine
=
1167 new CSocks5StateMachine(*proxyData
, proxyCommand
);
1172 m_proxyStateMachine
=
1173 new CSocks4StateMachine(*proxyData
, proxyCommand
);
1177 m_proxyStateMachine
=
1178 new CHttpStateMachine(*proxyData
, proxyCommand
);
1187 CProxySocket::~CProxySocket()
1189 delete m_proxyStateMachine
;
1192 void CProxySocket::SetProxyData(const CProxyData
*proxyData
)
1194 m_useProxy
= proxyData
!= NULL
&& proxyData
->m_proxyEnable
;
1196 m_proxyData
= *proxyData
;
1197 m_proxyAddress
.Hostname(m_proxyData
.m_proxyHostName
);
1198 m_proxyAddress
.Service(m_proxyData
.m_proxyPort
);
1200 m_proxyData
.Clear();
1204 bool CProxySocket::Start(const wxIPaddress
&peerAddress
)
1207 // Important note! SaveState()/RestoreState() DO NOT save/restore
1208 // the event handler. The method SaveEventHandler() has been created
1211 SetEventHandler(g_proxyEventHandler
, ID_PROXY_SOCKET_EVENT
);
1213 wxSOCKET_CONNECTION_FLAG
|
1214 wxSOCKET_INPUT_FLAG
|
1215 wxSOCKET_OUTPUT_FLAG
|
1216 wxSOCKET_LOST_FLAG
);
1218 Connect(m_proxyAddress
, false);
1219 SetFlags(wxSOCKET_NONE
);
1220 bool ok
= m_proxyStateMachine
->Start(peerAddress
, this);
1225 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand
) const
1229 switch (m_proxyData
.m_proxyType
) {
1235 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1236 proxyCommand
== PROXY_CMD_BIND
||
1237 proxyCommand
== PROXY_CMD_UDP_ASSOCIATE
;
1242 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1243 proxyCommand
== PROXY_CMD_BIND
;
1247 ret
= proxyCommand
== PROXY_CMD_CONNECT
;
1254 //------------------------------------------------------------------------------
1255 // CSocketClientProxy
1256 //------------------------------------------------------------------------------
1258 CSocketClientProxy::CSocketClientProxy(
1259 wxSocketFlags flags
,
1260 const CProxyData
*proxyData
)
1262 CProxySocket(flags
, proxyData
, PROXY_CMD_CONNECT
)
1266 bool CSocketClientProxy::Connect(wxIPaddress
&address
, bool wait
)
1268 wxMutexLocker
lock(m_socketLocker
);
1271 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT
)) {
1272 ok
= Start(address
);
1274 ok
= wxSocketClient::Connect(address
, wait
);
1280 CSocketClientProxy
& CSocketClientProxy::Read(void *buffer
, wxUint32 nbytes
)
1282 wxMutexLocker
lock(m_socketLocker
);
1283 CProxySocket::Read(buffer
, nbytes
);
1289 CSocketClientProxy
& CSocketClientProxy::Write(const void *buffer
, wxUint32 nbytes
)
1291 wxMutexLocker
lock(m_socketLocker
);
1292 CProxySocket::Write(buffer
, nbytes
);
1297 //------------------------------------------------------------------------------
1298 // CSocketServerProxy
1299 //------------------------------------------------------------------------------
1301 CSocketServerProxy::CSocketServerProxy(
1302 wxIPaddress
&address
,
1303 wxSocketFlags flags
,
1306 wxSocketServer(address
, flags
)
1308 /* Maybe some day when socks6 is out... :) */
1311 CSocketServerProxy
& CSocketServerProxy::Read(void *buffer
, wxUint32 nbytes
)
1313 wxMutexLocker
lock(m_socketLocker
);
1314 wxSocketServer::Read(buffer
, nbytes
);
1319 CSocketServerProxy
& CSocketServerProxy::Write(const void *buffer
, wxUint32 nbytes
)
1321 wxMutexLocker
lock(m_socketLocker
);
1322 wxSocketServer::Write(buffer
, nbytes
);
1327 //------------------------------------------------------------------------------
1328 // CDatagramSocketProxy
1329 //------------------------------------------------------------------------------
1331 CDatagramSocketProxy::CDatagramSocketProxy(
1332 wxIPaddress
&address
, wxSocketFlags flags
, const CProxyData
*proxyData
)
1334 wxDatagramSocket(address
, flags
),
1335 m_proxyTCPSocket(wxSOCKET_NOWAIT
, proxyData
, PROXY_CMD_UDP_ASSOCIATE
, this)
1337 m_udpSocketOk
= false;
1338 if ( m_proxyTCPSocket
.GetUseProxy() &&
1339 m_proxyTCPSocket
.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE
)) {
1340 m_proxyTCPSocket
.Start(address
);
1343 m_lastUDPOperation
= UDP_OPERATION_NONE
;
1346 CDatagramSocketProxy::~CDatagramSocketProxy()
1349 // "A UDP association terminates when the TCP connection that the
1350 // UDP ASSOCIATE request arrived terminates."
1353 wxDatagramSocket
&CDatagramSocketProxy::RecvFrom(
1354 wxSockAddress
&addr
, void* buf
, wxUint32 nBytes
)
1356 wxMutexLocker
lock(m_socketLocker
);
1357 m_lastUDPOperation
= UDP_OPERATION_RECV_FROM
;
1358 if (m_proxyTCPSocket
.GetUseProxy()) {
1359 if (m_udpSocketOk
) {
1360 char *bufUDP
= NULL
;
1361 if (nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
> PROXY_BUFFER_SIZE
) {
1362 bufUDP
= new char[nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
];
1364 bufUDP
= m_proxyTCPSocket
.GetBuffer();
1366 wxDatagramSocket::RecvFrom(
1367 m_proxyTCPSocket
.GetProxyBoundAddress(),
1368 bufUDP
, nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
);
1369 unsigned int offset
;
1370 switch (m_proxyTCPSocket
.GetBuffer()[3]) {
1371 case SOCKS5_ATYP_IPV4_ADDRESS
: {
1372 offset
= PROXY_UDP_OVERHEAD_IPV4
;
1374 amuleIPV4Address
&a
= dynamic_cast<amuleIPV4Address
&>(addr
);
1375 a
.Hostname( PeekUInt32( m_proxyTCPSocket
.GetBuffer()+4 ) );
1376 a
.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket
.GetBuffer()+8) ) );
1377 } catch (const std::bad_cast
& WXUNUSED(e
)) {
1378 AddDebugLogLineM(false, logProxy
,
1379 wxT("(2)bad_cast exception!"));
1385 case SOCKS5_ATYP_DOMAINNAME
:
1386 offset
= PROXY_UDP_OVERHEAD_DOMAIN_NAME
;
1389 case SOCKS5_ATYP_IPV6_ADDRESS
:
1390 offset
= PROXY_UDP_OVERHEAD_IPV6
;
1398 memcpy(buf
, bufUDP
+ offset
, nBytes
);
1399 // Uncomment here to see the buffer contents on console
1400 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1402 /* Only delete buffer if it was dynamically created */
1403 if (bufUDP
!= m_proxyTCPSocket
.GetBuffer()) {
1404 /* We should use a fixed buffer to avoid
1405 * new/delete it all the time.
1406 * I need an upper bound */
1409 /* There is still one problem pending, fragmentation.
1410 * Either we support it or we have to drop fragmented
1411 * messages. I vote for drop :)
1415 wxDatagramSocket::RecvFrom(addr
, buf
, nBytes
);
1421 wxDatagramSocket
&CDatagramSocketProxy::SendTo(
1422 wxIPaddress
&addr
, const void* buf
, wxUint32 nBytes
)
1424 wxMutexLocker
lock(m_socketLocker
);
1425 m_lastUDPOperation
= UDP_OPERATION_SEND_TO
;
1426 m_lastUDPOverhead
= PROXY_UDP_OVERHEAD_IPV4
;
1427 if (m_proxyTCPSocket
.GetUseProxy()) {
1428 if (m_udpSocketOk
) {
1429 m_proxyTCPSocket
.GetBuffer()[0] = SOCKS5_RSV
; // Reserved
1430 m_proxyTCPSocket
.GetBuffer()[1] = SOCKS5_RSV
; // Reserved
1431 m_proxyTCPSocket
.GetBuffer()[2] = 0; // FRAG
1432 m_proxyTCPSocket
.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
1433 PokeUInt32( m_proxyTCPSocket
.GetBuffer()+4, StringIPtoUint32(addr
.IPAddress()));
1434 RawPokeUInt16( m_proxyTCPSocket
.GetBuffer()+8, ENDIAN_HTONS( addr
.Service() ) );
1435 memcpy(m_proxyTCPSocket
.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4
, buf
, nBytes
);
1436 nBytes
+= PROXY_UDP_OVERHEAD_IPV4
;
1437 wxDatagramSocket::SendTo(
1438 m_proxyTCPSocket
.GetProxyBoundAddress(),
1439 m_proxyTCPSocket
.GetBuffer(), nBytes
);
1440 // Uncomment here to see the buffer contents on console
1441 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1444 wxDatagramSocket::SendTo(addr
, buf
, nBytes
);
1450 wxUint32
CDatagramSocketProxy::LastCount(void) const
1454 if (m_proxyTCPSocket
.GetUseProxy()) {
1455 switch (m_lastUDPOperation
) {
1456 case UDP_OPERATION_RECV_FROM
:
1457 case UDP_OPERATION_SEND_TO
:
1458 ret
= Ok() ? wxDatagramSocket::LastCount() - m_lastUDPOverhead
: 0;
1461 case UDP_OPERATION_NONE
:
1468 ret
= wxDatagramSocket::LastCount();
1474 #endif // CLIENT_GUI
1476 /******************************************************************************/
1477 // File_checked_for_headers