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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +93 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +21 -0
  5. data/.rubocop_todo.yml +1074 -0
  6. data/.travis.yml +51 -0
  7. data/CHANGES.txt +698 -0
  8. data/Gemfile +13 -0
  9. data/Gemfile.noed25519 +12 -0
  10. data/ISSUE_TEMPLATE.md +30 -0
  11. data/LICENSE.txt +19 -0
  12. data/Manifest +132 -0
  13. data/README.md +287 -0
  14. data/Rakefile +105 -0
  15. data/THANKS.txt +110 -0
  16. data/appveyor.yml +58 -0
  17. data/lib/net/ssh/authentication/agent.rb +284 -0
  18. data/lib/net/ssh/authentication/certificate.rb +183 -0
  19. data/lib/net/ssh/authentication/constants.rb +20 -0
  20. data/lib/net/ssh/authentication/ed25519.rb +185 -0
  21. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  22. data/lib/net/ssh/authentication/key_manager.rb +297 -0
  23. data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
  24. data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  25. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  26. data/lib/net/ssh/authentication/methods/none.rb +34 -0
  27. data/lib/net/ssh/authentication/methods/password.rb +80 -0
  28. data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
  29. data/lib/net/ssh/authentication/pageant.rb +497 -0
  30. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  31. data/lib/net/ssh/authentication/session.rb +163 -0
  32. data/lib/net/ssh/buffer.rb +434 -0
  33. data/lib/net/ssh/buffered_io.rb +202 -0
  34. data/lib/net/ssh/config.rb +406 -0
  35. data/lib/net/ssh/connection/channel.rb +695 -0
  36. data/lib/net/ssh/connection/constants.rb +33 -0
  37. data/lib/net/ssh/connection/event_loop.rb +123 -0
  38. data/lib/net/ssh/connection/keepalive.rb +59 -0
  39. data/lib/net/ssh/connection/session.rb +712 -0
  40. data/lib/net/ssh/connection/term.rb +180 -0
  41. data/lib/net/ssh/errors.rb +106 -0
  42. data/lib/net/ssh/key_factory.rb +218 -0
  43. data/lib/net/ssh/known_hosts.rb +264 -0
  44. data/lib/net/ssh/loggable.rb +62 -0
  45. data/lib/net/ssh/packet.rb +106 -0
  46. data/lib/net/ssh/prompt.rb +62 -0
  47. data/lib/net/ssh/proxy/command.rb +123 -0
  48. data/lib/net/ssh/proxy/errors.rb +16 -0
  49. data/lib/net/ssh/proxy/http.rb +98 -0
  50. data/lib/net/ssh/proxy/https.rb +50 -0
  51. data/lib/net/ssh/proxy/jump.rb +54 -0
  52. data/lib/net/ssh/proxy/socks4.rb +67 -0
  53. data/lib/net/ssh/proxy/socks5.rb +140 -0
  54. data/lib/net/ssh/service/forward.rb +426 -0
  55. data/lib/net/ssh/test/channel.rb +147 -0
  56. data/lib/net/ssh/test/extensions.rb +173 -0
  57. data/lib/net/ssh/test/kex.rb +46 -0
  58. data/lib/net/ssh/test/local_packet.rb +53 -0
  59. data/lib/net/ssh/test/packet.rb +101 -0
  60. data/lib/net/ssh/test/remote_packet.rb +40 -0
  61. data/lib/net/ssh/test/script.rb +180 -0
  62. data/lib/net/ssh/test/socket.rb +65 -0
  63. data/lib/net/ssh/test.rb +94 -0
  64. data/lib/net/ssh/transport/algorithms.rb +502 -0
  65. data/lib/net/ssh/transport/cipher_factory.rb +103 -0
  66. data/lib/net/ssh/transport/constants.rb +40 -0
  67. data/lib/net/ssh/transport/ctr.rb +115 -0
  68. data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
  69. data/lib/net/ssh/transport/hmac/md5.rb +10 -0
  70. data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  71. data/lib/net/ssh/transport/hmac/none.rb +13 -0
  72. data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  73. data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  74. data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  75. data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  76. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  77. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  78. data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  79. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  80. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  81. data/lib/net/ssh/transport/hmac.rb +47 -0
  82. data/lib/net/ssh/transport/identity_cipher.rb +57 -0
  83. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  84. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  85. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  86. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  87. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  88. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  89. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  90. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  92. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  93. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  94. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  95. data/lib/net/ssh/transport/kex.rb +31 -0
  96. data/lib/net/ssh/transport/key_expander.rb +30 -0
  97. data/lib/net/ssh/transport/openssl.rb +253 -0
  98. data/lib/net/ssh/transport/packet_stream.rb +280 -0
  99. data/lib/net/ssh/transport/server_version.rb +77 -0
  100. data/lib/net/ssh/transport/session.rb +354 -0
  101. data/lib/net/ssh/transport/state.rb +208 -0
  102. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  103. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  104. data/lib/net/ssh/verifiers/always.rb +58 -0
  105. data/lib/net/ssh/verifiers/never.rb +19 -0
  106. data/lib/net/ssh/version.rb +68 -0
  107. data/lib/net/ssh.rb +330 -0
  108. data/net-ssh-public_cert.pem +20 -0
  109. data/net-ssh.gemspec +44 -0
  110. data/support/ssh_tunnel_bug.rb +65 -0
  111. 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