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