net-ssh-backports 6.3.0.backports
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +93 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +1074 -0
- data/.travis.yml +51 -0
- data/CHANGES.txt +698 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/LICENSE.txt +19 -0
- data/Manifest +132 -0
- data/README.md +287 -0
- data/Rakefile +105 -0
- data/THANKS.txt +110 -0
- data/appveyor.yml +58 -0
- data/lib/net/ssh/authentication/agent.rb +284 -0
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +20 -0
- data/lib/net/ssh/authentication/ed25519.rb +185 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +297 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
- data/lib/net/ssh/authentication/methods/none.rb +34 -0
- data/lib/net/ssh/authentication/methods/password.rb +80 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
- data/lib/net/ssh/authentication/pageant.rb +497 -0
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +163 -0
- data/lib/net/ssh/buffer.rb +434 -0
- data/lib/net/ssh/buffered_io.rb +202 -0
- data/lib/net/ssh/config.rb +406 -0
- data/lib/net/ssh/connection/channel.rb +695 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +712 -0
- data/lib/net/ssh/connection/term.rb +180 -0
- data/lib/net/ssh/errors.rb +106 -0
- data/lib/net/ssh/key_factory.rb +218 -0
- data/lib/net/ssh/known_hosts.rb +264 -0
- data/lib/net/ssh/loggable.rb +62 -0
- data/lib/net/ssh/packet.rb +106 -0
- data/lib/net/ssh/prompt.rb +62 -0
- data/lib/net/ssh/proxy/command.rb +123 -0
- data/lib/net/ssh/proxy/errors.rb +16 -0
- data/lib/net/ssh/proxy/http.rb +98 -0
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +67 -0
- data/lib/net/ssh/proxy/socks5.rb +140 -0
- data/lib/net/ssh/service/forward.rb +426 -0
- data/lib/net/ssh/test/channel.rb +147 -0
- data/lib/net/ssh/test/extensions.rb +173 -0
- data/lib/net/ssh/test/kex.rb +46 -0
- data/lib/net/ssh/test/local_packet.rb +53 -0
- data/lib/net/ssh/test/packet.rb +101 -0
- data/lib/net/ssh/test/remote_packet.rb +40 -0
- data/lib/net/ssh/test/script.rb +180 -0
- data/lib/net/ssh/test/socket.rb +65 -0
- data/lib/net/ssh/test.rb +94 -0
- data/lib/net/ssh/transport/algorithms.rb +502 -0
- data/lib/net/ssh/transport/cipher_factory.rb +103 -0
- data/lib/net/ssh/transport/constants.rb +40 -0
- data/lib/net/ssh/transport/ctr.rb +115 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
- data/lib/net/ssh/transport/hmac/md5.rb +10 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/none.rb +13 -0
- data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +47 -0
- data/lib/net/ssh/transport/identity_cipher.rb +57 -0
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
- data/lib/net/ssh/transport/kex.rb +31 -0
- data/lib/net/ssh/transport/key_expander.rb +30 -0
- data/lib/net/ssh/transport/openssl.rb +253 -0
- data/lib/net/ssh/transport/packet_stream.rb +280 -0
- data/lib/net/ssh/transport/server_version.rb +77 -0
- data/lib/net/ssh/transport/session.rb +354 -0
- data/lib/net/ssh/transport/state.rb +208 -0
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +68 -0
- data/lib/net/ssh.rb +330 -0
- data/net-ssh-public_cert.pem +20 -0
- data/net-ssh.gemspec +44 -0
- data/support/ssh_tunnel_bug.rb +65 -0
- metadata +271 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'net/ssh/proxy/errors'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Proxy
|
7
|
+
# An implementation of an HTTP proxy. To use it, instantiate it, then
|
8
|
+
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
9
|
+
#
|
10
|
+
# require 'net/ssh/proxy/http'
|
11
|
+
#
|
12
|
+
# proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port)
|
13
|
+
# Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# If the proxy requires authentication, you can pass :user and :password
|
18
|
+
# to the proxy's constructor:
|
19
|
+
#
|
20
|
+
# proxy = Net::SSH::Proxy::HTTP.new('proxy_host', proxy_port,
|
21
|
+
# :user => "user", :password => "password")
|
22
|
+
#
|
23
|
+
# Note that HTTP digest authentication is not supported; Basic only at
|
24
|
+
# this point.
|
25
|
+
class HTTP
|
26
|
+
# The hostname or IP address of the HTTP proxy.
|
27
|
+
attr_reader :proxy_host
|
28
|
+
|
29
|
+
# The port number of the proxy.
|
30
|
+
attr_reader :proxy_port
|
31
|
+
|
32
|
+
# The map of additional options that were given to the object at
|
33
|
+
# initialization.
|
34
|
+
attr_reader :options
|
35
|
+
|
36
|
+
# Create a new socket factory that tunnels via the given host and
|
37
|
+
# port. The +options+ parameter is a hash of additional settings that
|
38
|
+
# can be used to tweak this proxy connection. Specifically, the following
|
39
|
+
# options are supported:
|
40
|
+
#
|
41
|
+
# * :user => the user name to use when authenticating to the proxy
|
42
|
+
# * :password => the password to use when authenticating
|
43
|
+
def initialize(proxy_host, proxy_port=80, options={})
|
44
|
+
@proxy_host = proxy_host
|
45
|
+
@proxy_port = proxy_port
|
46
|
+
@options = options
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a new socket connected to the given host and port via the
|
50
|
+
# proxy that was requested when the socket factory was instantiated.
|
51
|
+
def open(host, port, connection_options)
|
52
|
+
socket = establish_connection(connection_options[:timeout])
|
53
|
+
socket.write "CONNECT #{host}:#{port} HTTP/1.1\r\n"
|
54
|
+
socket.write "Host: #{host}:#{port}\r\n"
|
55
|
+
|
56
|
+
if options[:user]
|
57
|
+
credentials = ["#{options[:user]}:#{options[:password]}"].pack("m*").gsub(/\s/, "")
|
58
|
+
socket.write "Proxy-Authorization: Basic #{credentials}\r\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
socket.write "\r\n"
|
62
|
+
|
63
|
+
resp = parse_response(socket)
|
64
|
+
|
65
|
+
return socket if resp[:code] == 200
|
66
|
+
|
67
|
+
socket.close
|
68
|
+
raise ConnectError, resp.inspect
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def establish_connection(connect_timeout)
|
74
|
+
Socket.tcp(proxy_host, proxy_port, nil, nil,
|
75
|
+
connect_timeout: connect_timeout)
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_response(socket)
|
79
|
+
version, code, reason = socket.gets.chomp.split(/ /, 3)
|
80
|
+
headers = {}
|
81
|
+
|
82
|
+
while (line = socket.gets) && (line.chomp! != "")
|
83
|
+
name, value = line.split(/:/, 2)
|
84
|
+
headers[name.strip] = value.strip
|
85
|
+
end
|
86
|
+
|
87
|
+
body = socket.read(headers["Content-Length"].to_i) if headers["Content-Length"]
|
88
|
+
|
89
|
+
return { version: version,
|
90
|
+
code: code.to_i,
|
91
|
+
reason: reason,
|
92
|
+
headers: headers,
|
93
|
+
body: body }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'openssl'
|
3
|
+
require 'net/ssh/proxy/errors'
|
4
|
+
require 'net/ssh/proxy/http'
|
5
|
+
|
6
|
+
module Net
|
7
|
+
module SSH
|
8
|
+
module Proxy
|
9
|
+
# A specialization of the HTTP proxy which encrypts the whole connection
|
10
|
+
# using OpenSSL. This has the advantage that proxy authentication
|
11
|
+
# information is not sent in plaintext.
|
12
|
+
class HTTPS < HTTP
|
13
|
+
# Create a new socket factory that tunnels via the given host and
|
14
|
+
# port. The +options+ parameter is a hash of additional settings that
|
15
|
+
# can be used to tweak this proxy connection. In addition to the options
|
16
|
+
# taken by Net::SSH::Proxy::HTTP it supports:
|
17
|
+
#
|
18
|
+
# * :ssl_context => the SSL configuration to use for the connection
|
19
|
+
def initialize(proxy_host, proxy_port=80, options={})
|
20
|
+
@ssl_context = options.delete(:ssl_context) ||
|
21
|
+
OpenSSL::SSL::SSLContext.new
|
22
|
+
super(proxy_host, proxy_port, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
# Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
|
28
|
+
# for all intents and purposes of Net::SSH::BufferedIo
|
29
|
+
module SSLSocketCompatibility
|
30
|
+
def self.extended(object) #:nodoc:
|
31
|
+
object.define_singleton_method(:recv, object.method(:sysread))
|
32
|
+
object.sync_close = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def send(data, _opts)
|
36
|
+
syswrite(data)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def establish_connection(connect_timeout)
|
41
|
+
plain_socket = super(connect_timeout)
|
42
|
+
OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
|
43
|
+
socket.extend(SSLSocketCompatibility)
|
44
|
+
socket.connect
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/ssh/proxy/command'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Proxy
|
7
|
+
# An implementation of a jump proxy. To use it, instantiate it,
|
8
|
+
# then pass the instantiated object via the :proxy key to
|
9
|
+
# Net::SSH.start:
|
10
|
+
#
|
11
|
+
# require 'net/ssh/proxy/jump'
|
12
|
+
#
|
13
|
+
# proxy = Net::SSH::Proxy::Jump.new('user@proxy')
|
14
|
+
# Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
|
15
|
+
# ...
|
16
|
+
# end
|
17
|
+
class Jump < Command
|
18
|
+
# The jump proxies
|
19
|
+
attr_reader :jump_proxies
|
20
|
+
|
21
|
+
# Create a new socket factory that tunnels via multiple jump proxes as
|
22
|
+
# [user@]host[:port].
|
23
|
+
def initialize(jump_proxies)
|
24
|
+
@jump_proxies = jump_proxies
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return a new socket connected to the given host and port via the jump
|
28
|
+
# proxy that was requested when the socket factory was instantiated.
|
29
|
+
def open(host, port, connection_options = nil)
|
30
|
+
build_proxy_command_equivalent(connection_options)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
# We cannot build the ProxyCommand template until we know if the :config
|
35
|
+
# option was specified during `Net::SSH.start`.
|
36
|
+
def build_proxy_command_equivalent(connection_options = nil)
|
37
|
+
first_jump, extra_jumps = jump_proxies.split(",", 2)
|
38
|
+
config = connection_options && connection_options[:config]
|
39
|
+
uri = URI.parse("ssh://#{first_jump}")
|
40
|
+
|
41
|
+
template = "ssh".dup
|
42
|
+
template << " -l #{uri.user}" if uri.user
|
43
|
+
template << " -p #{uri.port}" if uri.port
|
44
|
+
template << " -J #{extra_jumps}" if extra_jumps
|
45
|
+
template << " -F #{config}" if config != true && config
|
46
|
+
template << " -W %h:%p "
|
47
|
+
template << uri.host
|
48
|
+
|
49
|
+
@command_line_template = template
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'resolv'
|
3
|
+
require 'ipaddr'
|
4
|
+
require 'net/ssh/proxy/errors'
|
5
|
+
|
6
|
+
module Net
|
7
|
+
module SSH
|
8
|
+
module Proxy
|
9
|
+
# An implementation of a SOCKS4 proxy. To use it, instantiate it, then
|
10
|
+
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
11
|
+
#
|
12
|
+
# require 'net/ssh/proxy/socks4'
|
13
|
+
#
|
14
|
+
# proxy = Net::SSH::Proxy::SOCKS4.new('proxy.host', proxy_port, :user => 'user')
|
15
|
+
# Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
|
16
|
+
# ...
|
17
|
+
# end
|
18
|
+
class SOCKS4
|
19
|
+
# The SOCKS protocol version used by this class
|
20
|
+
VERSION = 4
|
21
|
+
|
22
|
+
# The packet type for connection requests
|
23
|
+
CONNECT = 1
|
24
|
+
|
25
|
+
# The status code for a successful connection
|
26
|
+
GRANTED = 90
|
27
|
+
|
28
|
+
# The proxy's host name or IP address, as given to the constructor.
|
29
|
+
attr_reader :proxy_host
|
30
|
+
|
31
|
+
# The proxy's port number.
|
32
|
+
attr_reader :proxy_port
|
33
|
+
|
34
|
+
# The additional options that were given to the proxy's constructor.
|
35
|
+
attr_reader :options
|
36
|
+
|
37
|
+
# Create a new proxy connection to the given proxy host and port.
|
38
|
+
# Optionally, a :user key may be given to identify the username
|
39
|
+
# with which to authenticate.
|
40
|
+
def initialize(proxy_host, proxy_port=1080, options={})
|
41
|
+
@proxy_host = proxy_host
|
42
|
+
@proxy_port = proxy_port
|
43
|
+
@options = options
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return a new socket connected to the given host and port via the
|
47
|
+
# proxy that was requested when the socket factory was instantiated.
|
48
|
+
def open(host, port, connection_options)
|
49
|
+
socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
|
50
|
+
connect_timeout: connection_options[:timeout])
|
51
|
+
ip_addr = IPAddr.new(Resolv.getaddress(host))
|
52
|
+
|
53
|
+
packet = [VERSION, CONNECT, port.to_i, ip_addr.to_i, options[:user]].pack("CCnNZ*")
|
54
|
+
socket.send packet, 0
|
55
|
+
|
56
|
+
version, status, port, ip = socket.recv(8).unpack("CCnN")
|
57
|
+
if status != GRANTED
|
58
|
+
socket.close
|
59
|
+
raise ConnectError, "error connecting to proxy (#{status})"
|
60
|
+
end
|
61
|
+
|
62
|
+
return socket
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'net/ssh/proxy/errors'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Proxy
|
7
|
+
# An implementation of a SOCKS5 proxy. To use it, instantiate it, then
|
8
|
+
# pass the instantiated object via the :proxy key to Net::SSH.start:
|
9
|
+
#
|
10
|
+
# require 'net/ssh/proxy/socks5'
|
11
|
+
#
|
12
|
+
# proxy = Net::SSH::Proxy::SOCKS5.new('proxy.host', proxy_port,
|
13
|
+
# :user => 'user', :password => "password")
|
14
|
+
# Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
|
15
|
+
# ...
|
16
|
+
# end
|
17
|
+
class SOCKS5
|
18
|
+
# The SOCKS protocol version used by this class
|
19
|
+
VERSION = 5
|
20
|
+
|
21
|
+
# The SOCKS authentication type for requests without authentication
|
22
|
+
METHOD_NO_AUTH = 0
|
23
|
+
|
24
|
+
# The SOCKS authentication type for requests via username/password
|
25
|
+
METHOD_PASSWD = 2
|
26
|
+
|
27
|
+
# The SOCKS authentication type for when there are no supported
|
28
|
+
# authentication methods.
|
29
|
+
METHOD_NONE = 0xFF
|
30
|
+
|
31
|
+
# The SOCKS packet type for requesting a proxy connection.
|
32
|
+
CMD_CONNECT = 1
|
33
|
+
|
34
|
+
# The SOCKS address type for connections via IP address.
|
35
|
+
ATYP_IPV4 = 1
|
36
|
+
|
37
|
+
# The SOCKS address type for connections via domain name.
|
38
|
+
ATYP_DOMAIN = 3
|
39
|
+
|
40
|
+
# The SOCKS response code for a successful operation.
|
41
|
+
SUCCESS = 0
|
42
|
+
|
43
|
+
# The proxy's host name or IP address
|
44
|
+
attr_reader :proxy_host
|
45
|
+
|
46
|
+
# The proxy's port number
|
47
|
+
attr_reader :proxy_port
|
48
|
+
|
49
|
+
# The map of options given at initialization
|
50
|
+
attr_reader :options
|
51
|
+
|
52
|
+
# Create a new proxy connection to the given proxy host and port.
|
53
|
+
# Optionally, :user and :password options may be given to
|
54
|
+
# identify the username and password with which to authenticate.
|
55
|
+
def initialize(proxy_host, proxy_port=1080, options={})
|
56
|
+
@proxy_host = proxy_host
|
57
|
+
@proxy_port = proxy_port
|
58
|
+
@options = options
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return a new socket connected to the given host and port via the
|
62
|
+
# proxy that was requested when the socket factory was instantiated.
|
63
|
+
def open(host, port, connection_options)
|
64
|
+
socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
|
65
|
+
connect_timeout: connection_options[:timeout])
|
66
|
+
|
67
|
+
methods = [METHOD_NO_AUTH]
|
68
|
+
methods << METHOD_PASSWD if options[:user]
|
69
|
+
|
70
|
+
packet = [VERSION, methods.size, *methods].pack("C*")
|
71
|
+
socket.send packet, 0
|
72
|
+
|
73
|
+
version, method = socket.recv(2).unpack("CC")
|
74
|
+
if version != VERSION
|
75
|
+
socket.close
|
76
|
+
raise Net::SSH::Proxy::Error, "invalid SOCKS version (#{version})"
|
77
|
+
end
|
78
|
+
|
79
|
+
if method == METHOD_NONE
|
80
|
+
socket.close
|
81
|
+
raise Net::SSH::Proxy::Error, "no supported authorization methods"
|
82
|
+
end
|
83
|
+
|
84
|
+
negotiate_password(socket) if method == METHOD_PASSWD
|
85
|
+
|
86
|
+
packet = [VERSION, CMD_CONNECT, 0].pack("C*")
|
87
|
+
|
88
|
+
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
|
89
|
+
packet << [ATYP_IPV4, $1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
|
90
|
+
else
|
91
|
+
packet << [ATYP_DOMAIN, host.length, host].pack("CCA*")
|
92
|
+
end
|
93
|
+
|
94
|
+
packet << [port].pack("n")
|
95
|
+
socket.send packet, 0
|
96
|
+
|
97
|
+
version, reply, = socket.recv(2).unpack("C*")
|
98
|
+
socket.recv(1)
|
99
|
+
address_type = socket.recv(1).getbyte(0)
|
100
|
+
case address_type
|
101
|
+
when 1
|
102
|
+
socket.recv(4) # get four bytes for IPv4 address
|
103
|
+
when 3
|
104
|
+
len = socket.recv(1).getbyte(0)
|
105
|
+
hostname = socket.recv(len)
|
106
|
+
when 4
|
107
|
+
ipv6addr hostname = socket.recv(16)
|
108
|
+
else
|
109
|
+
socket.close
|
110
|
+
raise ConnectError, "Illegal response type"
|
111
|
+
end
|
112
|
+
portnum = socket.recv(2)
|
113
|
+
|
114
|
+
unless reply == SUCCESS
|
115
|
+
socket.close
|
116
|
+
raise ConnectError, "#{reply}"
|
117
|
+
end
|
118
|
+
|
119
|
+
return socket
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Simple username/password negotiation with the SOCKS5 server.
|
125
|
+
def negotiate_password(socket)
|
126
|
+
packet = [0x01, options[:user].length, options[:user],
|
127
|
+
options[:password].length, options[:password]].pack("CCA*CA*")
|
128
|
+
socket.send packet, 0
|
129
|
+
|
130
|
+
version, status = socket.recv(2).unpack("CC")
|
131
|
+
|
132
|
+
if status != SUCCESS
|
133
|
+
socket.close
|
134
|
+
raise UnauthorizedError, "could not authorize user"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|