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