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

Generated on Sat Oct 31 19:54:30 2009 for gloox by  doxygen 1.4.1