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

Generated on Sat Mar 22 09:32:19 2008 for gloox by  doxygen 1.4.1