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