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