gloox 1.0.27
connectionsocks5proxy.cpp
1/*
2 Copyright (c) 2007-2023 by Jakob Schröter <js@camaya.net>
3 This file is part of the gloox library. http://camaya.net/gloox
4
5 This software is distributed under a license. The full license
6 agreement can be found in the file LICENSE in this distribution.
7 This software may not be copied, modified, sold or distributed
8 other than expressed in the named license agreement.
9
10 This software is distributed without any warranty.
11*/
12
13
14
15#include "config.h"
16
17#include "gloox.h"
18
19#include "connectionsocks5proxy.h"
20#include "dns.h"
21#include "logsink.h"
22#include "prep.h"
23#include "base64.h"
24#include "util.h"
25
26#include <string>
27#include <cstdlib>
28
29#include <string.h>
30
31#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
32# include <netinet/in.h>
33#endif
34
35#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
36# include <winsock.h>
37#elif defined( _WIN32_WCE )
38# include <winsock2.h>
39#endif
40
41namespace gloox
42{
43
45 const LogSink& logInstance,
46 const std::string& server,
47 int port, bool ip )
48 : ConnectionBase( 0 ), m_connection( connection ),
49 m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
50 {
51// FIXME check return value?
53 m_port = port;
54
55 if( m_connection )
56 m_connection->registerConnectionDataHandler( this );
57 }
58
60 ConnectionBase* connection,
61 const LogSink& logInstance,
62 const std::string& server,
63 int port, bool ip )
64 : ConnectionBase( cdh ), m_connection( connection ),
65 m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
66 {
67// FIXME check return value?
69 m_port = port;
70
71 if( m_connection )
72 m_connection->registerConnectionDataHandler( this );
73 }
74
76 {
77 if( m_connection )
78 delete m_connection;
79 }
80
82 {
83 ConnectionBase* conn = m_connection ? m_connection->newInstance() : 0;
84 return new ConnectionSOCKS5Proxy( m_handler, conn, m_logInstance, m_server, m_port, m_ip );
85 }
86
88 {
89 if( m_connection )
90 delete m_connection;
91
92 m_connection = connection;
93 }
94
96 {
97// FIXME CHECKME
98 if( m_connection && m_connection->state() == StateConnected && m_handler )
99 {
101 m_s5state = S5StateConnected;
102 return ConnNoError;
103 }
104
105 if( m_connection && m_handler )
106 {
108 m_s5state = S5StateConnecting;
109 return m_connection->connect();
110 }
111
112 return ConnNotConnected;
113 }
114
116 {
117 if( m_connection )
118 m_connection->disconnect();
119 cleanup();
120 }
121
123 {
124 if( m_connection )
125 return m_connection->recv( timeout );
126 else
127 return ConnNotConnected;
128 }
129
131 {
132 if( m_connection )
133 return m_connection->receive();
134 else
135 return ConnNotConnected;
136 }
137
138 bool ConnectionSOCKS5Proxy::send( const std::string& data )
139 {
140// if( m_s5state != S5StateConnected )
141// {
142// printf( "p data sent: " );
143// const char* x = data.c_str();
144// for( unsigned int i = 0; i < data.length(); ++i )
145// printf( "%02X ", (const char)x[i] );
146// printf( "\n" );
147// }
148
149 if( m_connection )
150 return m_connection->send( data );
151
152 return false;
153 }
154
156 {
158 m_s5state = S5StateDisconnected;
159
160 if( m_connection )
161 m_connection->cleanup();
162 }
163
164 void ConnectionSOCKS5Proxy::getStatistics( long int &totalIn, long int &totalOut )
165 {
166 if( m_connection )
167 m_connection->getStatistics( totalIn, totalOut );
168 else
169 {
170 totalIn = 0;
171 totalOut = 0;
172 }
173 }
174
176 const std::string& data )
177 {
178 if( !m_connection || !m_handler )
179 return;
180
181 if( m_s5state != S5StateConnected )
182 m_proxyHandshakeBuffer += data;
183
184 ConnectionError connError = ConnNoError;
185
186 switch( m_s5state )
187 {
188 case S5StateConnecting:
189 if( m_proxyHandshakeBuffer.length() < 2 )
190 return;
191
192 if( m_proxyHandshakeBuffer.length() != 2 || m_proxyHandshakeBuffer[0] != 0x05 )
193 connError = ConnIoError;
194
195 if( m_proxyHandshakeBuffer[1] == 0x00 ) // no auth
196 {
197 negotiate();
198 }
199 else if( m_proxyHandshakeBuffer[1] == 0x02 && !m_proxyUser.empty() && !m_proxyPwd.empty() ) // user/password auth
200 {
202 "authenticating to socks5 proxy as user " + m_proxyUser );
203 m_s5state = S5StateAuthenticating;
204 char* d = new char[3 + m_proxyUser.length() + m_proxyPwd.length()];
205 size_t pos = 0;
206 d[pos++] = 0x01;
207 d[pos++] = static_cast<char>( m_proxyUser.length() );
208 strncpy( d + pos, m_proxyUser.c_str(), m_proxyUser.length() );
209 pos += m_proxyUser.length();
210 d[pos++] = static_cast<char>( m_proxyPwd.length() );
211 strncpy( d + pos, m_proxyPwd.c_str(), m_proxyPwd.length() );
212 pos += m_proxyPwd.length();
213
214 if( !send( std::string( d, pos ) ) )
215 {
216 cleanup();
218 }
219 delete[] d;
220 }
221 else
222 {
223 if( m_proxyHandshakeBuffer[1] == static_cast<char>( 0xFF ) && !m_proxyUser.empty() && !m_proxyPwd.empty() )
224 connError = ConnProxyNoSupportedAuth;
225 else
226 connError = ConnProxyAuthRequired;
227 }
228
229 m_proxyHandshakeBuffer = "";
230 break;
231 case S5StateNegotiating:
232 if( m_proxyHandshakeBuffer.length() < 6 )
233 return;
234
235 if( m_proxyHandshakeBuffer.length() >= 6 && m_proxyHandshakeBuffer[0] == 0x05 )
236 {
237 if( m_proxyHandshakeBuffer[1] == 0x00 )
238 {
240 m_s5state = S5StateConnected;
241 m_handler->handleConnect( this );
242 }
243 else // connection refused
244 connError = ConnConnectionRefused;
245 }
246 else
247 connError = ConnIoError;
248
249 m_proxyHandshakeBuffer = "";
250 break;
251 case S5StateAuthenticating:
252 if( m_proxyHandshakeBuffer.length() < 2 )
253 return;
254
255 if( m_proxyHandshakeBuffer.length() == 2 && m_proxyHandshakeBuffer[0] == 0x01 && m_proxyHandshakeBuffer[1] == 0x00 )
256 negotiate();
257 else
258 connError = ConnProxyAuthFailed;
259
260 m_proxyHandshakeBuffer = "";
261 break;
262 case S5StateConnected:
263 m_handler->handleReceivedData( this, data );
264 break;
265 default:
266 break;
267 }
268
269 if( connError != ConnNoError )
270 {
271 m_connection->disconnect();
272 m_handler->handleDisconnect( this, connError );
273 }
274
275 }
276
277 void ConnectionSOCKS5Proxy::negotiate()
278 {
279 m_s5state = S5StateNegotiating;
280 char* d = new char[m_ip ? 10 : 6 + m_server.length() + 1];
281 size_t pos = 0;
282 d[pos++] = 0x05; // SOCKS version 5
283 d[pos++] = 0x01; // command CONNECT
284 d[pos++] = 0x00; // reserved
285 int port = m_port;
286 std::string server = m_server;
287 if( m_ip ) // IP address
288 {
289 d[pos++] = 0x01; // IPv4 address
290 std::string s;
291 const size_t j = server.length();
292 size_t l = 0;
293 for( size_t k = 0; k < j && l < 4; ++k )
294 {
295 if( server[k] != '.' )
296 s += server[k];
297
298 if( server[k] == '.' || k == j-1 )
299 {
300 d[pos++] = static_cast<char>( atoi( s.c_str() ) & 0xFF );
301 s = EmptyString;
302 ++l;
303 }
304 }
305 }
306 else // hostname
307 {
308 if( port == -1 )
309 {
310 const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
311 if( servers.size() )
312 {
313 const std::pair< std::string, int >& host = *servers.begin();
314 server = host.first;
315 port = host.second;
316 }
317 }
318 d[pos++] = 0x03; // hostname
319 d[pos++] = static_cast<char>( m_server.length() );
320 strncpy( d + pos, m_server.c_str(), m_server.length() );
321 pos += m_server.length();
322 }
323 int nport = htons( port );
324 d[pos++] = static_cast<char>( nport );
325 d[pos++] = static_cast<char>( nport >> 8 );
326
327 std::string message = "Requesting socks5 proxy connection to " + server + ":"
328 + util::int2string( port );
329 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, message );
330
331 if( !send( std::string( d, pos ) ) )
332 {
333 cleanup();
335 }
336 delete[] d;
337 }
338
340 {
341 if( m_connection )
342 {
343 std::string server = m_server;
344 int port = m_port;
345 if( port == -1 )
346 {
347 const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
348 if( !servers.empty() )
349 {
350 const std::pair< std::string, int >& host = *servers.begin();
351 server = host.first;
352 port = host.second;
353 }
354 }
356 "Attempting to negotiate socks5 proxy connection" );
357
358 const bool auth = !m_proxyUser.empty() && !m_proxyPwd.empty();
359 const char d[4] = {
360 0x05, // SOCKS version 5
361 static_cast<char>( auth ? 0x02 // two methods
362 : 0x01 ), // one method
363 0x00, // method: no auth
364 0x02 // method: username/password auth
365 };
366
367 if( !send( std::string( d, auth ? 4 : 3 ) ) )
368 {
369 cleanup();
370 if( m_handler )
372 }
373 }
374 }
375
377 ConnectionError reason )
378 {
379 cleanup();
380 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, "socks5 proxy connection closed" );
381
382 if( m_handler )
383 m_handler->handleDisconnect( this, reason );
384 }
385
386}
An abstract base class for a connection.
virtual void cleanup()
ConnectionState m_state
const std::string & server() const
ConnectionState state() const
virtual ConnectionBase * newInstance() const =0
virtual ConnectionError recv(int timeout=-1)=0
virtual bool send(const std::string &data)=0
ConnectionDataHandler * m_handler
virtual ConnectionError connect()=0
virtual ConnectionError receive()=0
virtual void getStatistics(long int &totalIn, long int &totalOut)=0
virtual void disconnect()=0
void registerConnectionDataHandler(ConnectionDataHandler *cdh)
This is an abstract base class to receive events from a ConnectionBase-derived object.
virtual void handleReceivedData(const ConnectionBase *connection, const std::string &data)=0
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)=0
virtual void handleConnect(const ConnectionBase *connection)=0
ConnectionSOCKS5Proxy(ConnectionBase *connection, const LogSink &logInstance, const std::string &server, int port=-1, bool ip=false)
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)
virtual ConnectionError recv(int timeout=-1)
virtual void handleConnect(const ConnectionBase *connection)
virtual void handleReceivedData(const ConnectionBase *connection, const std::string &data)
virtual ConnectionBase * newInstance() const
virtual ConnectionError connect()
void setConnectionImpl(ConnectionBase *connection)
virtual bool send(const std::string &data)
virtual ConnectionError receive()
virtual void getStatistics(long int &totalIn, long int &totalOut)
static HostMap resolve(const std::string &service, const std::string &proto, const std::string &domain, const LogSink &logInstance)
Definition: dns.cpp:83
std::map< std::string, int > HostMap
Definition: dns.h:68
An implementation of log sink and source.
Definition: logsink.h:39
void dbg(LogArea area, const std::string &message) const
Definition: logsink.h:66
bool idna(const std::string &domain, std::string &out)
Definition: prep.cpp:107
The namespace for the gloox library.
Definition: adhoc.cpp:28
ConnectionError
Definition: gloox.h:684
@ ConnProxyNoSupportedAuth
Definition: gloox.h:694
@ ConnNotConnected
Definition: gloox.h:715
@ ConnProxyAuthFailed
Definition: gloox.h:692
@ ConnProxyAuthRequired
Definition: gloox.h:690
@ ConnConnectionRefused
Definition: gloox.h:698
@ ConnNoError
Definition: gloox.h:685
@ ConnIoError
Definition: gloox.h:696
@ LogAreaClassConnectionSOCKS5Proxy
Definition: gloox.h:1061
const std::string EmptyString
Definition: gloox.cpp:124
@ StateDisconnected
Definition: gloox.h:642
@ StateConnected
Definition: gloox.h:644
@ StateConnecting
Definition: gloox.h:643