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