Bug Summary

File:rootdir/src/Proxy.cpp
Warning:line 110, column 3
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Proxy.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D USE_WX_EXTENSIONS -I /usr/include/upnp -D ENABLE_UPNP=1 -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D ENABLE_IP2COUNTRY=1 -I ./libs -I libs -I ./include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-17-082348-14898-1 -x c++ Proxy.cpp
1//
2// This file is part of the aMule Project.
3//
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 )
6//
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
9// respective authors.
10//
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.
15//
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.
20//
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
24//
25
26#include "Proxy.h" /* for Interface */
27
28#include <common/EventIDs.h>
29
30#include "ArchSpecific.h" /* for ENDIAN_HTONS() */
31#include "Logger.h" /* for AddDebugLogLineN */
32#include "OtherFunctions.h" /* for EncodeBase64() */
33#include <common/StringFunctions.h> /* for unicode2char */
34#include "GuiEvents.h"
35
36// Define it to 1 to debug proxy communication and state machine design. If
37// enabled messages sent to and received from proxies will be dumped to stdout.
38// Has effect only in debug-enabled builds.
39#ifndef DEBUG_DUMP_PROXY_MSG0
40#define DEBUG_DUMP_PROXY_MSG0 0
41#endif
42
43
44//------------------------------------------------------------------------------
45// CProxyData
46//------------------------------------------------------------------------------
47
48CProxyData::CProxyData()
49{
50 Clear();
51}
52
53CProxyData::CProxyData(
54 bool proxyEnable,
55 CProxyType proxyType,
56 const wxString &proxyHostName,
57 unsigned short proxyPort,
58 bool enablePassword,
59 const wxString &userName,
60 const wxString &password)
61:
62m_proxyEnable(proxyEnable),
63m_proxyType(proxyType),
64m_proxyHostName(proxyHostName),
65m_proxyPort(proxyPort),
66m_enablePassword(enablePassword),
67m_userName(userName),
68m_password(password)
69{
70}
71
72void CProxyData::Clear()
73{
74 m_proxyEnable = false;
75 m_proxyType = PROXY_NONE;
76 m_proxyHostName.Clear();
77 m_proxyPort = 0;
78 m_enablePassword = false;
79 m_userName.Clear();
80 m_password.Clear();
81}
82
83#ifndef CLIENT_GUI
84
85#include <typeinfo> // Do_not_auto_remove (NetBSD, older gccs)
86
87#ifndef ASIO_SOCKETS
88
89//------------------------------------------------------------------------------
90// ProxyEventHandler
91//------------------------------------------------------------------------------
92
93CProxyEventHandler::CProxyEventHandler()
94{
95}
96
97BEGIN_EVENT_TABLE(CProxyEventHandler, wxEvtHandler)const wxEventTable CProxyEventHandler::sm_eventTable = { &
wxEvtHandler::sm_eventTable, &CProxyEventHandler::sm_eventTableEntries
[0] }; const wxEventTable *CProxyEventHandler::GetEventTable(
) const { return &CProxyEventHandler::sm_eventTable; } wxEventHashTable
CProxyEventHandler::sm_eventHashTable(CProxyEventHandler::sm_eventTable
); wxEventHashTable &CProxyEventHandler::GetEventHashTable
() const { return CProxyEventHandler::sm_eventHashTable; } const
wxEventTableEntry CProxyEventHandler::sm_eventTableEntries[]
= {
98 EVT_SOCKET(ID_PROXY_SOCKET_EVENT, CProxyEventHandler::ProxySocketHandler)wxEventTableEntry(wxEVT_SOCKET, ID_PROXY_SOCKET_EVENT, wxID_ANY
, wxNewEventTableFunctor(wxEVT_SOCKET, wxEventFunctionCast(wxPrivate
::DoCast<wxPrivate::EventArgOf<wxSocketEventFunction>
::type>(&CProxyEventHandler::ProxySocketHandler))), __null
),
99END_EVENT_TABLE()wxEventTableEntry(wxEVT_NULL, 0, 0, __null, __null) };
100
101//
102// THE one and only Event Handler
103//
104static CProxyEventHandler g_proxyEventHandler;
105
106void CProxyEventHandler::ProxySocketHandler(wxSocketEvent& event)
107{
108 CProxySocket *sock = dynamic_cast<CProxySocket *>(event.GetSocket());
109 if (sock) {
110 sock->m_proxyStateMachine->Schedule(event.GetSocketEvent());
This statement is never executed
111 sock->m_proxyStateMachine->Clock();
112 } else {
113 // we're doomed :)
114 }
115}
116
117#else
118
119//
120// In Asio mode the event handler is:
121//
122void CProxySocket::OnProxyEvent(int evt)
123{
124 m_proxyStateMachine->Schedule(evt);
125 m_proxyStateMachine->Clock();
126}
127
128#endif
129
130//------------------------------------------------------------------------------
131// CProxyStateMachine
132//------------------------------------------------------------------------------
133
134CProxyStateMachine::CProxyStateMachine(
135 wxString name,
136 const unsigned int max_states,
137 const CProxyData &proxyData,
138 CProxyCommand proxyCommand)
139:
140CStateMachine(NewName(name, proxyCommand), max_states, PROXY_STATE_START),
141m_proxyData(proxyData),
142m_proxyCommand(proxyCommand),
143m_isLost(false),
144m_isConnected(false),
145m_canReceive(false),
146m_canSend(false),
147m_ok(true),
148m_lastRead(0),
149// Will be initialized at Start()
150m_peerAddress(NULL__null),
151m_proxyClientSocket(NULL__null),
152m_proxyBoundAddress(NULL__null),
153// Temporary variables
154m_lastReply(0),
155m_packetLenght(0)
156{
157}
158
159CProxyStateMachine::~CProxyStateMachine()
160{
161 delete m_peerAddress;
162}
163
164wxString &CProxyStateMachine::NewName(wxString &s, CProxyCommand proxyCommand)
165{
166 switch (proxyCommand) {
167 case PROXY_CMD_CONNECT:
168 s += wxT("-CONNECT")L"-CONNECT";
169 break;
170
171 case PROXY_CMD_BIND:
172 s += wxT("-BIND")L"-BIND";
173 break;
174
175 case PROXY_CMD_UDP_ASSOCIATE:
176 s += wxT("-UDP")L"-UDP";
177 break;
178 }
179
180 return s;
181}
182
183bool CProxyStateMachine::Start(const amuleIPV4Address &peerAddress, CLibSocket *proxyClientSocket)
184{
185 m_proxyClientSocket = proxyClientSocket;
186 m_peerAddress = new amuleIPV4Address(peerAddress);
187 //try {
188 // const wxIPV4address &peer = dynamic_cast<const wxIPV4address &>(peerAddress);
189 // m_peerAddress = new amuleIPV4Address(peer);
190 //} catch (const std::bad_cast& WXUNUSED(e)) {
191 // // Should process other types of wxIPAddress before quitting
192 // AddDebugLogLineN(logProxy, wxT("(1)bad_cast exception!"));
193 // wxFAIL;
194 // return false;
195 //}
196
197 // To run the state machine, return and just let the events start to happen.
198 return true;
199}
200
201static const int MULE_SOCKET_DUMMY_VALUE = MULE_SOCKET_INPUTwxSOCKET_INPUT + MULE_SOCKET_OUTPUTwxSOCKET_OUTPUT + MULE_SOCKET_CONNECTIONwxSOCKET_CONNECTION + MULE_SOCKET_LOSTwxSOCKET_LOST;
202
203t_sm_state CProxyStateMachine::HandleEvent(t_sm_event event)
204{
205 // Default is stay in current state
206 t_sm_state ret = GetState();
207 switch(event)
208 {
209 case MULE_SOCKET_CONNECTIONwxSOCKET_CONNECTION:
210 AddDebugLogLineN(logProxy, wxT("Connection event"))do {} while (false);
211 m_isConnected = true;
212 break;
213
214 case MULE_SOCKET_INPUTwxSOCKET_INPUT:
215 AddDebugLogLineN(logProxy, wxT("Input event"))do {} while (false);
216 m_canReceive = true;
217 break;
218
219 case MULE_SOCKET_OUTPUTwxSOCKET_OUTPUT:
220 AddDebugLogLineN(logProxy, wxT("Output event"))do {} while (false);
221 m_canSend = true;
222 break;
223
224 case MULE_SOCKET_LOSTwxSOCKET_LOST:
225 AddDebugLogLineN(logProxy, wxT("Lost connection event"))do {} while (false);
226 m_isLost = true;
227 m_ok = false;
228 break;
229
230 case MULE_SOCKET_DUMMY_VALUE:
231 AddDebugLogLineN(logProxy, wxT("Dummy event"))do {} while (false);
232 break;
233
234 default:
235 AddDebugLogLineN(logProxy, CFormat(wxT("Unknown event %d")) % event)do {} while (false);
236 break;
237 }
238
239 // Aborting conditions:
240 // - MULE_SOCKET_LOST event
241 // - More than 10 times on the same state
242 if ( m_isLost ||
243 GetClocksInCurrentState() > 10) {
244 ret = PROXY_STATE_END;
245 }
246
247 return ret;
248}
249
250void CProxyStateMachine::AddDummyEvent()
251{
252#ifdef ASIO_SOCKETS
253 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
254 if (s) { // should always be
255 CoreNotify_ProxySocketEvent(s, MULE_SOCKET_DUMMY_VALUE)MuleNotify::DoNotifyAlways(&MuleNotify::ProxySocketEvent,
s, MULE_SOCKET_DUMMY_VALUE)
;
256 }
257#else
258 wxSocketEvent e(ID_PROXY_SOCKET_EVENT);
259 // Make sure this is an unknown event :)
260 e.m_event = (wxSocketNotify)(MULE_SOCKET_DUMMY_VALUE);
261 e.SetEventObject(m_proxyClientSocket);
262 g_proxyEventHandler.AddPendingEvent(e);
263#endif
264}
265
266void CProxyStateMachine::ReactivateSocket()
267{
268 /* If proxy is being used, then the TCP socket handlers
269 * (CServerSocketHandler and CClientTCPSocketHandler) will not
270 * receive a wxSOCKET_CONNECTION event, because the connection has
271 * already started with the proxy. So we must add a wxSOCKET_CONNECTION
272 * event to make things go undetected. A wxSOCKET_OUTPUT event is also
273 * necessary to start sending data to the server. */
274 CProxySocket *s = dynamic_cast<CProxySocket *>(m_proxyClientSocket);
275 // If that is not true, we are in serious trouble...
276 wxASSERT(s)do { if ( s ) { } else if ( wxTheAssertHandler && (wxOnAssert
("Proxy.cpp", 276, __FUNCTION__, "s", (const char*)__null), wxTrapInAssert
) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while
( (void)0, 0 )
;
277 if (CDatagramSocketProxy *udp = s->GetUDPSocket()) {
278 // The original socket was a UDP socket
279 if(m_ok) {
280 // From now on, the UDP socket can be used,
281 // remove the protection.
282 udp->SetUDPSocketOk();
283 }
284 // No need to call RestoreState(), that socket will no longer
285 // be used after proxy negotiation.
286 } else {
287 // The original socket was a TCP socket
288#ifdef ASIO_SOCKETS
289 if (s->GetProxyState()) { // somehow this gets called twice ?
290 s->SetProxyState(false);
291 CoreNotify_LibSocketConnect(s, 0)MuleNotify::DoNotifyAlways(&MuleNotify::LibSocketConnect,
s, 0)
;
292 if (m_ok) {
293 CoreNotify_LibSocketSend(s, 0)MuleNotify::DoNotifyAlways(&MuleNotify::LibSocketSend, s,
0)
;
294 } else {
295 CoreNotify_LibSocketLost(s)MuleNotify::DoNotifyAlways(&MuleNotify::LibSocketLost, s);
296 }
297 }
298#else
299 s->RestoreEventHandler();
300 wxSocketEvent e(s->GetEventHandlerId());
301 e.m_event = wxSOCKET_CONNECTION;
302 e.SetEventObject(s);
303 wxEvtHandler *h(s->GetEventHandler());
304 h->AddPendingEvent(e);
305 e.m_event = wxSOCKET_OUTPUT;
306 h->AddPendingEvent(e);
307 if (!m_ok) {
308 e.m_event = wxSOCKET_LOST;
309 h->AddPendingEvent(e);
310 }
311 s->RestoreState();
312#endif
313 }
314}
315
316uint32 CProxyStateMachine::ProxyWrite(CLibSocket &socket, const void *buffer, wxUint32 nbytes)
317{
318 uint32 written = socket.Write(buffer, nbytes);
319 /* Set the status of this operation */
320 m_ok = true;
321 if (m_proxyClientSocket->BlocksWrite()) {
322 m_lastError = 0;
323 m_canSend = false;
324 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
325 m_ok = false;
326 }
327 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyWrite %d %d ok %d cansend %d")) % nbytes % written % m_ok % m_canSend)do {} while (false);
328
329 return written;
330}
331
332uint32 CProxyStateMachine::ProxyRead(CLibSocket &socket, void *buffer)
333{
334 /* Always try to read the full buffer. That explicitly demands that
335 * the socket has the flag wxSOCKET_NONE. */
336 m_lastRead = socket.Read(buffer, PROXY_BUFFER_SIZE);
337 /* Set the status of this operation */
338 m_ok = true;
339 if (m_proxyClientSocket->BlocksRead()) {
340 m_lastError = 0;
341#ifndef ASIO_SOCKETS // m_canReceive is already assigned later
342 m_canReceive = false;
343#endif
344 } else if ((m_lastError = m_proxyClientSocket->LastError()) != 0) {
345 m_ok = false;
346 }
347#ifdef ASIO_SOCKETS
348 // We will get a new event right away if data is left, or when new data gets available.
349 // So block for now.
350 m_canReceive = false;
351#endif
352 AddDebugLogLineN(logProxy, CFormat(wxT("ProxyRead %d ok %d canrec %d")) % m_lastRead % m_ok % m_canReceive)do {} while (false);
353
354 return m_lastRead;
355}
356
357bool CProxyStateMachine::CanReceive() const
358{
359 return m_canReceive;
360}
361
362bool CProxyStateMachine::CanSend() const
363{
364 return m_canSend;
365}
366
367//------------------------------------------------------------------------------
368// CSocks5StateMachine
369//------------------------------------------------------------------------------
370
371/**
372 * The state machine constructor must initialize the array of pointer to member
373 * functions. Don't waste you time trying to statically initialize this, pointer
374 * to member functions require an object to operate on, so this array must be
375 * initialized at run time.
376 */
377CSocks5StateMachine::CSocks5StateMachine(
378 const CProxyData &proxyData,
379 CProxyCommand proxyCommand)
380:
381CProxyStateMachine(
382 wxString(wxT("Socks5")L"Socks5"), SOCKS5_MAX_STATES, proxyData, proxyCommand)
383{
384 m_process_state[ 0] = &CSocks5StateMachine::process_start;
385 m_state_name[ 0] = wxT("process_start")L"process_start";
386 m_process_state[ 1] = &CSocks5StateMachine::process_end;
387 m_state_name[ 1] = wxT("process_end")L"process_end";
388 m_process_state[ 2] = &CSocks5StateMachine::process_send_query_authentication_method;
389 m_state_name[ 2] = wxT("process_send_query_authentication_method")L"process_send_query_authentication_method";
390 m_process_state[ 3] = &CSocks5StateMachine::process_receive_authentication_method;
391 m_state_name[ 3] = wxT("process_receive_authentication_method")L"process_receive_authentication_method";
392 m_process_state[ 4] = &CSocks5StateMachine::process_process_authentication_method;
393 m_state_name[ 4] = wxT("process_process_authentication_method")L"process_process_authentication_method";
394 m_process_state[ 5] = &CSocks5StateMachine::process_send_authentication_gssapi;
395 m_state_name[ 5] = wxT("process_send_authentication_gssapi")L"process_send_authentication_gssapi";
396 m_process_state[ 6] = &CSocks5StateMachine::process_receive_authentication_gssapi;
397 m_state_name[ 6] = wxT("process_receive_authentication_gssapi")L"process_receive_authentication_gssapi";
398 m_process_state[ 7] = &CSocks5StateMachine::process_process_authentication_gssapi;
399 m_state_name[ 7] = wxT("process_process_authentication_gssapi")L"process_process_authentication_gssapi";
400 m_process_state[ 8] = &CSocks5StateMachine::process_send_authentication_username_password;
401 m_state_name[ 8] = wxT("process_send_authentication_username_password")L"process_send_authentication_username_password";
402 m_process_state[ 9] = &CSocks5StateMachine::process_receive_authentication_username_password;
403 m_state_name[ 9] = wxT("process_receive_authentication_username_password")L"process_receive_authentication_username_password";
404 m_process_state[10] = &CSocks5StateMachine::process_process_authentication_username_password;
405 m_state_name[10] = wxT("process_process_authentication_username_password")L"process_process_authentication_username_password";
406 m_process_state[11] = &CSocks5StateMachine::process_send_command_request;
407 m_state_name[11] = wxT("process_send_command_request")L"process_send_command_request";
408 m_process_state[12] = &CSocks5StateMachine::process_receive_command_reply;
409 m_state_name[12] = wxT("process_receive_command_reply")L"process_receive_command_reply";
410 m_process_state[13] = &CSocks5StateMachine::process_process_command_reply;
411 m_state_name[13] = wxT("process_process_command_reply")L"process_process_command_reply";
412}
413
414void CSocks5StateMachine::process_state(t_sm_state state, bool entry)
415{
416 /* Ok, the syntax is terrible, but this is correct. This is a
417 * pointer to a member function. No C equivalent for that. */
418 (this->*m_process_state[state])(entry);
419
420#ifdef __DEBUG__
421#if DEBUG_DUMP_PROXY_MSG0
422 int n = 0;
423
424 switch (state) {
425 case SOCKS5_STATE_START:
426 case SOCKS5_STATE_END:
427 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
428 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
429 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
430 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
431 default:
432 n = 0;
433 break;
434
435 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
436 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
437 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
438 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
439 n = m_packetLenght;
440 break;
441
442 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
443 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
444 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
445 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
446 n = m_lastRead;
447 break;
448 }
449
450 if (entry) {
451 DumpMem(m_buffer, n, m_state_name[state], m_ok);
452 }
453#endif
454 AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState())do {} while (false);
455#endif // __DEBUG__
456}
457
458/**
459 * Code this such that the next state is only entered when it is able to
460 * perform the operation (read or write). State processing will assume
461 * that it can read or write upon entry of the state. This is done using
462 * CanSend() and CanReceive().
463 */
464t_sm_state CSocks5StateMachine::next_state(t_sm_event event)
465{
466 // Default is stay in current state
467 t_sm_state ret = HandleEvent(event);
468 switch (GetState()) {
469 case SOCKS5_STATE_START:
470 if (m_isConnected && !m_isLost && CanSend()) {
471 ret = SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD;
472 }
473 break;
474
475 case SOCKS5_STATE_SEND_QUERY_AUTHENTICATION_METHOD:
476 if (CanReceive()) {
477 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD;
478 }
479 break;
480
481 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_METHOD:
482 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD;
483 break;
484
485 case SOCKS5_STATE_PROCESS_AUTHENTICATION_METHOD:
486 if (m_ok) {
487 if (CanSend()) {
488 switch (m_lastReply) {
489 case SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED:
490 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
491 break;
492
493 case SOCKS5_AUTH_METHOD_GSSAPI:
494 ret = SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI;
495 break;
496
497 case SOCKS5_AUTH_METHOD_USERNAME_PASSWORD:
498 ret = SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD;
499 break;
500
501 case SOCKS5_AUTH_METHOD_NO_ACCEPTABLE_METHODS:
502 default:
503 ret = SOCKS5_STATE_END;
504 break;
505 }
506 } else {
507 AddDebugLogLineN(logProxy, wxT("Can't send"))do {} while (false);
508 }
509 } else {
510 ret = SOCKS5_STATE_END;
511 }
512 break;
513
514 case SOCKS5_STATE_SEND_AUTHENTICATION_GSSAPI:
515 if (m_ok) {
516 if (CanReceive()) {
517 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI;
518 }
519 } else {
520 ret = SOCKS5_STATE_END;
521 }
522 break;
523
524 case SOCKS5_STATE_SEND_AUTHENTICATION_USERNAME_PASSWORD:
525 if (m_ok) {
526 if (CanReceive()) {
527 ret = SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD;
528 }
529 } else {
530 ret = SOCKS5_STATE_END;
531 }
532 break;
533
534 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_GSSAPI:
535 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI;
536 break;
537
538 case SOCKS5_STATE_RECEIVE_AUTHENTICATION_USERNAME_PASSWORD:
539 ret = SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD;
540 break;
541
542 case SOCKS5_STATE_PROCESS_AUTHENTICATION_GSSAPI:
543 case SOCKS5_STATE_PROCESS_AUTHENTICATION_USERNAME_PASSWORD:
544 if (m_ok) {
545 if (CanSend()) {
546 ret = SOCKS5_STATE_SEND_COMMAND_REQUEST;
547 }
548 } else {
549 ret = SOCKS5_STATE_END;
550 }
551 break;
552
553 case SOCKS5_STATE_SEND_COMMAND_REQUEST:
554 if (m_ok) {
555 if (CanReceive()) {
556 ret = SOCKS5_STATE_RECEIVE_COMMAND_REPLY;
557 }
558 } else {
559 ret = SOCKS5_STATE_END;
560 }
561 break;
562
563 case SOCKS5_STATE_RECEIVE_COMMAND_REPLY:
564 ret = SOCKS5_STATE_PROCESS_COMMAND_REPLY;
565 break;
566
567 case SOCKS5_STATE_PROCESS_COMMAND_REPLY:
568 ret = SOCKS5_STATE_END;
569 break;
570
571 case SOCKS5_STATE_END:
572 default:
573 break;
574 }
575
576 return ret;
577}
578
579/**
580 * So, this is how you do it: the state machine is clocked by the events
581 * that happen inside the event handler. You can add a dummy event whenever
582 * you see that the system will not generate an event. But don't add dummy
583 * events before reads, reads should only be performed after input events.
584 *
585 * Maybe it makes sense to add a dummy event before a read if there is no
586 * state change (wait state).
587 *
588 * The event system will generate at least 2 events, one wxSOCKET_CONNECTION,
589 * one wxSOCKET_OUTPUT, so we will have 2 clocks in our state machine. Plus, each
590 * time there is unread data in the receive buffer of the socket, a wxSOCKET_INPUT
591 * event will be generated. If you feel you will need more clocks than these, use
592 * AddDummyEvent(), but I suggest you review your state machine design first.
593 */
594void CSocks5StateMachine::process_start(bool)
595{}
596
597void CSocks5StateMachine::process_end(bool)
598{
599 ReactivateSocket();
600}
601
602void CSocks5StateMachine::process_send_query_authentication_method(bool entry)
603{
604 if (entry) {
605 // Prepare the authentication method negotiation packet
606 m_buffer[0] = SOCKS5_VERSION;
607 m_buffer[1] = 1; // Number of supported methods
608 m_buffer[2] = SOCKS5_AUTH_METHOD_NO_AUTH_REQUIRED;
609 m_packetLenght = 3;
610 if (m_proxyData.m_enablePassword) {
611 // add SOCKS5_AUTH_METHOD_GSSAPI here if we ever implement
612 // GSS-API authentication
613 m_buffer[1] = 2;
614 m_buffer[3] = SOCKS5_AUTH_METHOD_USERNAME_PASSWORD;
615 m_packetLenght = 4;
616 }
617
618 // Send the authentication method negotiation packet
619 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
620 }
621}
622
623void CSocks5StateMachine::process_receive_authentication_method(bool entry)
624{
625 if (entry) {
626 // Receive the method selection message
627 m_packetLenght = 2;
628 ProxyRead(*m_proxyClientSocket, m_buffer);
629 }
630 /* This is added because there will be no more input events. If the
631 * world was a nice place, we could think about joining the
632 * process_receive and the process_process states here, but some day
633 * we might have to deal with the fact that the i/o operation has been
634 * incomplete, and that we must finish our job the next time we enter
635 * this state. */
636 AddDummyEvent();
637}
638
639void CSocks5StateMachine::process_process_authentication_method(bool entry)
640{
641 if (entry) {
642 m_lastReply = m_buffer[1];
643 m_ok = m_ok && m_buffer[0] == SOCKS5_VERSION;
644 }
645 /* Ok, this one is here because wxSOCKET_OUTPUT events only happen
646 * once when you connect the socket, and after that, only after a
647 * wxSOCKET_WOULDBLOCK error happens. */
648 AddDummyEvent();
649}
650
651void CSocks5StateMachine::process_send_authentication_gssapi(bool)
652{
653 // TODO or not TODO? That is the question...
654 m_ok = false;
655}
656
657void CSocks5StateMachine::process_receive_authentication_gssapi(bool)
658{
659 AddDummyEvent();
660}
661
662void CSocks5StateMachine::process_process_authentication_gssapi(bool)
663{
664 AddDummyEvent();
665}
666
667void CSocks5StateMachine::process_send_authentication_username_password(bool entry)
668{
669 if (entry) {
670 unsigned char lenUser = m_proxyData.m_userName.Len();
671 unsigned char lenPassword = m_proxyData.m_password.Len();
672 m_packetLenght = 1 + 1 + lenUser + 1 + lenPassword;
673 unsigned int offsetUser = 2;
674 unsigned int offsetPassword = offsetUser + lenUser + 1;
675
676 // Prepare username/password buffer
677 m_buffer[0] = SOCKS5_AUTH_VERSION_USERNAME_PASSWORD;
678 m_buffer[offsetUser-1] = lenUser;
679 memcpy(m_buffer+offsetUser, unicode2char(m_proxyData.m_userName),
680 lenUser);
681 m_buffer[offsetPassword-1] = lenPassword;
682 memcpy(m_buffer+offsetPassword, unicode2char(m_proxyData.m_password),
683 lenPassword);
684
685 // Send the username/password packet
686 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
687 }
688}
689
690void CSocks5StateMachine::process_receive_authentication_username_password(bool entry)
691{
692 if (entry) {
693 // Receive the server's authentication response
694 m_packetLenght = 2;
695 ProxyRead(*m_proxyClientSocket, m_buffer);
696 }
697 AddDummyEvent();
698}
699
700void CSocks5StateMachine::process_process_authentication_username_password(bool entry)
701{
702 if (entry) {
703 // Process the server's reply
704 m_lastReply = m_buffer[1];
705 m_ok = m_ok &&
706 m_buffer[0] == SOCKS5_AUTH_VERSION_USERNAME_PASSWORD &&
707 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
708 }
709 AddDummyEvent();
710}
711
712void CSocks5StateMachine::process_send_command_request(bool entry)
713{
714 if (entry) {
715 // Prepare the request command buffer
716 m_buffer[0] = SOCKS5_VERSION;
717 switch (m_proxyCommand) {
718 case PROXY_CMD_CONNECT:
719 m_buffer[1] = SOCKS5_CMD_CONNECT;
720 break;
721
722 case PROXY_CMD_BIND:
723 m_buffer[1] = SOCKS5_CMD_BIND;
724 break;
725
726 case PROXY_CMD_UDP_ASSOCIATE:
727 m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
728 break;
729 }
730 m_buffer[2] = SOCKS5_RSV;
731 m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
732 PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
733 RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() )( ((wxUint16) ( (((wxUint16) (m_peerAddress->Service()) &
(wxUint16) 0x00ffU) << 8) | (((wxUint16) (m_peerAddress
->Service()) & (wxUint16) 0xff00U) >> 8))) )
);
734
735 // Send the command packet
736 m_packetLenght = 10;
737 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
738 }
739}
740
741void CSocks5StateMachine::process_receive_command_reply(bool entry)
742{
743 if (entry) {
744 // The minimum number of bytes to read is 10 in the case of
745 // ATYP == SOCKS5_ATYP_IPV4_ADDRESS
746 m_packetLenght = 10;
747 ProxyRead(*m_proxyClientSocket, m_buffer);
748 }
749 AddDummyEvent();
750}
751
752void CSocks5StateMachine::process_process_command_reply(bool entry)
753{
754 if (entry) {
755 m_lastReply = m_buffer[1];
756 unsigned char addressType = m_buffer[3];
757 // Process the server's reply
758 m_ok = m_ok &&
759 m_buffer[0] == SOCKS5_VERSION &&
760 m_buffer[1] == SOCKS5_REPLY_SUCCEED;
761 if (m_ok) {
762 // Read BND.ADDR
763 unsigned int portOffset = 0;
764 switch(addressType) {
765 case SOCKS5_ATYP_IPV4_ADDRESS:
766 {
767 const unsigned int addrOffset = 4;
768 portOffset = 8;
769 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset) );
770 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
771 break;
772 }
773 case SOCKS5_ATYP_DOMAINNAME:
774 {
775 // Read the domain name
776 const unsigned int addrOffset = 5;
777 portOffset = 10 + m_buffer[4];
778 char c = m_buffer[portOffset];
779 m_buffer[portOffset] = 0;
780 m_proxyBoundAddressIPV4.Hostname(
781 char2unicode(m_buffer+addrOffset));
782 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
783 m_buffer[portOffset] = c;
784 break;
785 }
786 case SOCKS5_ATYP_IPV6_ADDRESS:
787 {
788 portOffset = 20;
789 // TODO
790 // IPV6 not yet implemented in wx
791 //m_proxyBoundAddress.Hostname(Uint128toStringIP(
792 // *((uint128 *)(m_buffer+addrOffset)) ));
793 //m_proxyBoundAddress = &m_proxyBoundAddressIPV6;
794 m_ok = false;
795 break;
796 }
797 }
798 // Set the packet length at last
799 m_packetLenght = portOffset + 2;
800 // Read BND.PORT
801 m_proxyBoundAddress->Service( ENDIAN_NTOHS( RawPeekUInt16( m_buffer+portOffset) )( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( m_buffer+portOffset
)) & (wxUint16) 0x00ffU) << 8) | (((wxUint16) (RawPeekUInt16
( m_buffer+portOffset)) & (wxUint16) 0xff00U) >> 8)
)) )
);
802 }
803 }
804 AddDummyEvent();
805}
806
807//------------------------------------------------------------------------------
808// CSocks4StateMachine
809//------------------------------------------------------------------------------
810
811CSocks4StateMachine::CSocks4StateMachine(
812 const CProxyData &proxyData,
813 CProxyCommand proxyCommand)
814:
815CProxyStateMachine(
816 wxString(wxT("Socks4")L"Socks4"), SOCKS4_MAX_STATES, proxyData, proxyCommand)
817{
818 m_process_state[0] = &CSocks4StateMachine::process_start;
819 m_state_name[0] = wxT("process_start")L"process_start";
820 m_process_state[1] = &CSocks4StateMachine::process_end;
821 m_state_name[1] = wxT("process_end")L"process_end";
822 m_process_state[2] = &CSocks4StateMachine::process_send_command_request;
823 m_state_name[2] = wxT("process_send_command_request")L"process_send_command_request";
824 m_process_state[3] = &CSocks4StateMachine::process_receive_command_reply;
825 m_state_name[3] = wxT("process_receive_command_reply")L"process_receive_command_reply";
826 m_process_state[4] = &CSocks4StateMachine::process_process_command_reply;
827 m_state_name[4] = wxT("process_process_command_reply")L"process_process_command_reply";
828}
829
830void CSocks4StateMachine::process_state(t_sm_state state, bool entry)
831{
832 (this->*m_process_state[state])(entry);
833
834#ifdef __DEBUG__
835#if DEBUG_DUMP_PROXY_MSG0
836 int n = 0;
837
838 switch (state) {
839 case SOCKS4_STATE_START:
840 case SOCKS4_STATE_END:
841 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
842 default:
843 n = 0;
844 break;
845
846 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
847 n = m_packetLenght;
848 break;
849
850 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
851 n = m_lastRead;
852 break;
853 }
854
855 if (entry) {
856 DumpMem(m_buffer, n, m_state_name[state], m_ok);
857 }
858#endif
859 AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState())do {} while (false);
860#endif // __DEBUG__
861}
862
863t_sm_state CSocks4StateMachine::next_state(t_sm_event event)
864{
865 // Default is stay in current state
866 t_sm_state ret = HandleEvent(event);
867 switch (GetState()) {
868 case SOCKS4_STATE_START:
869 if (m_isConnected && !m_isLost && CanSend()) {
870 ret = SOCKS4_STATE_SEND_COMMAND_REQUEST;
871 }
872 break;
873
874 case SOCKS4_STATE_SEND_COMMAND_REQUEST:
875 if (m_ok) {
876 if (CanReceive()) {
877 ret = SOCKS4_STATE_RECEIVE_COMMAND_REPLY;
878 }
879 } else {
880 ret = SOCKS4_STATE_END;
881 }
882 break;
883
884 case SOCKS4_STATE_RECEIVE_COMMAND_REPLY:
885 ret = SOCKS4_STATE_PROCESS_COMMAND_REPLY;
886 break;
887
888 case SOCKS4_STATE_PROCESS_COMMAND_REPLY:
889 ret = SOCKS4_STATE_END;
890 break;
891
892 case SOCKS4_STATE_END:
893 default:
894 break;
895 }
896
897 return ret;
898}
899
900void CSocks4StateMachine::process_start(bool)
901{}
902
903void CSocks4StateMachine::process_end(bool)
904{
905 ReactivateSocket();
906}
907
908void CSocks4StateMachine::process_send_command_request(bool entry)
909{
910 if (entry) {
911 // Prepare the request command buffer
912 m_buffer[0] = SOCKS4_VERSION;
913 switch (m_proxyCommand) {
914 case PROXY_CMD_CONNECT:
915 m_buffer[1] = SOCKS4_CMD_CONNECT;
916 break;
917
918 case PROXY_CMD_BIND:
919 m_buffer[1] = SOCKS4_CMD_BIND;
920 break;
921
922 case PROXY_CMD_UDP_ASSOCIATE:
923 m_ok = false;
924 return;
925 break;
926 }
927 RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service())( ((wxUint16) ( (((wxUint16) (m_peerAddress->Service()) &
(wxUint16) 0x00ffU) << 8) | (((wxUint16) (m_peerAddress
->Service()) & (wxUint16) 0xff00U) >> 8))) )
);
928 // Special processing for SOCKS4a
929 switch (m_proxyData.m_proxyType) {
930 case PROXY_SOCKS4a:
931 PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")L"0.0.0.1"));
932 break;
933 case PROXY_SOCKS4:
934 default:
935 PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
936 break;
937 }
938 // Common processing for SOCKS4/SOCKS4a
939 unsigned int offsetUser = 8;
940 unsigned char lenUser = 0;
941 if (m_proxyData.m_enablePassword) {
942 lenUser = m_proxyData.m_userName.Len();
943 memcpy(m_buffer + offsetUser, unicode2char(m_proxyData.m_userName), lenUser);
944 }
945 m_buffer[offsetUser + lenUser] = 0;
946 // Special processing for SOCKS4a
947 switch (m_proxyData.m_proxyType) {
948 case PROXY_SOCKS4a: {
949 unsigned int offsetDomain = offsetUser + lenUser + 1;
950 // The Hostname() method was used here before, but I don't see why we can't use
951 // the IP address which we actually know instead here.
952 wxString hostname(m_peerAddress->IPAddress());
953 unsigned char lenDomain = hostname.Len();
954 memcpy(m_buffer + offsetDomain,
955 unicode2char(hostname), lenDomain);
956 m_buffer[offsetDomain + lenDomain] = 0;
957 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
958 break;
959 }
960 case PROXY_SOCKS4:
961 default:
962 m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
963 break;
964 }
965 // Send the command packet
966 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
967 }
968}
969
970void CSocks4StateMachine::process_receive_command_reply(bool entry)
971{
972 if (entry) {
973 // Receive the server's reply
974 m_packetLenght = 8;
975 ProxyRead(*m_proxyClientSocket, m_buffer);
976 }
977 AddDummyEvent();
978}
979
980void CSocks4StateMachine::process_process_command_reply(bool entry)
981{
982 if (entry) {
983 m_lastReply = m_buffer[1];
984
985 // Process the server's reply
986 m_ok = m_ok &&
987 m_buffer[0] == SOCKS4_REPLY_CODE &&
988 m_buffer[1] == SOCKS4_REPLY_GRANTED;
989 if (m_ok) {
990 // Read BND.PORT
991 const unsigned int portOffset = 2;
992 m_ok = m_proxyBoundAddressIPV4.Service(ENDIAN_NTOHS(( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( m_buffer+portOffset
)) & (wxUint16) 0x00ffU) << 8) | (((wxUint16) (RawPeekUInt16
( m_buffer+portOffset)) & (wxUint16) 0xff00U) >> 8)
)) )
993 RawPeekUInt16( m_buffer+portOffset) )( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( m_buffer+portOffset
)) & (wxUint16) 0x00ffU) << 8) | (((wxUint16) (RawPeekUInt16
( m_buffer+portOffset)) & (wxUint16) 0xff00U) >> 8)
)) )
);
994 // Read BND.ADDR
995 const unsigned int addrOffset = 4;
996 m_ok = m_ok &&
997 m_proxyBoundAddressIPV4.Hostname( PeekUInt32( m_buffer+addrOffset ) );
998 m_proxyBoundAddress = &m_proxyBoundAddressIPV4;
999 }
1000 }
1001 AddDummyEvent();
1002}
1003
1004//------------------------------------------------------------------------------
1005// CHttpStateMachine
1006//------------------------------------------------------------------------------
1007
1008CHttpStateMachine::CHttpStateMachine(
1009 const CProxyData &proxyData,
1010 CProxyCommand proxyCommand)
1011:
1012CProxyStateMachine(
1013 wxString(wxT("Http")L"Http"), HTTP_MAX_STATES, proxyData, proxyCommand)
1014{
1015 m_process_state[0] = &CHttpStateMachine::process_start;
1016 m_state_name[0] = wxT("process_start")L"process_start";
1017 m_process_state[1] = &CHttpStateMachine::process_end;
1018 m_state_name[1] = wxT("process_end")L"process_end";
1019 m_process_state[2] = &CHttpStateMachine::process_send_command_request;
1020 m_state_name[2] = wxT("process_send_command_request")L"process_send_command_request";
1021 m_process_state[3] = &CHttpStateMachine::process_receive_command_reply;
1022 m_state_name[3] = wxT("process_receive_command_reply")L"process_receive_command_reply";
1023 m_process_state[4] = &CHttpStateMachine::process_process_command_reply;
1024 m_state_name[4] = wxT("process_process_command_reply")L"process_process_command_reply";
1025}
1026
1027void CHttpStateMachine::process_state(t_sm_state state, bool entry)
1028{
1029 (this->*m_process_state[state])(entry);
1030
1031#ifdef __DEBUG__
1032#if DEBUG_DUMP_PROXY_MSG0
1033 int n = 0;
1034
1035 switch (state) {
1036 case HTTP_STATE_START:
1037 case HTTP_STATE_END:
1038 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1039 default:
1040 n = 0;
1041 break;
1042
1043 case HTTP_STATE_SEND_COMMAND_REQUEST:
1044 n = m_packetLenght;
1045 break;
1046
1047 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1048 n = m_lastRead;
1049 break;
1050 }
1051
1052 if (entry) {
1053 DumpMem(m_buffer, n, m_state_name[state], m_ok);
1054 }
1055#endif
1056 AddDebugLogLineN(logProxy, CFormat(wxString(wxT("state: %s clocks: %u"))) % m_state_name[state] % GetClocksInCurrentState())do {} while (false);
1057#endif // __DEBUG__
1058}
1059
1060t_sm_state CHttpStateMachine::next_state(t_sm_event event)
1061{
1062 // Default is stay in current state
1063 t_sm_state ret = HandleEvent(event);
1064 switch (GetState()) {
1065 case HTTP_STATE_START:
1066 if (m_isConnected && !m_isLost && CanSend()) {
1067 ret = HTTP_STATE_SEND_COMMAND_REQUEST;
1068 }
1069 break;
1070
1071 case HTTP_STATE_SEND_COMMAND_REQUEST:
1072 if (m_ok) {
1073 if (CanReceive()) {
1074 ret = HTTP_STATE_RECEIVE_COMMAND_REPLY;
1075 }
1076 } else {
1077 ret = HTTP_STATE_END;
1078 }
1079 break;
1080
1081 case HTTP_STATE_RECEIVE_COMMAND_REPLY:
1082 ret = HTTP_STATE_PROCESS_COMMAND_REPLY;
1083 break;
1084
1085 case HTTP_STATE_PROCESS_COMMAND_REPLY:
1086 ret = HTTP_STATE_END;
1087 break;
1088
1089 case HTTP_STATE_END:
1090 default:
1091 break;
1092 }
1093
1094 return ret;
1095}
1096
1097void CHttpStateMachine::process_start(bool)
1098{}
1099
1100void CHttpStateMachine::process_end(bool)
1101{
1102 ReactivateSocket();
1103}
1104
1105void CHttpStateMachine::process_send_command_request(bool entry)
1106{
1107 if (entry) {
1108 // Prepare the request command buffer
1109 wxString ip = m_peerAddress->IPAddress();
1110 uint16 port = m_peerAddress->Service();
1111 wxString userPass;
1112 wxString userPassEncoded;
1113 if (m_proxyData.m_enablePassword) {
1114 userPass = m_proxyData.m_userName + wxT(":")L":" + m_proxyData.m_password;
1115 userPassEncoded =
1116 EncodeBase64(unicode2char(userPass), userPass.Length()).Trim();
1117 }
1118 wxString msg;
1119
1120 switch (m_proxyCommand) {
1121 case PROXY_CMD_CONNECT:
1122 msg <<
1123 wxT("CONNECT ")L"CONNECT " << ip << wxT(":")L":" << port << wxT(" HTTP/1.1\r\n")L" HTTP/1.1\r\n" <<
1124 wxT("Host: ")L"Host: " << ip << wxT(":")L":" << port << wxT("\r\n")L"\r\n";
1125 if (m_proxyData.m_enablePassword) {
1126 msg << wxT("Proxy-Authorization: Basic ")L"Proxy-Authorization: Basic " << userPassEncoded << wxT("\r\n")L"\r\n";
1127 }
1128 msg << wxT("\r\n")L"\r\n";
1129 break;
1130
1131 case PROXY_CMD_BIND:
1132 m_ok = false;
1133 break;
1134
1135 case PROXY_CMD_UDP_ASSOCIATE:
1136 m_ok = false;
1137 return;
1138 break;
1139 }
1140 // Send the command packet
1141 m_packetLenght = msg.Len();
1142 memcpy(m_buffer, unicode2char(msg), m_packetLenght+1);
1143 ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
1144 }
1145}
1146
1147void CHttpStateMachine::process_receive_command_reply(bool entry)
1148{
1149 if (entry) {
1150 // Receive the server's reply -- Use a large number, but don't
1151 // Expect to get it all. HTTP protocol does not have a fixed length.
1152 m_packetLenght = PROXY_BUFFER_SIZE;
1153 ProxyRead(*m_proxyClientSocket, m_buffer);
1154 }
1155 AddDummyEvent();
1156}
1157
1158/*
1159 * HTTP Proxy server response should be something like:
1160 * "HTTP/1.1 200 Connection established\r\n\r\n"
1161 * but that may vary. The important thing is the "200"
1162 * code, that means success.
1163 */
1164static const char HTTP_AUTH_RESPONSE[] = "HTTP/";
1165static const int HTTP_AUTH_RESPONSE_LENGHT = strlen(HTTP_AUTH_RESPONSE);
1166void CHttpStateMachine::process_process_command_reply(bool entry)
1167{
1168 if (entry) {
1169 // The position of the first space in the buffer
1170 int i = 8;
1171 while (m_buffer[i] == ' ') {
1172 i++;
1173 }
1174 // Process the server's reply
1175 m_ok = !memcmp(m_buffer + 0, HTTP_AUTH_RESPONSE, HTTP_AUTH_RESPONSE_LENGHT) &&
1176 !memcmp(m_buffer + i, "200", 3);
1177 }
1178 AddDummyEvent();
1179}
1180
1181//------------------------------------------------------------------------------
1182// CProxySocket
1183//------------------------------------------------------------------------------
1184
1185CProxySocket::CProxySocket(
1186 muleSocketFlags flags,
1187 const CProxyData *proxyData,
1188 CProxyCommand proxyCommand,
1189 CDatagramSocketProxy *udpSocket)
1190:
1191CLibSocket(flags),
1192m_proxyStateMachine(NULL__null),
1193m_udpSocket(udpSocket)
1194#ifndef ASIO_SOCKETS
1195,m_socketEventHandler(NULL__null)
1196,m_socketEventHandlerId(0)
1197,m_savedSocketEventHandler(NULL__null)
1198,m_savedSocketEventHandlerId(0)
1199#endif
1200{
1201 SetProxyData(proxyData);
1202 if (m_useProxy) {
1203 switch (m_proxyData.m_proxyType) {
1204 case PROXY_NONE:
1205 break;
1206
1207 case PROXY_SOCKS5:
1208 m_proxyStateMachine =
1209 new CSocks5StateMachine(*proxyData, proxyCommand);
1210 break;
1211
1212 case PROXY_SOCKS4:
1213 case PROXY_SOCKS4a:
1214 m_proxyStateMachine =
1215 new CSocks4StateMachine(*proxyData, proxyCommand);
1216 break;
1217
1218 case PROXY_HTTP:
1219 m_proxyStateMachine =
1220 new CHttpStateMachine(*proxyData, proxyCommand);
1221 break;
1222
1223 default:
1224 break;
1225 }
1226 }
1227}
1228
1229CProxySocket::~CProxySocket()
1230{
1231 delete m_proxyStateMachine;
1232}
1233
1234void CProxySocket::SetProxyData(const CProxyData *proxyData)
1235{
1236 m_useProxy = proxyData != NULL__null && proxyData->m_proxyEnable;
1237 if (proxyData) {
1238 m_proxyData = *proxyData;
1239 m_proxyAddress.Hostname(m_proxyData.m_proxyHostName);
1240 m_proxyAddress.Service(m_proxyData.m_proxyPort);
1241 } else {
1242 m_proxyData.Clear();
1243 }
1244}
1245
1246bool CProxySocket::Start(const amuleIPV4Address &peerAddress)
1247{
1248#ifdef ASIO_SOCKETS
1249 SetProxyState(true, &peerAddress);
1250#else
1251 SaveState();
1252 // Important note! SaveState()/RestoreState() DO NOT save/restore
1253 // the event handler. The method SaveEventHandler() has been created
1254 // for that.
1255 SaveEventHandler();
1256 SetEventHandler(g_proxyEventHandler, ID_PROXY_SOCKET_EVENT);
1257 SetNotify(
1258 wxSOCKET_CONNECTION_FLAG |
1259 wxSOCKET_INPUT_FLAG |
1260 wxSOCKET_OUTPUT_FLAG |
1261 wxSOCKET_LOST_FLAG);
1262 Notify(true);
1263#endif
1264 Connect(m_proxyAddress, false);
1265 SetFlags(MULE_SOCKET_NONEwxSOCKET_NONE);
1266 return m_proxyStateMachine->Start(peerAddress, this);
1267}
1268
1269bool CProxySocket::ProxyIsCapableOf(CProxyCommand proxyCommand) const
1270{
1271 bool ret = false;
1272
1273 switch (m_proxyData.m_proxyType) {
1274 case PROXY_NONE:
1275 ret = false;
1276 break;
1277
1278 case PROXY_SOCKS5:
1279 ret = proxyCommand == PROXY_CMD_CONNECT ||
1280 proxyCommand == PROXY_CMD_BIND ||
1281 proxyCommand == PROXY_CMD_UDP_ASSOCIATE;
1282 break;
1283
1284 case PROXY_SOCKS4:
1285 case PROXY_SOCKS4a:
1286 ret = proxyCommand == PROXY_CMD_CONNECT ||
1287 proxyCommand == PROXY_CMD_BIND;
1288 break;
1289
1290 case PROXY_HTTP:
1291 ret = proxyCommand == PROXY_CMD_CONNECT;
1292 break;
1293 }
1294
1295 return ret;
1296}
1297
1298//------------------------------------------------------------------------------
1299// CSocketClientProxy
1300//------------------------------------------------------------------------------
1301
1302CSocketClientProxy::CSocketClientProxy(
1303 muleSocketFlags flags,
1304 const CProxyData *proxyData)
1305:
1306CProxySocket(flags, proxyData, PROXY_CMD_CONNECT)
1307{
1308}
1309
1310bool CSocketClientProxy::Connect(amuleIPV4Address &address, bool wait)
1311{
1312 wxMutexLocker lock(m_socketLocker);
1313 bool ok;
1314
1315 if (GetUseProxy() && ProxyIsCapableOf(PROXY_CMD_CONNECT)) {
1316 ok = Start(address);
1317 } else {
1318 ok = CLibSocket::Connect(address, wait);
1319 }
1320
1321 return ok;
1322}
1323
1324uint32 CSocketClientProxy::Read(void *buffer, wxUint32 nbytes)
1325{
1326 wxMutexLocker lock(m_socketLocker);
1327 return CProxySocket::Read(buffer, nbytes);
1328}
1329
1330uint32 CSocketClientProxy::Write(const void *buffer, wxUint32 nbytes)
1331{
1332 wxMutexLocker lock(m_socketLocker);
1333 return CProxySocket::Write(buffer, nbytes);
1334}
1335
1336//------------------------------------------------------------------------------
1337// CSocketServerProxy
1338//------------------------------------------------------------------------------
1339
1340CSocketServerProxy::CSocketServerProxy(
1341 amuleIPV4Address &address,
1342 muleSocketFlags flags,
1343 const CProxyData *)
1344:
1345CLibSocketServer(address, flags)
1346{
1347 /* Maybe some day when socks6 is out... :) */
1348}
1349
1350//------------------------------------------------------------------------------
1351// CDatagramSocketProxy
1352//------------------------------------------------------------------------------
1353
1354CDatagramSocketProxy::CDatagramSocketProxy(
1355 amuleIPV4Address &address, muleSocketFlags flags, const CProxyData *proxyData)
1356:
1357CLibUDPSocket(address, flags),
1358m_proxyTCPSocket(MULE_SOCKET_NOWAITwxSOCKET_NOWAIT, proxyData, PROXY_CMD_UDP_ASSOCIATE, this)
1359{
1360 m_udpSocketOk = false;
1361 if ( m_proxyTCPSocket.GetUseProxy() &&
1362 m_proxyTCPSocket.ProxyIsCapableOf(PROXY_CMD_UDP_ASSOCIATE)) {
1363 m_proxyTCPSocket.Start(address);
1364 } else {
1365 }
1366 m_lastUDPOperation = UDP_OPERATION_NONE;
1367}
1368
1369CDatagramSocketProxy::~CDatagramSocketProxy()
1370{
1371 // From RFC-1928:
1372 // "A UDP association terminates when the TCP connection that the
1373 // UDP ASSOCIATE request arrived terminates."
1374}
1375
1376uint32 CDatagramSocketProxy::RecvFrom(amuleIPV4Address& addr, void* buf, uint32 nBytes)
1377{
1378 uint32 read = 0;
1379 wxMutexLocker lock(m_socketLocker);
1380 m_lastUDPOperation = UDP_OPERATION_RECV_FROM;
1381 if (m_proxyTCPSocket.GetUseProxy()) {
1382 if (m_udpSocketOk) {
1383 char *bufUDP = NULL__null;
1384 if (nBytes + PROXY_UDP_MAXIMUM_OVERHEAD > PROXY_BUFFER_SIZE) {
1385 bufUDP = new char[nBytes + PROXY_UDP_MAXIMUM_OVERHEAD];
1386 } else {
1387 bufUDP = m_proxyTCPSocket.GetBuffer();
1388 }
1389 read = CLibUDPSocket::RecvFrom(
1390 m_proxyTCPSocket.GetProxyBoundAddress(),
1391 bufUDP, nBytes + PROXY_UDP_MAXIMUM_OVERHEAD);
1392 unsigned int offset;
1393 switch (m_proxyTCPSocket.GetBuffer()[3]) {
1394 case SOCKS5_ATYP_IPV4_ADDRESS: {
1395 offset = PROXY_UDP_OVERHEAD_IPV4;
1396 try {
1397 amuleIPV4Address &a = dynamic_cast<amuleIPV4Address &>(addr);
1398 a.Hostname( PeekUInt32( m_proxyTCPSocket.GetBuffer()+4 ) );
1399 a.Service( ENDIAN_NTOHS( RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8) )( ((wxUint16) ( (((wxUint16) (RawPeekUInt16( m_proxyTCPSocket
.GetBuffer()+8)) & (wxUint16) 0x00ffU) << 8) | (((wxUint16
) (RawPeekUInt16( m_proxyTCPSocket.GetBuffer()+8)) & (wxUint16
) 0xff00U) >> 8))) )
);
1400 } catch (const std::bad_cast& WXUNUSED(e)) {
1401 AddDebugLogLineN(logProxy,do {} while (false)
1402 wxT("(2)bad_cast exception!"))do {} while (false);
1403 wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("Proxy.cpp"
, 1403, __FUNCTION__, "\"Assert failure\"", (const char*)__null
), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile (
"int $3"); } } while ( (void)0, 0 )
;
1404 }
1405 }
1406 break;
1407
1408 case SOCKS5_ATYP_DOMAINNAME:
1409 offset = PROXY_UDP_OVERHEAD_DOMAIN_NAME;
1410 break;
1411
1412 case SOCKS5_ATYP_IPV6_ADDRESS:
1413 offset = PROXY_UDP_OVERHEAD_IPV6;
1414 break;
1415
1416 default:
1417 /* Error! */
1418 offset = 0;
1419 break;
1420 }
1421 memcpy(buf, bufUDP + offset, nBytes);
1422 // Uncomment here to see the buffer contents on console
1423 // DumpMem(bufUDP, wxDatagramSocket::LastCount(), wxT("RecvFrom"), 3);
1424
1425 /* Only delete buffer if it was dynamically created */
1426 if (bufUDP != m_proxyTCPSocket.GetBuffer()) {
1427 /* We should use a fixed buffer to avoid
1428 * new/delete it all the time.
1429 * I need an upper bound */
1430 delete [] bufUDP;
1431 }
1432 /* There is still one problem pending, fragmentation.
1433 * Either we support it or we have to drop fragmented
1434 * messages. I vote for drop :)
1435 */
1436 }
1437 } else {
1438 read = CLibUDPSocket::RecvFrom(addr, buf, nBytes);
1439 }
1440
1441 return read;
1442}
1443
1444uint32 CDatagramSocketProxy::SendTo(const amuleIPV4Address& addr, const void* buf, uint32 nBytes)
1445{
1446 uint32 sent = 0;
1447 wxMutexLocker lock(m_socketLocker);
1448 m_lastUDPOperation = UDP_OPERATION_SEND_TO;
1449 m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
1450 if (m_proxyTCPSocket.GetUseProxy()) {
1451 if (m_udpSocketOk) {
1452 m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV; // Reserved
1453 m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV; // Reserved
1454 m_proxyTCPSocket.GetBuffer()[2] = 0; // FRAG
1455 m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
1456 PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
1457 RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() )( ((wxUint16) ( (((wxUint16) (addr.Service()) & (wxUint16
) 0x00ffU) << 8) | (((wxUint16) (addr.Service()) & (
wxUint16) 0xff00U) >> 8))) )
);
1458 memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
1459 nBytes += PROXY_UDP_OVERHEAD_IPV4;
1460 sent = CLibUDPSocket::SendTo(
1461 m_proxyTCPSocket.GetProxyBoundAddress(),
1462 m_proxyTCPSocket.GetBuffer(), nBytes);
1463 // Uncomment here to see the buffer contents on console
1464 // DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
1465 }
1466 } else {
1467 sent = CLibUDPSocket::SendTo(addr, buf, nBytes);
1468 }
1469
1470 return sent;
1471}
1472
1473#endif // CLIENT_GUI
1474
1475/******************************************************************************/
1476// File_checked_for_headers