00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "config.h"
00016
00017 #include "gloox.h"
00018
00019 #include "connectionsocks5proxy.h"
00020 #include "dns.h"
00021 #include "logsink.h"
00022 #include "prep.h"
00023 #include "base64.h"
00024 #include "util.h"
00025
00026 #include <string>
00027 #include <cstdlib>
00028
00029 #include <string.h>
00030
00031 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
00032 # include <netinet/in.h>
00033 #endif
00034
00035 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
00036 # include <winsock.h>
00037 #elif defined( _WIN32_WCE )
00038 # include <winsock2.h>
00039 #endif
00040
00041 #include <cstdlib>
00042
00043 namespace gloox
00044 {
00045
00046 ConnectionSOCKS5Proxy::ConnectionSOCKS5Proxy( ConnectionBase* connection,
00047 const LogSink& logInstance,
00048 const std::string& server,
00049 int port, bool ip )
00050 : ConnectionBase( 0 ), m_connection( connection ),
00051 m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
00052 {
00053
00054 prep::idna( server, m_server );
00055 m_port = port;
00056
00057 if( m_connection )
00058 m_connection->registerConnectionDataHandler( this );
00059 }
00060
00061 ConnectionSOCKS5Proxy::ConnectionSOCKS5Proxy( ConnectionDataHandler* cdh,
00062 ConnectionBase* connection,
00063 const LogSink& logInstance,
00064 const std::string& server,
00065 int port, bool ip )
00066 : ConnectionBase( cdh ), m_connection( connection ),
00067 m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
00068 {
00069
00070 prep::idna( server, m_server );
00071 m_port = port;
00072
00073 if( m_connection )
00074 m_connection->registerConnectionDataHandler( this );
00075 }
00076
00077 ConnectionSOCKS5Proxy::~ConnectionSOCKS5Proxy()
00078 {
00079 if( m_connection )
00080 delete m_connection;
00081 }
00082
00083 ConnectionBase* ConnectionSOCKS5Proxy::newInstance() const
00084 {
00085 ConnectionBase* conn = m_connection ? m_connection->newInstance() : 0;
00086 return new ConnectionSOCKS5Proxy( m_handler, conn, m_logInstance, m_server, m_port, m_ip );
00087 }
00088
00089 void ConnectionSOCKS5Proxy::setConnectionImpl( ConnectionBase* connection )
00090 {
00091 if( m_connection )
00092 delete m_connection;
00093
00094 m_connection = connection;
00095 }
00096
00097 ConnectionError ConnectionSOCKS5Proxy::connect()
00098 {
00099
00100 if( m_connection && m_connection->state() == StateConnected && m_handler )
00101 {
00102 m_state = StateConnected;
00103 m_s5state = S5StateConnected;
00104 return ConnNoError;
00105 }
00106
00107 if( m_connection && m_handler )
00108 {
00109 m_state = StateConnecting;
00110 m_s5state = S5StateConnecting;
00111 return m_connection->connect();
00112 }
00113
00114 return ConnNotConnected;
00115 }
00116
00117 void ConnectionSOCKS5Proxy::disconnect()
00118 {
00119 if( m_connection )
00120 m_connection->disconnect();
00121 cleanup();
00122 }
00123
00124 ConnectionError ConnectionSOCKS5Proxy::recv( int timeout )
00125 {
00126 if( m_connection )
00127 return m_connection->recv( timeout );
00128 else
00129 return ConnNotConnected;
00130 }
00131
00132 ConnectionError ConnectionSOCKS5Proxy::receive()
00133 {
00134 if( m_connection )
00135 return m_connection->receive();
00136 else
00137 return ConnNotConnected;
00138 }
00139
00140 bool ConnectionSOCKS5Proxy::send( const std::string& data )
00141 {
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 if( m_connection )
00152 return m_connection->send( data );
00153
00154 return false;
00155 }
00156
00157 void ConnectionSOCKS5Proxy::cleanup()
00158 {
00159 m_state = StateDisconnected;
00160 m_s5state = S5StateDisconnected;
00161
00162 if( m_connection )
00163 m_connection->cleanup();
00164 }
00165
00166 void ConnectionSOCKS5Proxy::getStatistics( long int &totalIn, long int &totalOut )
00167 {
00168 if( m_connection )
00169 m_connection->getStatistics( totalIn, totalOut );
00170 else
00171 {
00172 totalIn = 0;
00173 totalOut = 0;
00174 }
00175 }
00176
00177 void ConnectionSOCKS5Proxy::handleReceivedData( const ConnectionBase* ,
00178 const std::string& data )
00179 {
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 if( !m_connection || !m_handler )
00190 return;
00191
00192 ConnectionError connError = ConnNoError;
00193
00194 switch( m_s5state )
00195 {
00196 case S5StateConnecting:
00197 if( data.length() != 2 || data[0] != 0x05 )
00198 connError = ConnIoError;
00199
00200 if( data[1] == 0x00 )
00201 {
00202 negotiate();
00203 }
00204 else if( data[1] == 0x02 && !m_proxyUser.empty() && !m_proxyPwd.empty() )
00205 {
00206 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy,
00207 "authenticating to socks5 proxy as user " + m_proxyUser );
00208 m_s5state = S5StateAuthenticating;
00209 char* d = new char[3 + m_proxyUser.length() + m_proxyPwd.length()];
00210 size_t pos = 0;
00211 d[pos++] = 0x01;
00212 d[pos++] = (char)m_proxyUser.length();
00213 strncpy( d + pos, m_proxyUser.c_str(), m_proxyUser.length() );
00214 pos += m_proxyUser.length();
00215 d[pos++] = (char)m_proxyPwd.length();
00216 strncpy( d + pos, m_proxyPwd.c_str(), m_proxyPwd.length() );
00217 pos += m_proxyPwd.length();
00218
00219 if( !send( std::string( d, pos ) ) )
00220 {
00221 cleanup();
00222 m_handler->handleDisconnect( this, ConnIoError );
00223 }
00224 delete[] d;
00225 }
00226 else
00227 {
00228 if( data[1] == (char)(unsigned char)0xFF && !m_proxyUser.empty() && !m_proxyPwd.empty() )
00229 connError = ConnProxyNoSupportedAuth;
00230 else
00231 connError = ConnProxyAuthRequired;
00232 }
00233 break;
00234 case S5StateNegotiating:
00235 if( data.length() >= 6 && data[0] == 0x05 )
00236 {
00237 if( data[1] == 0x00 )
00238 {
00239 m_state = StateConnected;
00240 m_s5state = S5StateConnected;
00241 m_handler->handleConnect( this );
00242 }
00243 else
00244 connError = ConnConnectionRefused;
00245 }
00246 else
00247 connError = ConnIoError;
00248 break;
00249 case S5StateAuthenticating:
00250 if( data.length() == 2 && data[0] == 0x01 && data[1] == 0x00 )
00251 negotiate();
00252 else
00253 connError = ConnProxyAuthFailed;
00254 break;
00255 case S5StateConnected:
00256 m_handler->handleReceivedData( this, data );
00257 break;
00258 default:
00259 break;
00260 }
00261
00262 if( connError != ConnNoError )
00263 {
00264 m_connection->disconnect();
00265 m_handler->handleDisconnect( this, connError );
00266 }
00267
00268 }
00269
00270 void ConnectionSOCKS5Proxy::negotiate()
00271 {
00272 m_s5state = S5StateNegotiating;
00273 char* d = new char[m_ip ? 10 : 6 + m_server.length() + 1];
00274 size_t pos = 0;
00275 d[pos++] = 0x05;
00276 d[pos++] = 0x01;
00277 d[pos++] = 0x00;
00278 int port = m_port;
00279 std::string server = m_server;
00280 if( m_ip )
00281 {
00282 d[pos++] = 0x01;
00283 std::string s;
00284 const size_t j = server.length();
00285 size_t l = 0;
00286 for( size_t k = 0; k < j && l < 4; ++k )
00287 {
00288 if( server[k] != '.' )
00289 s += server[k];
00290
00291 if( server[k] == '.' || k == j-1 )
00292 {
00293 d[pos++] = static_cast<char>( atoi( s.c_str() ) & 0xFF );
00294 s = EmptyString;
00295 ++l;
00296 }
00297 }
00298 }
00299 else
00300 {
00301 if( port == -1 )
00302 {
00303 const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
00304 if( servers.size() )
00305 {
00306 const std::pair< std::string, int >& host = *servers.begin();
00307 server = host.first;
00308 port = host.second;
00309 }
00310 }
00311 d[pos++] = 0x03;
00312 d[pos++] = (char)m_server.length();
00313 strncpy( d + pos, m_server.c_str(), m_server.length() );
00314 pos += m_server.length();
00315 }
00316 int nport = htons( port );
00317 d[pos++] = static_cast<char>( nport );
00318 d[pos++] = static_cast<char>( nport >> 8 );
00319
00320 std::string message = "Requesting socks5 proxy connection to " + server + ":"
00321 + util::int2string( port );
00322 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, message );
00323
00324 if( !send( std::string( d, pos ) ) )
00325 {
00326 cleanup();
00327 m_handler->handleDisconnect( this, ConnIoError );
00328 }
00329 delete[] d;
00330 }
00331
00332 void ConnectionSOCKS5Proxy::handleConnect( const ConnectionBase* )
00333 {
00334 if( m_connection )
00335 {
00336 std::string server = m_server;
00337 int port = m_port;
00338 if( port == -1 )
00339 {
00340 const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
00341 if( !servers.empty() )
00342 {
00343 const std::pair< std::string, int >& host = *servers.begin();
00344 server = host.first;
00345 port = host.second;
00346 }
00347 }
00348 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy,
00349 "Attempting to negotiate socks5 proxy connection" );
00350
00351 const bool auth = !m_proxyUser.empty() && !m_proxyPwd.empty();
00352 const char d[4] = {
00353 0x05,
00354 static_cast<char>( auth ? 0x02
00355 : 0x01 ),
00356 0x00,
00357 0x02
00358 };
00359
00360 if( !send( std::string( d, auth ? 4 : 3 ) ) )
00361 {
00362 cleanup();
00363 if( m_handler )
00364 m_handler->handleDisconnect( this, ConnIoError );
00365 }
00366 }
00367 }
00368
00369 void ConnectionSOCKS5Proxy::handleDisconnect( const ConnectionBase* ,
00370 ConnectionError reason )
00371 {
00372 cleanup();
00373 m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, "socks5 proxy connection closed" );
00374
00375 if( m_handler )
00376 m_handler->handleDisconnect( this, reason );
00377 }
00378
00379 }