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

A Socks4a packet.

Attributes

command[RW]
dest_ip[RW]
dest_port[RW]
userid[RW]
version[RW]

Public Class Methods

new() click to toggle source
# File lib/rex/proto/proxy/socks4a.rb, line 41
def initialize
  @version   = REQUEST_VERSION
  @command   = 0
  @dest_port = 0
  @dest_ip   = '0.0.0.0'
  @userid    = ''
end
recv( sock, timeout=30 ) click to toggle source

A helper function to recv in a Socks4a packet byte by byte.

sf: we could just call raw = sock.get_once but some clients

seem to need reading this byte by byte instead.
# File lib/rex/proto/proxy/socks4a.rb, line 55
def Packet.recv( sock, timeout=30 )
  raw = ''
  # read in the 8 byte header
  while( raw.length < 8 )
    raw << sock.read( 1 )
  end
  # if its a request there will be more data
  if( raw[0..0].unpack( 'C' ).first == REQUEST_VERSION )
    # read in the userid
    while( raw[8..raw.length].index( "\x00" ) == nil )
      raw << sock.read( 1 )
    end
    # if a hostname is going to be present, read it in
    ip = raw[4..7].unpack( 'N' ).first
    if( ( ip & 0xFFFFFF00 ) == 0x00000000 and ( ip & 0x000000FF ) != 0x00 )
      hostname = ''
      while( hostname.index( "\x00" ) == nil )
        hostname += sock.read( 1 )
      end
      raw << hostname
    end
  end
  # create a packet from this raw data...
  packet = Packet.new
  packet.from_r( raw ) ? packet : nil
end

Public Instance Methods

from_r( raw ) click to toggle source

Unpack a raw packet into its components.

# File lib/rex/proto/proxy/socks4a.rb, line 94
def from_r( raw )
  return false if( raw.length < 8 )
  @version   = raw[0..0].unpack( 'C' ).first
  return false if( @version != REQUEST_VERSION and @version != REPLY_VERSION )
  @command   = raw[1..1].unpack( 'C' ).first
  @dest_port = raw[2..3].unpack( 'n' ).first
  @dest_ip   = Rex::Socket.addr_itoa( raw[4..7].unpack( 'N' ).first )
  if( raw.length > 8 )
    @userid = raw[8..raw.length].unpack( 'Z*' ).first
    # if this is a socks4a request we can resolve the provided hostname
    if( self.is_hostname? )
      hostname = raw[(8+@userid.length+1)..raw.length].unpack( 'Z*' ).first
      @dest_ip = self.resolve( hostname )
      # fail if we couldnt resolve the hostname
      return false if( not @dest_ip )
    end
  else
    @userid  = ''
  end
  return true
end
is_bind?() click to toggle source
# File lib/rex/proto/proxy/socks4a.rb, line 120
def is_bind?
  @command == COMMAND_BIND ? true : false
end
is_connect?() click to toggle source
# File lib/rex/proto/proxy/socks4a.rb, line 116
def is_connect?
  @command == COMMAND_CONNECT ? true : false
end
to_r() click to toggle source

Pack a packet into raw bytes for transmitting on the wire.

# File lib/rex/proto/proxy/socks4a.rb, line 85
def to_r
  raw = [ @version, @command, @dest_port, Rex::Socket.addr_atoi( @dest_ip ) ].pack( 'CCnN' )
  return raw if( @userid.empty? )
  return raw + [ @userid ].pack( 'Z*' )
end

Protected Instance Methods

is_hostname?() click to toggle source

As per the Socks4a spec, check to see if the provided dest_ip is 0.0.0.XX which indicates after the @userid field contains a hostname to resolve.

# File lib/rex/proto/proxy/socks4a.rb, line 146
def is_hostname?
  ip = Rex::Socket.addr_atoi( @dest_ip )
  if( ip & 0xFFFFFF00 == 0x00000000 )
    return true if( ip & 0x000000FF != 0x00 )
  end
  return false
end
resolve( hostname ) click to toggle source

Resolve the given hostname into a dotted IP address.

# File lib/rex/proto/proxy/socks4a.rb, line 131
def resolve( hostname )
  if( not hostname.empty? )
    begin
      return Rex::Socket.addr_itoa( Rex::Socket.gethostbyname( hostname )[3].unpack( 'N' ).first )
    rescue ::SocketError
      return nil
    end
  end
  return nil
end