gloox 1.0

socks5bytestreamserver.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 #include "socks5bytestreamserver.h"
00015 #include "connectiontcpserver.h"
00016 #include "mutexguard.h"
00017 #include "util.h"
00018 
00019 namespace gloox
00020 {
00021 
00022   SOCKS5BytestreamServer::SOCKS5BytestreamServer( const LogSink& logInstance, int port,
00023                                                   const std::string& ip )
00024     : m_tcpServer( 0 ), m_logInstance( logInstance ), m_ip( ip ), m_port( port )
00025   {
00026     m_tcpServer = new ConnectionTCPServer( this, m_logInstance, m_ip, m_port );
00027   }
00028 
00029   SOCKS5BytestreamServer::~SOCKS5BytestreamServer()
00030   {
00031     if( m_tcpServer )
00032       delete m_tcpServer;
00033 
00034     ConnectionMap::const_iterator it = m_connections.begin();
00035     for( ; it != m_connections.end(); ++it )
00036       delete (*it).first;
00037   }
00038 
00039   ConnectionError SOCKS5BytestreamServer::listen()
00040   {
00041     if( m_tcpServer )
00042       return m_tcpServer->connect();
00043 
00044     return ConnNotConnected;
00045   }
00046 
00047   ConnectionError SOCKS5BytestreamServer::recv( int timeout )
00048   {
00049     if( !m_tcpServer )
00050       return ConnNotConnected;
00051 
00052     ConnectionError ce = m_tcpServer->recv( timeout );
00053     if( ce != ConnNoError )
00054       return ce;
00055 
00056     ConnectionMap::const_iterator it = m_connections.begin();
00057     ConnectionMap::const_iterator it2;
00058     while( it != m_connections.end() )
00059     {
00060       it2 = it++;
00061       (*it2).first->recv( timeout );
00062     }
00063 
00064     util::clearList( m_oldConnections );
00065     return ConnNoError;
00066   }
00067 
00068   void SOCKS5BytestreamServer::stop()
00069   {
00070     if( m_tcpServer )
00071     {
00072       m_tcpServer->disconnect();
00073       m_tcpServer->cleanup();
00074     }
00075   }
00076 
00077   int SOCKS5BytestreamServer::localPort() const
00078   {
00079     if( m_tcpServer )
00080       return m_tcpServer->localPort();
00081 
00082     return m_port;
00083   }
00084 
00085   const std::string SOCKS5BytestreamServer::localInterface() const
00086   {
00087     if( m_tcpServer )
00088       return m_tcpServer->localInterface();
00089 
00090     return m_ip;
00091   }
00092 
00093   ConnectionBase* SOCKS5BytestreamServer::getConnection( const std::string& hash )
00094   {
00095     util::MutexGuard mg( m_mutex );
00096 
00097     ConnectionMap::iterator it = m_connections.begin();
00098     for( ; it != m_connections.end(); ++it )
00099     {
00100       if( (*it).second.hash == hash )
00101       {
00102         ConnectionBase* conn = (*it).first;
00103         conn->registerConnectionDataHandler( 0 );
00104         m_connections.erase( it );
00105         return conn;
00106       }
00107     }
00108 
00109     return 0;
00110   }
00111 
00112   void SOCKS5BytestreamServer::registerHash( const std::string& hash )
00113   {
00114     util::MutexGuard mg( m_mutex );
00115     m_hashes.push_back( hash );
00116   }
00117 
00118   void SOCKS5BytestreamServer::removeHash( const std::string& hash )
00119   {
00120     util::MutexGuard mg( m_mutex );
00121     m_hashes.remove( hash );
00122   }
00123 
00124   void SOCKS5BytestreamServer::handleIncomingConnection( ConnectionBase* /*server*/, ConnectionBase* connection )
00125   {
00126     connection->registerConnectionDataHandler( this );
00127     ConnectionInfo ci;
00128     ci.state = StateUnnegotiated;
00129     m_connections[connection] = ci;
00130   }
00131 
00132   void SOCKS5BytestreamServer::handleReceivedData( const ConnectionBase* connection,
00133                                                    const std::string& data )
00134   {
00135     ConnectionMap::iterator it = m_connections.find( const_cast<ConnectionBase*>( connection ) );
00136     if( it == m_connections.end() )
00137       return;
00138 
00139     switch( (*it).second.state )
00140     {
00141       case StateDisconnected:
00142         (*it).first->disconnect();
00143         break;
00144       case StateUnnegotiated:
00145       {
00146         char c[2];
00147         c[0] = 0x05;
00148         c[1] = (char)(unsigned char)0xFF;
00149         (*it).second.state = StateDisconnected;
00150 
00151         if( data.length() >= 3 && data[0] == 0x05 )
00152         {
00153           unsigned int sz = ( data.length() - 2 < static_cast<unsigned int>( data[1] ) )
00154                               ? static_cast<unsigned int>( data.length() - 2 )
00155                               : static_cast<unsigned int>( data[1] );
00156           for( unsigned int i = 2; i < sz + 2; ++i )
00157           {
00158             if( data[i] == 0x00 )
00159             {
00160               c[1] = 0x00;
00161               (*it).second.state = StateAuthAccepted;
00162               break;
00163             }
00164           }
00165         }
00166         (*it).first->send( std::string( c, 2 ) );
00167         break;
00168       }
00169       case StateAuthmethodAccepted:
00170         // place to implement any future auth support
00171         break;
00172       case StateAuthAccepted:
00173       {
00174         std::string reply = data;
00175         if( reply.length() < 2 )
00176           reply.resize( 2 );
00177 
00178         reply[0] = 0x05;
00179         reply[1] = 0x01; // general SOCKS server failure
00180         (*it).second.state = StateDisconnected;
00181 
00182         if( data.length() == 47 && data[0] == 0x05 && data[1] == 0x01 && data[2] == 0x00
00183             && data[3] == 0x03 && data[4] == 0x28 && data[45] == 0x00 && data[46] == 0x00 )
00184         {
00185           const std::string hash = data.substr( 5, 40 );
00186 
00187           HashMap::const_iterator ith = m_hashes.begin();
00188           for( ; ith != m_hashes.end() && (*ith) != hash; ++ith )
00189             ;
00190 
00191           if( ith != m_hashes.end() )
00192           {
00193             reply[1] = 0x00;
00194             (*it).second.hash = hash;
00195             (*it).second.state = StateDestinationAccepted;
00196           }
00197         }
00198         (*it).first->send( reply );
00199         break;
00200       }
00201       case StateDestinationAccepted:
00202       case StateActive:
00203         // should not happen
00204         break;
00205     }
00206   }
00207 
00208   void SOCKS5BytestreamServer::handleConnect( const ConnectionBase* /*connection*/ )
00209   {
00210     // should never happen, TCP connection is already established
00211   }
00212 
00213   void SOCKS5BytestreamServer::handleDisconnect( const ConnectionBase* connection,
00214                                                        ConnectionError /*reason*/ )
00215   {
00216     m_connections.erase( const_cast<ConnectionBase*>( connection ) );
00217     m_oldConnections.push_back( connection );
00218   }
00219 
00220 }