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