class RSocks::Socks5ProxyParser

Attributes

password[R]
username[R]

Public Class Methods

new(state_machine, config, client) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 14
def initialize(state_machine, config, client)
  @state_machine = state_machine
  @auth_method = config.auth_method
  @default_user = ENV['RSOCKS_USER'] || 'default'
  @default_password = ENV['RSOCKS_PASSWORD'] || 'default'
  @authenticator = RSocks::Authenticator.new(config.auth_adaptor)
  @original_addr = nil
  @original_port = nil
  @config = config
  @adaptor = config.auth_adaptor
  @client = client
end

Public Instance Methods

call(data) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 28
def call(data)
  if @state_machine.handshake?
    init_handshake(data)
    return
  end

  if @state_machine.auth?
    passed = @authenticator.auth!(data)
    if passed
      send_data(RSocks::SUCCESS_RESPONSE)
      @state_machine.connect!
      return
    end

    send_data(RSocks::FAILED_RESPONSE)
    return
  end

  if @state_machine.connect?
    connect_request(data)
    @username = @authenticator.username
    @password = @authenticator.password
    return [@addr, @port]
  end

  return send_data(not_accept) unless @state_machine.start?
end

Private Instance Methods

check_sock_cmd(cmd, data) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 112
def check_sock_cmd(cmd, data)
  raise RSocks::NotSupport unless cmd == RSocks::CMD_CONNECT

  _, addr_type = data.unpack('CC')

  address = nil
  port = nil
  type = nil

  if addr_type == RSocks::ADDR_IPV4
    type = RSocks::ADDR_IPV4
    address, port = parse_address_port(data[2..-1], 4, type)
  elsif addr_type == RSocks::ADDR_IPV6
    type = RSocks::ADDR_IPV6
    address, port = parse_address_port(data[2..-1], 16, type)
  elsif addr_type == RSocks::ADDR_DOMAIN
    type = RSocks::ADDR_DOMAIN
    padding = data[2].unpack('C')[0]
    address, port = parse_address_port(data[3..-1], padding, type)
  end

  [address, port, type]
end
close_connection() click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 175
def close_connection
  @client.close_connection_after_writing
end
connect_request(data) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 95
def connect_request(data)
  version, cmd = data.unpack('CC')
  return not_accept if version != RSocks::VERSION

  begin
    @addr, @port, @type = check_sock_cmd(cmd, data[2..-1])
  rescue
    send_data([RSocks::VERSION,RSocks::CONNECT_FAIL].pack('CC'))
    return close_connection
  end

  @state_machine.start!

  send_data([RSocks::VERSION, RSocks::CONNECT_SUCCESS].
    pack('CC') + pack_address_and_port_info(@type))
end
init_handshake(data) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 58
def init_handshake(data)

  version, num = data.unpack('CC')

  if version != RSocks::VERSION || num <= 0
    send_data(not_accept)
    close_connection
  end

  position = 'C' * num

  methods = data[2..-1].unpack(position)

  data = nil


  auth_method = @config.auth_method == :password ? PASSWORD_LOGIN : RSocks::NO_AUTH

  if methods.include?(auth_method)

    if auth_method == RSocks::NO_AUTH
      @state_machine.connect!
    elsif auth_method == RSocks::PASSWORD_LOGIN
      @state_machine.auth!
    end

    data = [RSocks::VERSION, auth_method].pack('CC')
  end

  if data.nil?
    send_data(not_accept)
    close_connection
  end

  send_data(data)
end
not_accept() click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 136
def not_accept
  [RSocks::VERSION, RSocks::NOT_ACCEPT].pack('CC')
end
pack_address_and_port_info(type) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 160
def pack_address_and_port_info(type)
  addr = @original_addr
  if type == RSocks::ADDR_DOMAIN
    domain_size = [addr.size].pack('C')
    addr = domain_size + @original_addr
  end

  temp = [RSocks::KEEP_ONE_BIT, type]
  temp.pack('C' * temp.size) + addr + @original_port
end
parse_address_port(data, padding, type) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 140
def parse_address_port(data, padding, type)
  address = data[0...padding]
  port_start = padding

  @original_port = data[port_start..-1]
  @original_addr = address

  temp = @original_port.unpack('CC')

  port = (temp[0] << 8) | temp[1]

  addr_str = if type == RSocks::ADDR_DOMAIN
               address
             else
               IPAddr.ntop(address)
             end

  [addr_str, port]
end
send_data(data) click to toggle source
# File lib/r_socks/socks5_proxy_parser.rb, line 171
def send_data(data)
  @client.send_data(data)
end