Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

connectionsocks5proxy.cpp

00001 /*
00002   Copyright (c) 2007-2008 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 "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 // FIXME check return value?
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 // FIXME check return value?
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 // FIXME CHECKME
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 //     if( m_s5state != S5StateConnected )
00142 //     {
00143 //       printf( "p data sent: " );
00144 //       const char* x = data.c_str();
00145 //       for( unsigned int i = 0; i < data.length(); ++i )
00146 //         printf( "%02X ", (const char)x[i] );
00147 //       printf( "\n" );
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* /*connection*/,
00177                                                   const std::string& data )
00178   {
00179 //     if( m_s5state != S5StateConnected )
00180 //     {
00181 //       printf( "data recv: " );
00182 //       const char* x = data.c_str();
00183 //       for( unsigned int i = 0; i < data.length(); ++i )
00184 //         printf( "%02X ", (const char)x[i] );
00185 //       printf( "\n" );
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 ) // no auth
00200         {
00201           negotiate();
00202         }
00203         else if( data[1] == 0x02 && !m_proxyUser.empty() && !m_proxyPwd.empty() ) // user/password auth
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 // connection refused
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; // SOCKS version 5
00275     d[pos++] = 0x01; // command CONNECT
00276     d[pos++] = 0x00; // reserved
00277     int port = m_port;
00278     std::string server = m_server;
00279     if( m_ip ) // IP address
00280     {
00281       d[pos++] = 0x01; // IPv4 address
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 // hostname
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; // hostname
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* /*connection*/ )
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,        // SOCKS version 5
00355         auth ? 0x02  // two methods
00356              : 0x01, // one methods
00357         0x00,        // method: no auth
00358         0x02         // method: username/password auth
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* /*connection*/,
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 }

Generated on Sun Oct 12 16:25:15 2008 for gloox by  doxygen 1.4.1