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
27 #include "Proxy.h" /* for Interface */
29 #include <common/EventIDs.h>
31 #include "ArchSpecific.h" /* for ENDIAN_HTONS() */
32 #include "Logger.h" /* for AddDebugLogLineN */
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 AddDebugLogLineN(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 AddDebugLogLineN(logProxy
, wxT("Connection event"));
194 m_isConnected
= true;
198 AddDebugLogLineN(logProxy
, wxT("Input event"));
202 case wxSOCKET_OUTPUT
:
203 AddDebugLogLineN(logProxy
, wxT("Output event"));
208 AddDebugLogLineN(logProxy
, wxT("Lost connection event"));
214 AddDebugLogLineN(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 a 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 bool CProxyStateMachine::CanReceive() const
331 bool CProxyStateMachine::CanSend() const
340 //------------------------------------------------------------------------------
341 // CSocks5StateMachine
342 //------------------------------------------------------------------------------
345 * The state machine constructor must initialize the array of pointer to member
346 * functions. Don't waste you time trying to statically initialize this, pointer
347 * to member functions require an object to operate on, so this array must be
348 * initialized at run time.
350 CSocks5StateMachine::CSocks5StateMachine(
351 const CProxyData
&proxyData
,
352 CProxyCommand proxyCommand
)
355 wxString(wxT("Socks5")), SOCKS5_MAX_STATES
, proxyData
, proxyCommand
)
357 m_process_state
[ 0] = &CSocks5StateMachine::process_start
;
358 m_state_name
[ 0] = wxT("process_start");
359 m_process_state
[ 1] = &CSocks5StateMachine::process_end
;
360 m_state_name
[ 1] = wxT("process_end");
361 m_process_state
[ 2] = &CSocks5StateMachine::process_send_query_authentication_method
;
362 m_state_name
[ 2] = wxT("process_send_query_authentication_method");
363 m_process_state
[ 3] = &CSocks5StateMachine::process_receive_authentication_method
;
364 m_state_name
[ 3] = wxT("process_receive_authentication_method");
365 m_process_state
[ 4] = &CSocks5StateMachine::process_process_authentication_method
;
366 m_state_name
[ 4] = wxT("process_process_authentication_method");
367 m_process_state
[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi
;
368 m_state_name
[ 5] = wxT("process_send_authentication_gssapi");
369 m_process_state
[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi
;
370 m_state_name
[ 6] = wxT("process_receive_authentication_gssapi");
371 m_process_state
[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi
;
372 m_state_name
[ 7] = wxT("process_process_authentication_gssapi");
373 m_process_state
[ 8] = &CSocks5StateMachine::process_send_authentication_username_password
;
374 m_state_name
[ 8] = wxT("process_send_authentication_username_password");
375 m_process_state
[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password
;
376 m_state_name
[ 9] = wxT("process_receive_authentication_username_password");
377 m_process_state
[10] = &CSocks5StateMachine::process_process_authentication_username_password
;
378 m_state_name
[10] = wxT("process_process_authentication_username_password");
379 m_process_state
[11] = &CSocks5StateMachine::process_send_command_request
;
380 m_state_name
[11] = wxT("process_send_command_request");
381 m_process_state
[12] = &CSocks5StateMachine::process_receive_command_reply
;
382 m_state_name
[12] = wxT("process_receive_command_reply");
383 m_process_state
[13] = &CSocks5StateMachine::process_process_command_reply
;
384 m_state_name
[13] = wxT("process_process_command_reply");
387 void CSocks5StateMachine::process_state(t_sm_state state
, bool entry
)
389 /* Ok, the syntax is terrible, but this is correct. This is a
390 * pointer to a member function. No C equivalent for that. */
391 (this->*m_process_state
[state
])(entry
);
396 case SOCKS5_STATE_START
:
397 case SOCKS5_STATE_END
:
398 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
399 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
400 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
401 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
406 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
407 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
408 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
409 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
413 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
414 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
415 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
416 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
422 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
424 AddDebugLogLineN(logProxy
,
425 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
431 * Code this such that the next state is only entered when it is able to
432 * perform the operation (read or write). State processing will assume
433 * that it can read or write upon entry of the state. This is done using
434 * CanSend() and CanReceive(). On daemon, these functions always return
435 * true, because sockets are blocking.
437 t_sm_state
CSocks5StateMachine::next_state(t_sm_event event
)
439 // Default is stay in current state
440 t_sm_state ret
= HandleEvent(event
);
441 switch (GetState()) {
442 case SOCKS5_STATE_START
:
443 if (m_isConnected
&& !m_isLost
&& CanSend()) {
444 ret
= SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
;
448 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
:
450 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
;
454 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
:
455 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
;
458 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
:
461 switch (m_lastReply
) {
462 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
:
463 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
466 case SOCKS5_AUTH_METHOD_GSSAPI
:
467 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
;
470 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
:
471 ret
= SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
;
474 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS
:
476 ret
= SOCKS5_STATE_END
;
480 AddDebugLogLineN(logProxy
, wxT("Can't send"));
483 ret
= SOCKS5_STATE_END
;
487 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
:
490 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
;
493 ret
= SOCKS5_STATE_END
;
497 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
:
500 ret
= SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
;
503 ret
= SOCKS5_STATE_END
;
507 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
:
508 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
;
511 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
:
512 ret
= SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
;
515 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
:
516 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
:
519 ret
= SOCKS5_STATE_SEND_COMMAND_REQUEST
;
522 ret
= SOCKS5_STATE_END
;
526 case SOCKS5_STATE_SEND_COMMAND_REQUEST
:
529 ret
= SOCKS5_STATE_RECEIVE_COMMAND_REPLY
;
532 ret
= SOCKS5_STATE_END
;
536 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY
:
537 ret
= SOCKS5_STATE_PROCESS_COMMAND_REPLY
;
540 case SOCKS5_STATE_PROCESS_COMMAND_REPLY
:
541 ret
= SOCKS5_STATE_END
;
544 case SOCKS5_STATE_END
:
553 * So, this is how you do it: the state machine is clocked by the events
554 * that happen inside the event handler. You can add a dummy event whenever
555 * you see that the system will not generate an event. But don't add dummy
556 * events before reads, reads should only be performed after input events.
558 * Maybe it makes sense to add a dummy event before a read if there is no
559 * state change (wait state).
561 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
562 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
563 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
564 * event will be generated. If you feel you will need more clocks than these, use
565 * AddDummyEvent(), but I suggest you review your state machine design first.
567 void CSocks5StateMachine::process_start(bool entry
)
574 void CSocks5StateMachine::process_end(bool)
579 void CSocks5StateMachine::process_send_query_authentication_method(bool entry
)
582 // Prepare the authentication method negotiation packet
583 m_buffer
[0] = SOCKS5_VERSION
;
584 m_buffer
[1] = 2; // Number of supported methods
585 //m_buffer[1] = 3; // Number of supported methods
586 m_buffer
[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
;
587 m_buffer
[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
;
588 m_buffer
[4] = SOCKS5_AUTH_METHOD_GSSAPI
;
590 //m_packetLenght = 5;
592 // Send the authentication method negotiation packet
593 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
597 void CSocks5StateMachine::process_receive_authentication_method(bool entry
)
600 // Receive the method selection message
602 ProxyRead(*m_proxyClientSocket
, m_buffer
);
604 /* This is added because there will be no more input events. If the
605 * world was a nice place, we could think about joining the
606 * process_receive and the process_process states here, but some day
607 * we might have to deal with the fact that the i/o operation has been
608 * incomplete, and that we must finish our job the next time we enter
613 void CSocks5StateMachine::process_process_authentication_method(bool entry
)
616 m_lastReply
= m_buffer
[1];
617 m_ok
= m_ok
&& m_buffer
[0] == SOCKS5_VERSION
;
619 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
620 * once when you connect the socket, and after that, only after a
621 * wxSOCKET_WOULDBLOCK error happens. */
625 void CSocks5StateMachine::process_send_authentication_gssapi(bool)
627 // TODO or not TODO? That is the question...
631 void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
636 void CSocks5StateMachine::process_process_authentication_gssapi(bool)
641 void CSocks5StateMachine::process_send_authentication_username_password(bool entry
)
644 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
645 unsigned char lenPassword
= m_proxyData
.m_password
.Len();
646 m_packetLenght
= 1 + 1 + lenUser
+ 1 + lenPassword
;
647 unsigned int offsetUser
= 2;
648 unsigned int offsetPassword
= offsetUser
+ lenUser
+ 1;
650 // Prepare username/password buffer
651 m_buffer
[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
;
652 m_buffer
[offsetUser
-1] = lenUser
;
653 memcpy(m_buffer
+offsetUser
, unicode2char(m_proxyData
.m_userName
),
655 m_buffer
[offsetPassword
-1] = lenPassword
;
656 memcpy(m_buffer
+offsetPassword
, unicode2char(m_proxyData
.m_password
),
659 // Send the username/password packet
660 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
664 void CSocks5StateMachine::process_receive_authentication_username_password(bool entry
)
667 // Receive the server's authentication response
669 ProxyRead(*m_proxyClientSocket
, m_buffer
);
674 void CSocks5StateMachine::process_process_authentication_username_password(bool entry
)
677 // Process the server's reply
678 m_lastReply
= m_buffer
[1];
680 m_buffer
[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
&&
681 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
686 void CSocks5StateMachine::process_send_command_request(bool entry
)
689 // Prepare the request command buffer
690 m_buffer
[0] = SOCKS5_VERSION
;
691 switch (m_proxyCommand
) {
692 case PROXY_CMD_CONNECT
:
693 m_buffer
[1] = SOCKS5_CMD_CONNECT
;
697 m_buffer
[1] = SOCKS5_CMD_BIND
;
700 case PROXY_CMD_UDP_ASSOCIATE
:
701 m_buffer
[1] = SOCKS5_CMD_UDP_ASSOCIATE
;
704 m_buffer
[2] = SOCKS5_RSV
;
705 m_buffer
[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
706 PokeUInt32( m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()) );
707 RawPokeUInt16( m_buffer
+8, ENDIAN_HTONS( m_peerAddress
->Service() ) );
709 // Send the command packet
711 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
715 void CSocks5StateMachine::process_receive_command_reply(bool entry
)
718 // The minimum number of bytes to read is 10 in the case of
719 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
721 ProxyRead(*m_proxyClientSocket
, m_buffer
);
726 void CSocks5StateMachine::process_process_command_reply(bool entry
)
729 m_lastReply
= m_buffer
[1];
730 unsigned char addressType
= m_buffer
[3];
731 // Process the server's reply
733 m_buffer
[0] == SOCKS5_VERSION
&&
734 m_buffer
[1] == SOCKS5_REPLY_SUCCEED
;
737 unsigned int portOffset
= 0;
738 switch(addressType
) {
739 case SOCKS5_ATYP_IPV4_ADDRESS
:
741 const unsigned int addrOffset
= 4;
743 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
744 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
747 case SOCKS5_ATYP_DOMAINNAME
:
749 // Read the domain name
750 const unsigned int addrOffset
= 5;
751 portOffset
= 10 + m_buffer
[4];
752 char c
= m_buffer
[portOffset
];
753 m_buffer
[portOffset
] = 0;
754 m_proxyBoundAddressIPV4
.Hostname(
755 char2unicode(m_buffer
+addrOffset
));
756 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
757 m_buffer
[portOffset
] = c
;
760 case SOCKS5_ATYP_IPV6_ADDRESS
:
764 // IPV6 not yet implemented in wx
765 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
766 // *((uint128 *)(m_buffer+addrOffset)) ));
767 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
772 // Set the packet length at last
773 m_packetLenght
= portOffset
+ 2;
775 m_proxyBoundAddress
->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer
+portOffset
) ) );
781 //------------------------------------------------------------------------------
782 // CSocks4StateMachine
783 //------------------------------------------------------------------------------
785 CSocks4StateMachine::CSocks4StateMachine(
786 const CProxyData
&proxyData
,
787 CProxyCommand proxyCommand
)
790 wxString(wxT("Socks4")), SOCKS4_MAX_STATES
, proxyData
, proxyCommand
)
792 m_process_state
[0] = &CSocks4StateMachine::process_start
;
793 m_state_name
[0] = wxT("process_start");
794 m_process_state
[1] = &CSocks4StateMachine::process_end
;
795 m_state_name
[1] = wxT("process_end");
796 m_process_state
[2] = &CSocks4StateMachine::process_send_command_request
;
797 m_state_name
[2] = wxT("process_send_command_request");
798 m_process_state
[3] = &CSocks4StateMachine::process_receive_command_reply
;
799 m_state_name
[3] = wxT("process_receive_command_reply");
800 m_process_state
[4] = &CSocks4StateMachine::process_process_command_reply
;
801 m_state_name
[4] = wxT("process_process_command_reply");
804 void CSocks4StateMachine::process_state(t_sm_state state
, bool entry
)
806 (this->*m_process_state
[state
])(entry
);
811 case SOCKS4_STATE_START
:
812 case SOCKS4_STATE_END
:
813 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
818 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
822 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
828 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
830 AddDebugLogLineN(logProxy
,
831 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
836 t_sm_state
CSocks4StateMachine::next_state(t_sm_event event
)
838 // Default is stay in current state
839 t_sm_state ret
= HandleEvent(event
);
840 switch (GetState()) {
841 case SOCKS4_STATE_START
:
842 if (m_isConnected
&& !m_isLost
&& CanSend()) {
843 ret
= SOCKS4_STATE_SEND_COMMAND_REQUEST
;
847 case SOCKS4_STATE_SEND_COMMAND_REQUEST
:
850 ret
= SOCKS4_STATE_RECEIVE_COMMAND_REPLY
;
853 ret
= SOCKS4_STATE_END
;
857 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY
:
858 ret
= SOCKS4_STATE_PROCESS_COMMAND_REPLY
;
861 case SOCKS4_STATE_PROCESS_COMMAND_REPLY
:
862 ret
= SOCKS4_STATE_END
;
865 case SOCKS4_STATE_END
:
873 void CSocks4StateMachine::process_start(bool entry
)
880 void CSocks4StateMachine::process_end(bool)
885 void CSocks4StateMachine::process_send_command_request(bool entry
)
888 // Prepare the request command buffer
889 m_buffer
[0] = SOCKS4_VERSION
;
890 switch (m_proxyCommand
) {
891 case PROXY_CMD_CONNECT
:
892 m_buffer
[1] = SOCKS4_CMD_CONNECT
;
896 m_buffer
[1] = SOCKS4_CMD_BIND
;
899 case PROXY_CMD_UDP_ASSOCIATE
:
904 RawPokeUInt16(m_buffer
+2, ENDIAN_HTONS(m_peerAddress
->Service()));
905 // Special processing for SOCKS4a
906 switch (m_proxyData
.m_proxyType
) {
908 PokeUInt32(m_buffer
+4, StringIPtoUint32(wxT("0.0.0.1")));
912 PokeUInt32(m_buffer
+4, StringIPtoUint32(m_peerAddress
->IPAddress()));
915 // Common processing for SOCKS4/SOCKS4a
916 unsigned int offsetUser
= 8;
917 unsigned char lenUser
= m_proxyData
.m_userName
.Len();
918 memcpy(m_buffer
+ offsetUser
,
919 unicode2char(m_proxyData
.m_userName
), lenUser
);
920 m_buffer
[offsetUser
+ lenUser
] = 0;
921 // Special processing for SOCKS4a
922 switch (m_proxyData
.m_proxyType
) {
923 case PROXY_SOCKS4a
: {
924 unsigned int offsetDomain
= offsetUser
+ lenUser
+ 1;
925 unsigned char lenDomain
= m_peerAddress
->Hostname().Len();
926 memcpy(m_buffer
+ offsetDomain
,
927 unicode2char(m_peerAddress
->Hostname()), lenDomain
);
928 m_buffer
[offsetDomain
+ lenDomain
] = 0;
929 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1 + lenDomain
+ 1;
934 m_packetLenght
= 1 + 1 + 2 + 4 + lenUser
+ 1;
937 // Send the command packet
938 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
942 void CSocks4StateMachine::process_receive_command_reply(bool entry
)
945 // Receive the server's reply
947 ProxyRead(*m_proxyClientSocket
, m_buffer
);
952 void CSocks4StateMachine::process_process_command_reply(bool entry
)
955 m_lastReply
= m_buffer
[1];
957 // Process the server's reply
959 m_buffer
[0] == SOCKS4_REPLY_CODE
&&
960 m_buffer
[1] == SOCKS4_REPLY_GRANTED
;
963 const unsigned int portOffset
= 2;
964 m_ok
= m_proxyBoundAddressIPV4
.Service(ENDIAN_NTOHS(
965 RawPeekUInt16( m_buffer
+portOffset
) ) );
967 const unsigned int addrOffset
= 4;
969 m_proxyBoundAddressIPV4
.Hostname( PeekUInt32( m_buffer
+addrOffset
) );
970 m_proxyBoundAddress
= &m_proxyBoundAddressIPV4
;
976 //------------------------------------------------------------------------------
978 //------------------------------------------------------------------------------
980 CHttpStateMachine::CHttpStateMachine(
981 const CProxyData
&proxyData
,
982 CProxyCommand proxyCommand
)
985 wxString(wxT("Http")), HTTP_MAX_STATES
, proxyData
, proxyCommand
)
987 m_process_state
[0] = &CHttpStateMachine::process_start
;
988 m_state_name
[0] = wxT("process_start");
989 m_process_state
[1] = &CHttpStateMachine::process_end
;
990 m_state_name
[1] = wxT("process_end");
991 m_process_state
[2] = &CHttpStateMachine::process_send_command_request
;
992 m_state_name
[2] = wxT("process_send_command_request");
993 m_process_state
[3] = &CHttpStateMachine::process_receive_command_reply
;
994 m_state_name
[3] = wxT("process_receive_command_reply");
995 m_process_state
[4] = &CHttpStateMachine::process_process_command_reply
;
996 m_state_name
[4] = wxT("process_process_command_reply");
999 void CHttpStateMachine::process_state(t_sm_state state
, bool entry
)
1001 (this->*m_process_state
[state
])(entry
);
1006 case HTTP_STATE_START
:
1007 case HTTP_STATE_END
:
1008 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1013 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1017 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1023 DumpMem(m_buffer
, n
, m_state_name
[state
], m_ok
);
1025 AddDebugLogLineN(logProxy
,
1026 wxString(wxT("wait state -- ")) << m_state_name
[state
]);
1031 t_sm_state
CHttpStateMachine::next_state(t_sm_event event
)
1033 // Default is stay in current state
1034 t_sm_state ret
= HandleEvent(event
);
1035 switch (GetState()) {
1036 case HTTP_STATE_START
:
1037 if (m_isConnected
&& !m_isLost
&& CanSend()) {
1038 ret
= HTTP_STATE_SEND_COMMAND_REQUEST
;
1042 case HTTP_STATE_SEND_COMMAND_REQUEST
:
1045 ret
= HTTP_STATE_RECEIVE_COMMAND_REPLY
;
1048 ret
= HTTP_STATE_END
;
1052 case HTTP_STATE_RECEIVE_COMMAND_REPLY
:
1053 ret
= HTTP_STATE_PROCESS_COMMAND_REPLY
;
1056 case HTTP_STATE_PROCESS_COMMAND_REPLY
:
1057 ret
= HTTP_STATE_END
;
1060 case HTTP_STATE_END
:
1068 void CHttpStateMachine::process_start(bool entry
)
1075 void CHttpStateMachine::process_end(bool)
1080 void CHttpStateMachine::process_send_command_request(bool entry
)
1083 // Prepare the request command buffer
1084 wxString ip
= m_peerAddress
->IPAddress();
1085 uint16 port
= m_peerAddress
->Service();
1087 wxString userPassEncoded
;
1088 if (m_proxyData
.m_enablePassword
) {
1089 userPass
= m_proxyData
.m_userName
+ wxT(":") + m_proxyData
.m_password
;
1091 EncodeBase64(unicode2char(userPass
), userPass
.Length());
1095 switch (m_proxyCommand
) {
1096 case PROXY_CMD_CONNECT
:
1098 wxT("CONNECT ") << ip
<< wxT(":") << port
<< wxT(" HTTP/1.1\r\n") <<
1099 wxT("Host: ") << ip
<< wxT(":") << port
<< wxT("\r\n");
1100 if (m_proxyData
.m_enablePassword
) {
1102 wxT("Authorization: Basic ") << userPassEncoded
<< wxT("\r\n") <<
1103 wxT("Proxy-Authorization: Basic ") << userPassEncoded
<< wxT("\r\n");
1108 case PROXY_CMD_BIND
:
1112 case PROXY_CMD_UDP_ASSOCIATE
:
1117 // Send the command packet
1118 m_packetLenght
= msg
.Len();
1119 memcpy(m_buffer
, unicode2char(msg
), m_packetLenght
+1);
1120 ProxyWrite(*m_proxyClientSocket
, m_buffer
, m_packetLenght
);
1124 void CHttpStateMachine::process_receive_command_reply(bool entry
)
1127 // Receive the server's reply -- Use a large number, but don't
1128 // Expect to get it all. HTTP protocol does not have a fixed length.
1129 m_packetLenght
= PROXY_BUFFER_SIZE
;
1130 ProxyRead(*m_proxyClientSocket
, m_buffer
);
1136 * HTTP Proxy server response should be something like:
1137 * "HTTP/1.1 200 Connection established\r\n\r\n"
1138 * but that may vary. The important thing is the "200"
1139 * code, that means success.
1141 static const char HTTP_AUTH_RESPONSE
[] = "HTTP/";
1142 static const int HTTP_AUTH_RESPONSE_LENGHT
= strlen(HTTP_AUTH_RESPONSE
);
1143 void CHttpStateMachine::process_process_command_reply(bool entry
)
1146 // The position of the first space in the buffer
1148 while (m_buffer
[i
] == ' ') {
1151 // Process the server's reply
1152 m_ok
= !memcmp(m_buffer
+ 0, HTTP_AUTH_RESPONSE
, HTTP_AUTH_RESPONSE_LENGHT
) &&
1153 !memcmp(m_buffer
+ i
, "200", 3);
1158 //------------------------------------------------------------------------------
1160 //------------------------------------------------------------------------------
1162 CProxySocket::CProxySocket(
1163 wxSocketFlags flags
,
1164 const CProxyData
*proxyData
,
1165 CProxyCommand proxyCommand
,
1166 CDatagramSocketProxy
*udpSocket
)
1168 wxSocketClient(flags
),
1169 m_proxyStateMachine(NULL
),
1170 m_udpSocket(udpSocket
),
1171 m_socketEventHandler(NULL
),
1172 m_socketEventHandlerId(0),
1173 m_savedSocketEventHandler(NULL
),
1174 m_savedSocketEventHandlerId(0)
1176 SetProxyData(proxyData
);
1178 switch (m_proxyData
.m_proxyType
) {
1183 m_proxyStateMachine
=
1184 new CSocks5StateMachine(*proxyData
, proxyCommand
);
1189 m_proxyStateMachine
=
1190 new CSocks4StateMachine(*proxyData
, proxyCommand
);
1194 m_proxyStateMachine
=
1195 new CHttpStateMachine(*proxyData
, proxyCommand
);
1204 CProxySocket::~CProxySocket()
1206 delete m_proxyStateMachine
;
1209 void CProxySocket::SetProxyData(const CProxyData
*proxyData
)
1211 m_useProxy
= proxyData
!= NULL
&& proxyData
->m_proxyEnable
;
1213 m_proxyData
= *proxyData
;
1214 m_proxyAddress
.Hostname(m_proxyData
.m_proxyHostName
);
1215 m_proxyAddress
.Service(m_proxyData
.m_proxyPort
);
1217 m_proxyData
.Clear();
1221 bool CProxySocket::Start(const wxIPaddress
&peerAddress
)
1224 // Important note! SaveState()/RestoreState() DO NOT save/restore
1225 // the event handler. The method SaveEventHandler() has been created
1228 SetEventHandler(g_proxyEventHandler
, ID_PROXY_SOCKET_EVENT
);
1230 wxSOCKET_CONNECTION_FLAG
|
1231 wxSOCKET_INPUT_FLAG
|
1232 wxSOCKET_OUTPUT_FLAG
|
1233 wxSOCKET_LOST_FLAG
);
1235 Connect(m_proxyAddress
, false);
1236 SetFlags(wxSOCKET_NONE
);
1237 bool ok
= m_proxyStateMachine
->Start(peerAddress
, this);
1242 bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand
) const
1246 switch (m_proxyData
.m_proxyType
) {
1252 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1253 proxyCommand
== PROXY_CMD_BIND
||
1254 proxyCommand
== PROXY_CMD_UDP_ASSOCIATE
;
1259 ret
= proxyCommand
== PROXY_CMD_CONNECT
||
1260 proxyCommand
== PROXY_CMD_BIND
;
1264 ret
= proxyCommand
== PROXY_CMD_CONNECT
;
1271 //------------------------------------------------------------------------------
1272 // CSocketClientProxy
1273 //------------------------------------------------------------------------------
1275 CSocketClientProxy::CSocketClientProxy(
1276 wxSocketFlags flags
,
1277 const CProxyData
*proxyData
)
1279 CProxySocket(flags
, proxyData
, PROXY_CMD_CONNECT
)
1283 bool CSocketClientProxy::Connect(wxIPaddress
&address
, bool wait
)
1285 wxMutexLocker
lock(m_socketLocker
);
1288 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT
)) {
1289 ok
= Start(address
);
1291 ok
= wxSocketClient::Connect(address
, wait
);
1297 CSocketClientProxy
& CSocketClientProxy::Read(void *buffer
, wxUint32 nbytes
)
1299 wxMutexLocker
lock(m_socketLocker
);
1300 CProxySocket::Read(buffer
, nbytes
);
1306 CSocketClientProxy
& CSocketClientProxy::Write(const void *buffer
, wxUint32 nbytes
)
1308 wxMutexLocker
lock(m_socketLocker
);
1309 CProxySocket::Write(buffer
, nbytes
);
1314 //------------------------------------------------------------------------------
1315 // CSocketServerProxy
1316 //------------------------------------------------------------------------------
1318 CSocketServerProxy::CSocketServerProxy(
1319 wxIPaddress
&address
,
1320 wxSocketFlags flags
,
1323 wxSocketServer(address
, flags
)
1325 /* Maybe some day when socks6 is out... :) */
1328 CSocketServerProxy
& CSocketServerProxy::Read(void *buffer
, wxUint32 nbytes
)
1330 wxMutexLocker
lock(m_socketLocker
);
1331 wxSocketServer::Read(buffer
, nbytes
);
1336 CSocketServerProxy
& CSocketServerProxy::Write(const void *buffer
, wxUint32 nbytes
)
1338 wxMutexLocker
lock(m_socketLocker
);
1339 wxSocketServer::Write(buffer
, nbytes
);
1344 //------------------------------------------------------------------------------
1345 // CDatagramSocketProxy
1346 //------------------------------------------------------------------------------
1348 CDatagramSocketProxy::CDatagramSocketProxy(
1349 wxIPaddress
&address
, wxSocketFlags flags
, const CProxyData
*proxyData
)
1351 wxDatagramSocket(address
, flags
),
1352 m_proxyTCPSocket(wxSOCKET_NOWAIT
, proxyData
, PROXY_CMD_UDP_ASSOCIATE
, this)
1354 m_udpSocketOk
= false;
1355 if ( m_proxyTCPSocket
.GetUseProxy() &&
1356 m_proxyTCPSocket
.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE
)) {
1357 m_proxyTCPSocket
.Start(address
);
1360 m_lastUDPOperation
= UDP_OPERATION_NONE
;
1363 CDatagramSocketProxy::~CDatagramSocketProxy()
1366 // "A UDP association terminates when the TCP connection that the
1367 // UDP ASSOCIATE request arrived terminates."
1370 wxDatagramSocket
&CDatagramSocketProxy::RecvFrom(
1371 wxSockAddress
&addr
, void* buf
, wxUint32 nBytes
)
1373 wxMutexLocker
lock(m_socketLocker
);
1374 m_lastUDPOperation
= UDP_OPERATION_RECV_FROM
;
1375 if (m_proxyTCPSocket
.GetUseProxy()) {
1376 if (m_udpSocketOk
) {
1377 char *bufUDP
= NULL
;
1378 if (nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
> PROXY_BUFFER_SIZE
) {
1379 bufUDP
= new char[nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
];
1381 bufUDP
= m_proxyTCPSocket
.GetBuffer();
1383 wxDatagramSocket::RecvFrom(
1384 m_proxyTCPSocket
.GetProxyBoundAddress(),
1385 bufUDP
, nBytes
+ PROXY_UDP_MAXIMUM_OVERHEAD
);
1386 unsigned int offset
;
1387 switch (m_proxyTCPSocket
.GetBuffer()[3]) {
1388 case SOCKS5_ATYP_IPV4_ADDRESS
: {
1389 offset
= PROXY_UDP_OVERHEAD_IPV4
;
1391 amuleIPV4Address
&a
= dynamic_cast<amuleIPV4Address
&>(addr
);
1392 a
.Hostname( PeekUInt32( m_proxyTCPSocket
.GetBuffer()+4 ) );
1393 a
.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket
.GetBuffer()+8) ) );
1394 } catch (const std::bad_cast
& WXUNUSED(e
)) {
1395 AddDebugLogLineN(logProxy
,
1396 wxT("(2)bad_cast exception!"));
1402 case SOCKS5_ATYP_DOMAINNAME
:
1403 offset
= PROXY_UDP_OVERHEAD_DOMAIN_NAME
;
1406 case SOCKS5_ATYP_IPV6_ADDRESS
:
1407 offset
= PROXY_UDP_OVERHEAD_IPV6
;
1415 memcpy(buf
, bufUDP
+ offset
, nBytes
);
1416 // Uncomment here to see the buffer contents on console
1417 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1419 /* Only delete buffer if it was dynamically created */
1420 if (bufUDP
!= m_proxyTCPSocket
.GetBuffer()) {
1421 /* We should use a fixed buffer to avoid
1422 * new/delete it all the time.
1423 * I need an upper bound */
1426 /* There is still one problem pending, fragmentation.
1427 * Either we support it or we have to drop fragmented
1428 * messages. I vote for drop :)
1432 wxDatagramSocket::RecvFrom(addr
, buf
, nBytes
);
1438 wxDatagramSocket
&CDatagramSocketProxy::SendTo(
1439 wxIPaddress
&addr
, const void* buf
, wxUint32 nBytes
)
1441 wxMutexLocker
lock(m_socketLocker
);
1442 m_lastUDPOperation
= UDP_OPERATION_SEND_TO
;
1443 m_lastUDPOverhead
= PROXY_UDP_OVERHEAD_IPV4
;
1444 if (m_proxyTCPSocket
.GetUseProxy()) {
1445 if (m_udpSocketOk
) {
1446 m_proxyTCPSocket
.GetBuffer()[0] = SOCKS5_RSV
; // Reserved
1447 m_proxyTCPSocket
.GetBuffer()[1] = SOCKS5_RSV
; // Reserved
1448 m_proxyTCPSocket
.GetBuffer()[2] = 0; // FRAG
1449 m_proxyTCPSocket
.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS
;
1450 PokeUInt32( m_proxyTCPSocket
.GetBuffer()+4, StringIPtoUint32(addr
.IPAddress()));
1451 RawPokeUInt16( m_proxyTCPSocket
.GetBuffer()+8, ENDIAN_HTONS( addr
.Service() ) );
1452 memcpy(m_proxyTCPSocket
.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4
, buf
, nBytes
);
1453 nBytes
+= PROXY_UDP_OVERHEAD_IPV4
;
1454 wxDatagramSocket::SendTo(
1455 m_proxyTCPSocket
.GetProxyBoundAddress(),
1456 m_proxyTCPSocket
.GetBuffer(), nBytes
);
1457 // Uncomment here to see the buffer contents on console
1458 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1461 wxDatagramSocket::SendTo(addr
, buf
, nBytes
);
1467 wxUint32
CDatagramSocketProxy::LastCount(void) const
1471 if (m_proxyTCPSocket
.GetUseProxy()) {
1472 switch (m_lastUDPOperation
) {
1473 case UDP_OPERATION_RECV_FROM
:
1474 case UDP_OPERATION_SEND_TO
:
1475 ret
= Ok() ? wxDatagramSocket::LastCount() - m_lastUDPOverhead
: 0;
1478 case UDP_OPERATION_NONE
:
1485 ret
= wxDatagramSocket::LastCount();
1491 #endif // CLIENT_GUI
1493 /******************************************************************************/
1494 // File_checked_for_headers