class Rex::Proto::Proxy::Socks4a::Client

A client connected to the Socks4a server.

Constants

COMMAND_BIND
COMMAND_CONNECT
HOST
PORT
REPLY_VERSION
REQUEST_GRANTED
REQUEST_REJECT_CONNECT
REQUEST_REJECT_FAILED
REQUEST_REJECT_USERID
REQUEST_VERSION

Public Class Methods

new( server, sock ) click to toggle source

Create a new client connected to the server.

# File lib/rex/proto/proxy/socks4a.rb, line 222
def initialize( server, sock )
  @server        = server
  @lsock         = sock
  @rsock         = nil
  @client_thread = nil
  @mutex         = ::Mutex.new
end

Public Instance Methods

start() click to toggle source

Start handling the client connection.

# File lib/rex/proto/proxy/socks4a.rb, line 233
def start
  # create a thread to handle this client request so as to not block the socks4a server
  @client_thread = Rex::ThreadFactory.spawn("SOCKS4AProxyClient", false) do
    begin
      @server.add_client( self )
      # get the initial client request packet
      request = Packet.recv( @lsock )
      raise "Invalid Socks4 request packet received." if not request
      # handle the request
      begin
        # handle socks4a conenct requests
        if( request.is_connect? )
          # perform the connection request
          params = {
            'PeerHost' => request.dest_ip,
            'PeerPort' => request.dest_port,
          }
          params['Context'] = @server.opts['Context'] if @server.opts.has_key?('Context')

          @rsock = Rex::Socket::Tcp.create( params )
          # and send back success to the client
          response         = Packet.new
          response.version = REPLY_VERSION
          response.command = REQUEST_GRANTED
          @lsock.put( response.to_r )
        # handle socks4a bind requests
        elsif( request.is_bind? )
          # create a server socket for this request
          params = {
            'LocalHost' => '0.0.0.0',
            'LocalPort' => 0,
          }
          params['Context'] = @server.opts['Context'] if @server.opts.has_key?('Context')
          bsock = Rex::Socket::TcpServer.create( params )
          # send back the bind success to the client
          response           = Packet.new
          response.version   = REPLY_VERSION
          response.command   = REQUEST_GRANTED
          response.dest_ip   = '0.0.0.0'
          response.dest_port = bsock.getlocalname()[PORT]
          @lsock.put( response.to_r )
          # accept a client connection (2 minute timeout as per spec)
          begin
            ::Timeout.timeout( 120 ) do
              @rsock = bsock.accept
            end
          rescue ::Timeout::Error
            raise "Timeout reached on accept request."
          end
          # close the listening socket
          bsock.close
          # verify the connection is from the dest_ip origionally specified by the client
          rpeer = @rsock.getpeername
          raise "Got connection from an invalid peer." if( rpeer[HOST] != request.dest_ip )
          # send back the client connect success to the client
          #
          # sf: according to the spec we send this response back to the client, however
          #     I have seen some clients who bawk if they get this second response.
          #
          response           = Packet.new
          response.version   = REPLY_VERSION
          response.command   = REQUEST_GRANTED
          response.dest_ip   = rpeer[HOST]
          response.dest_port = rpeer[PORT]
          @lsock.put( response.to_r )
        else
          raise "Unknown request command received #{request.command} received."
        end
      rescue
        # send back failure to the client
        response         = Packet.new
        response.version = REPLY_VERSION
        response.command = REQUEST_REJECT_FAILED
        @lsock.put( response.to_r )
        # raise an exception to close this client connection
        raise "Failed to handle the clients request."
      end
      # setup the two way relay for full duplex io
      @lsock.extend( Relay )
      @rsock.extend( Relay )
      # start the socket relays...
      @lsock.relay( self, @rsock )
      @rsock.relay( self, @lsock )
    rescue
      wlog( "Client.start - #{$!}" )
      self.stop
    end
  end
end
stop() click to toggle source

Stop handling the client connection.

# File lib/rex/proto/proxy/socks4a.rb, line 326
def stop
  @mutex.synchronize do
    if( not @closed )

      begin
        @lsock.close if @lsock
      rescue
      end

      begin
        @rsock.close if @rsock
      rescue
      end

      @client_thread.kill if( @client_thread and @client_thread.alive? )

      @server.remove_client( self )

      @closed = true
    end
  end
end