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 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
31 #include "amuleIPV4Address.h" // For amuleIPV4address
32 #include "StateMachine.h" // For CStateMachine
34 /******************************************************************************/
37 * SOCKS4 protocol implementation according to:
38 * - "SOCKS: A protocol for TCP proxy across firewalls":
39 * amule-root/docs/socks4.protocol
41 const unsigned char SOCKS4_VERSION
= 0x04;
43 const unsigned char SOCKS4_CMD_CONNECT
= 0x01;
44 const unsigned char SOCKS4_CMD_BIND
= 0x02;
46 const unsigned char SOCKS4_REPLY_CODE
= 0;
47 const unsigned char SOCKS4_REPLY_GRANTED
= 90;
48 const unsigned char SOCKS4_REPLY_FAILED
= 91;
49 const unsigned char SOCKS4_REPLY_FAILED_NO_IDENTD
= 92;
50 const unsigned char SOCKS4_REPLY_FAILED_DIFFERENT_USERIDS
= 93;
53 * SOCKS5 protocol implementation according to:
54 * - RFC-1928: SOCKS Protocol Version 5
55 * - RFC-1929: username/password Authentication for SOCKS V5
57 * Also, for the future :) :
58 * - RFC-1961: GSS-API Authentication Method for SOCKS Version 5
59 * - RFC-1508: Generic Security Service Application Program Interface
60 * - RFC-1509: Genecic Security Service API: C-bindings
64 const unsigned char SOCKS5_VERSION
= 0x05;
66 const unsigned char SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED
= 0x00;
67 const unsigned char SOCKS5_AUTH_METHOD_GSSAPI
= 0x01;
68 const unsigned char SOCKS5_AUTH_METHOD_USERNAME_PASSWORD
= 0x02;
69 const unsigned char SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS
= 0xFF;
71 const unsigned char SOCKS5_AUTH_VERSION_USERNAME_PASSWORD
= 0x01;
73 const unsigned char SOCKS5_CMD_CONNECT
= 0x01;
74 const unsigned char SOCKS5_CMD_BIND
= 0x02;
75 const unsigned char SOCKS5_CMD_UDP_ASSOCIATE
= 0x03;
77 const unsigned char SOCKS5_RSV
= 0x00;
79 const unsigned char SOCKS5_ATYP_IPV4_ADDRESS
= 0x01;
80 const unsigned char SOCKS5_ATYP_DOMAINNAME
= 0x03;
81 const unsigned char SOCKS5_ATYP_IPV6_ADDRESS
= 0x04;
83 const unsigned char SOCKS5_REPLY_SUCCEED
= 0x00;
84 const unsigned char SOCKS5_REPLY_GENERAL_SERVER_FAILURE
= 0x01;
85 const unsigned char SOCKS5_REPLY_CONNECTION_NOT_ALLOWED
= 0x02;
86 const unsigned char SOCKS5_REPLY_NETWORK_UNREACHABLE
= 0x03;
87 const unsigned char SOCKS5_REPLY_HOST_UNREACHABLE
= 0x04;
88 const unsigned char SOCKS5_REPLY_CONNECTION_REFUSED
= 0x05;
89 const unsigned char SOCKS5_REPLY_TTL_EXPIRED
= 0x06;
90 const unsigned char SOCKS5_REPLY_COMMAND_NOT_SUPPORTED
= 0x07;
91 const unsigned char SOCKS5_REPLY_ATYP_NOT_SUPPORTED
= 0x08;
93 //------------------------------------------------------------------------------
95 //------------------------------------------------------------------------------
98 * These constants must match the integer values saved in the configuration file,
99 * DO NOT CHANGE THIS ORDER!!!
110 //------------------------------------------------------------------------------
112 //------------------------------------------------------------------------------
114 * The ProxyData class will hold information about the proxy server to be used.
120 * Default constructor.
126 * @param proxyEnable Whether proxy is enabled or not.
127 * @param proxyType The type of the proxy server.
128 * @param proxyHostName The proxy host name or IP address.
129 * @param proxyPort The proxy port number.
130 * @param enablePassword Whether authentication should be performed.
131 * @param userName The user name to authenticate to the server.
132 * @param password The password to authenticate to the server.
136 CProxyType proxyType
,
137 const wxString
&proxyHostName
,
138 unsigned short proxyPort
,
140 const wxString
&userName
,
141 const wxString
&password
144 * Clears the object contents.
149 //! Whether proxy is enabled or not.
151 //! The type of the proxy server.
152 CProxyType m_proxyType
;
153 //! The proxy host name or IP address.
154 wxString m_proxyHostName
;
155 //! The proxy port number.
156 unsigned short m_proxyPort
;
157 //! Whether authentication should be performed.
158 bool m_enablePassword
;
159 //! The user name to authenticate to the server.
161 //! The password to authenticate to the server.
165 //------------------------------------------------------------------------------
166 // CProxyEventHandler
167 //------------------------------------------------------------------------------
169 * Event handler object used during proxy negotiation.
171 class CProxyEventHandler
: public wxEvtHandler
{
176 CProxyEventHandler();
180 * Event handler function.
182 void ProxySocketHandler(wxSocketEvent
&event
);
183 DECLARE_EVENT_TABLE()
186 //------------------------------------------------------------------------------
187 // CProxyStateMachine
188 //------------------------------------------------------------------------------
189 /* This size is just to be a little bit greater than the UDP buffer used in aMule.
190 * Proxy protocol needs much less than this. 1024 would be ok. Other options are
191 * - Default ethernet MTU - Eth-II - IP - UDP: 1,514 - 14 - 20 - 8 = 1472 bytes;
192 * - Default token ring MTU 4,202 - overheads = ??.
193 * It would be really more efficient if the final object was less than
194 * a page (4096 bytes) in size.
196 //const unsigned int PROXY_BUFFER_SIZE = 1024;
197 const unsigned int PROXY_BUFFER_SIZE
= 5*1024;
202 PROXY_CMD_UDP_ASSOCIATE
206 PROXY_STATE_START
= 0,
211 * The ProxyStateMachine class is the ancestor of all proxy classes.
213 * CProxyStateMachine will do all the common work that a proxy class must do
214 * and provide the necessary variables.
216 class CProxyStateMachine
: public CStateMachine
222 * @param name The name of the state machine. For debug messages only.
223 * @param max_states The maximum number of states that this machine will have.
224 * @param proxyData The necessary proxy information.
225 * @param cmd The type of proxy command to run.
229 const unsigned int max_states
,
230 const CProxyData
&proxyData
,
235 virtual ~CProxyStateMachine();
237 * Adds a small string to the state machine name, containing the proxy command.
239 * @param s The original state machine name.
240 * @param cmd The proxy command.
242 static wxString
&NewName(wxString
&s
, CProxyCommand cmd
);
245 bool Start(const wxIPaddress
&peerAddress
, wxSocketClient
*proxyClientSocket
);
246 t_sm_state
HandleEvent(t_sm_event event
);
247 void AddDummyEvent();
248 void ReactivateSocket();
249 char *GetBuffer() { return m_buffer
; }
250 wxIPaddress
&GetProxyBoundAddress(void) const { return *m_proxyBoundAddress
; }
251 unsigned char GetLastReply(void) const { return m_lastReply
; }
252 bool IsEndState() const { return GetState() == PROXY_STATE_END
; }
255 wxSocketBase
&ProxyWrite(wxSocketBase
&socket
, const void *buffer
, wxUint32 nbytes
);
256 wxSocketBase
&ProxyRead(wxSocketBase
&socket
, void *buffer
);
257 bool CanReceive() const;
258 bool CanSend() const;
260 // Initialized at constructor
262 const CProxyData
&m_proxyData
;
263 CProxyCommand m_proxyCommand
;
267 char m_buffer
[PROXY_BUFFER_SIZE
];
273 unsigned int m_lastRead
;
274 unsigned int m_lastWritten
;
275 wxSocketError m_lastError
;
277 // Will be initialized at Start()
279 wxIPaddress
*m_peerAddress
;
280 wxSocketClient
*m_proxyClientSocket
;
281 wxIPaddress
*m_proxyBoundAddress
;
282 amuleIPV4Address m_proxyBoundAddressIPV4
;
283 //wxIPV6address m_proxyBoundAddressIPV6;
285 // Temporary variables
287 unsigned char m_lastReply
;
288 unsigned int m_packetLenght
;
291 //------------------------------------------------------------------------------
292 // CSocks5StateMachine
293 //------------------------------------------------------------------------------
294 class CSocks5StateMachine
;
295 typedef void (CSocks5StateMachine::*Socks5StateProcessor
)(bool entry
);
296 class CSocks5StateMachine
: public CProxyStateMachine
299 static const unsigned int SOCKS5_MAX_STATES
= 14;
302 SOCKS5_STATE_START
= PROXY_STATE_START
,
303 SOCKS5_STATE_END
= PROXY_STATE_END
,
304 SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD
,
305 SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD
,
306 SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD
,
307 SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI
,
308 SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI
,
309 SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI
,
310 SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD
,
311 SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD
,
312 SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD
,
313 SOCKS5_STATE_SEND_COMMAND_REQUEST
,
314 SOCKS5_STATE_RECEIVE_COMMAND_REPLY
,
315 SOCKS5_STATE_PROCESS_COMMAND_REPLY
321 const CProxyData
&proxyData
,
322 CProxyCommand proxyCommand
);
323 void process_state(t_sm_state state
, bool entry
);
324 t_sm_state
next_state(t_sm_event event
);
327 /* State Processors */
328 void process_start(bool entry
);
329 void process_send_query_authentication_method(bool entry
);
330 void process_receive_authentication_method(bool entry
);
331 void process_process_authentication_method(bool entry
);
332 void process_send_authentication_gssapi(bool entry
);
333 void process_receive_authentication_gssapi(bool entry
);
334 void process_process_authentication_gssapi(bool entry
);
335 void process_send_authentication_username_password(bool entry
);
336 void process_receive_authentication_username_password(bool entry
);
337 void process_process_authentication_username_password(bool entry
);
338 void process_send_command_request(bool entry
);
339 void process_receive_command_reply(bool entry
);
340 void process_process_command_reply(bool entry
);
341 void process_end(bool entry
);
343 Socks5StateProcessor m_process_state
[SOCKS5_MAX_STATES
];
344 wxString m_state_name
[SOCKS5_MAX_STATES
];
347 //------------------------------------------------------------------------------
348 // CSocks4StateMachine
349 //------------------------------------------------------------------------------
350 class CSocks4StateMachine
;
351 typedef void (CSocks4StateMachine::*Socks4StateProcessor
)(bool entry
);
352 class CSocks4StateMachine
: public CProxyStateMachine
355 static const unsigned int SOCKS4_MAX_STATES
= 5;
358 SOCKS4_STATE_START
= PROXY_STATE_START
,
359 SOCKS4_STATE_END
= PROXY_STATE_END
,
360 SOCKS4_STATE_SEND_COMMAND_REQUEST
,
361 SOCKS4_STATE_RECEIVE_COMMAND_REPLY
,
362 SOCKS4_STATE_PROCESS_COMMAND_REPLY
368 const CProxyData
&proxyData
,
369 CProxyCommand proxyCommand
);
370 void process_state(t_sm_state state
, bool entry
);
371 t_sm_state
next_state(t_sm_event event
);
374 /* State Processors */
375 void process_start(bool entry
);
376 void process_send_command_request(bool entry
);
377 void process_receive_command_reply(bool entry
);
378 void process_process_command_reply(bool entry
);
379 void process_end(bool entry
);
381 Socks4StateProcessor m_process_state
[SOCKS4_MAX_STATES
];
382 wxString m_state_name
[SOCKS4_MAX_STATES
];
385 //------------------------------------------------------------------------------
387 //------------------------------------------------------------------------------
388 class CHttpStateMachine
;
389 typedef void (CHttpStateMachine::*HttpStateProcessor
)(bool entry
);
390 class CHttpStateMachine
: public CProxyStateMachine
393 static const unsigned int HTTP_MAX_STATES
= 5;
396 HTTP_STATE_START
= PROXY_STATE_START
,
397 HTTP_STATE_END
= PROXY_STATE_END
,
398 HTTP_STATE_SEND_COMMAND_REQUEST
,
399 HTTP_STATE_RECEIVE_COMMAND_REPLY
,
400 HTTP_STATE_PROCESS_COMMAND_REPLY
406 const CProxyData
&proxyData
,
407 CProxyCommand proxyCommand
);
408 void process_state(t_sm_state state
, bool entry
);
409 t_sm_state
next_state(t_sm_event event
);
412 /* State Processors */
413 void process_start(bool entry
);
414 void process_send_command_request(bool entry
);
415 void process_receive_command_reply(bool entry
);
416 void process_process_command_reply(bool entry
);
417 void process_end(bool entry
);
419 HttpStateProcessor m_process_state
[HTTP_MAX_STATES
];
420 wxString m_state_name
[HTTP_MAX_STATES
];
423 //------------------------------------------------------------------------------
425 //------------------------------------------------------------------------------
427 class CDatagramSocketProxy
;
429 class CProxySocket
: public wxSocketClient
431 friend class CProxyEventHandler
;
435 wxSocketFlags flags
= wxSOCKET_NONE
,
436 const CProxyData
*proxyData
= NULL
,
437 CProxyCommand proxyCommand
= PROXY_CMD_CONNECT
,
438 CDatagramSocketProxy
*udpSocket
= NULL
);
443 /* I know, this is not very good, because SetEventHandler is not
444 * virtual in wxSocketBase, but I need to GetEventHandler in Proxy.cpp,
447 void SetEventHandler(wxEvtHandler
&handler
, int id
= wxID_ANY
)
449 m_socketEventHandler
= &handler
;
450 m_socketEventHandlerId
= id
;
451 wxSocketClient::SetEventHandler(handler
, id
);
453 wxEvtHandler
*GetEventHandler(void) const { return m_socketEventHandler
; }
454 int GetEventHandlerId(void) const { return m_socketEventHandlerId
; }
455 void SaveEventHandler(void)
457 m_savedSocketEventHandler
= m_socketEventHandler
;
458 m_savedSocketEventHandlerId
= m_socketEventHandlerId
;
460 void RestoreEventHandler(void)
462 m_socketEventHandler
= m_savedSocketEventHandler
;
463 m_socketEventHandlerId
= m_savedSocketEventHandlerId
;
464 SetEventHandler(*m_socketEventHandler
, m_socketEventHandlerId
);
468 void SetProxyData(const CProxyData
*proxyData
);
469 bool GetUseProxy() const { return m_useProxy
; }
470 char *GetBuffer() { return m_proxyStateMachine
->GetBuffer(); }
471 wxIPaddress
&GetProxyBoundAddress(void) const
472 { return m_proxyStateMachine
->GetProxyBoundAddress(); }
473 bool Start(const wxIPaddress
&peerAddress
);
474 bool ProxyIsCapableOf(CProxyCommand proxyCommand
) const;
475 bool ProxyNegotiationIsOver() const { return m_proxyStateMachine
->IsEndState(); }
476 CDatagramSocketProxy
*GetUDPSocket() const { return m_udpSocket
; }
480 CProxyData m_proxyData
;
481 amuleIPV4Address m_proxyAddress
;
482 CProxyStateMachine
*m_proxyStateMachine
;
483 CDatagramSocketProxy
*m_udpSocket
;
484 wxEvtHandler
*m_socketEventHandler
;
485 int m_socketEventHandlerId
;
486 wxEvtHandler
*m_savedSocketEventHandler
;
487 int m_savedSocketEventHandlerId
;
490 //------------------------------------------------------------------------------
491 // CSocketClientProxy
492 //------------------------------------------------------------------------------
494 class CSocketClientProxy
: public CProxySocket
499 wxSocketFlags flags
= wxSOCKET_NONE
,
500 const CProxyData
*proxyData
= NULL
);
503 bool Connect(wxIPaddress
&address
, bool wait
);
504 CSocketClientProxy
& Read(void *buffer
, wxUint32 nbytes
);
505 CSocketClientProxy
& Write(const void *buffer
, wxUint32 nbytes
);
508 wxMutex m_socketLocker
;
511 //------------------------------------------------------------------------------
512 // CSocketServerProxy
513 //------------------------------------------------------------------------------
515 class CSocketServerProxy
: public wxSocketServer
520 wxIPaddress
&address
,
521 wxSocketFlags flags
= wxSOCKET_NONE
,
522 const CProxyData
*proxyData
= NULL
);
525 CSocketServerProxy
& Read(void *buffer
, wxUint32 nbytes
);
526 CSocketServerProxy
& Write(const void *buffer
, wxUint32 nbytes
);
529 wxMutex m_socketLocker
;
532 //------------------------------------------------------------------------------
533 // CDatagramSocketProxy
534 //------------------------------------------------------------------------------
538 UDP_OPERATION_RECV_FROM
,
539 UDP_OPERATION_SEND_TO
542 const unsigned int PROXY_UDP_OVERHEAD_IPV4
= 10;
543 const unsigned int PROXY_UDP_OVERHEAD_DOMAIN_NAME
= 262;
544 const unsigned int PROXY_UDP_OVERHEAD_IPV6
= 20;
545 const unsigned int PROXY_UDP_MAXIMUM_OVERHEAD
= PROXY_UDP_OVERHEAD_DOMAIN_NAME
;
547 class CDatagramSocketProxy
: public wxDatagramSocket
551 CDatagramSocketProxy(
552 wxIPaddress
&address
,
553 wxSocketFlags flags
= wxSOCKET_NONE
,
554 const CProxyData
*proxyData
= NULL
);
557 ~CDatagramSocketProxy();
560 void SetUDPSocketOk() { m_udpSocketOk
= true; }
562 /* wxDatagramSocket Interface */
563 virtual wxDatagramSocket
& RecvFrom(
564 wxSockAddress
& addr
, void* buf
, wxUint32 nBytes
);
565 virtual wxDatagramSocket
& SendTo(
566 wxIPaddress
& addr
, const void* buf
, wxUint32 nBytes
);
567 virtual wxUint32
LastCount(void) const;
571 CProxySocket m_proxyTCPSocket
;
572 enum UDPOperation m_lastUDPOperation
;
573 unsigned int m_lastUDPOverhead
;
574 wxMutex m_socketLocker
;
577 /******************************************************************************/
579 #endif /* __PROXY_H__ */
581 // File_checked_for_headers