Method: Net::SSH::Proxy::SOCKS5#open

Defined in:
lib/net/ssh/proxy/socks5.rb

#open(host, port, connection_options) ⇒ Object

Return a new socket connected to the given host and port via the proxy that was requested when the socket factory was instantiated.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/net/ssh/proxy/socks5.rb', line 63

def open(host, port, connection_options)
  socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
                      connect_timeout: connection_options[:timeout])

  methods = [METHOD_NO_AUTH]
  methods << METHOD_PASSWD if options[:user]

  packet = [VERSION, methods.size, *methods].pack("C*")
  socket.send packet, 0

  version, method = socket.recv(2).unpack("CC")
  if version != VERSION
    socket.close
    raise Net::SSH::Proxy::Error, "invalid SOCKS version (#{version})"
  end

  if method == METHOD_NONE
    socket.close
    raise Net::SSH::Proxy::Error, "no supported authorization methods"
  end

  negotiate_password(socket) if method == METHOD_PASSWD

  packet = [VERSION, CMD_CONNECT, 0].pack("C*")

  if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
    packet << [ATYP_IPV4, $1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
  else
    packet << [ATYP_DOMAIN, host.length, host].pack("CCA*")
  end

  packet << [port].pack("n")
  socket.send packet, 0

  version, reply, = socket.recv(2).unpack("C*")
  socket.recv(1)
  address_type = socket.recv(1).getbyte(0)
  case address_type
  when 1
    socket.recv(4) # get four bytes for IPv4 address
  when 3
    len = socket.recv(1).getbyte(0)
    hostname = socket.recv(len)
  when 4
    ipv6addr hostname = socket.recv(16)
  else
    socket.close
    raise ConnectError, "Illegal response type"
  end
  portnum = socket.recv(2)

  unless reply == SUCCESS
    socket.close
    raise ConnectError, "#{reply}"
  end

  return socket
end