summaryrefslogtreecommitdiff
path: root/lib/net/ssh/proxy
diff options
context:
space:
mode:
authorMarcus Ilgner <mail@marcusilgner.com>2016-09-09 16:54:43 +0200
committerMiklos Fazekas <mfazekas@szemafor.com>2016-10-15 16:54:27 +0200
commitd355aff1a18ca920c781a51ec716e1301983236f (patch)
treedda89e68ed91c6fd4ac1b16a7623283d6e3ad863 /lib/net/ssh/proxy
parented13802dc2059b479653f75c10bd15243f11c0df (diff)
downloadnet-ssh-d355aff1a18ca920c781a51ec716e1301983236f.tar.gz
Support HTTP Proxy on SSL socket
Since the HTTP Proxy only supports BASIC authentication, this adds the required infrastructure to net-ssh to connect to a SSL-enabled server. Closes: #432
Diffstat (limited to 'lib/net/ssh/proxy')
-rw-r--r--lib/net/ssh/proxy/http.rb11
-rw-r--r--lib/net/ssh/proxy/https.rb49
2 files changed, 56 insertions, 4 deletions
diff --git a/lib/net/ssh/proxy/http.rb b/lib/net/ssh/proxy/http.rb
index 27c99d5..5d64173 100644
--- a/lib/net/ssh/proxy/http.rb
+++ b/lib/net/ssh/proxy/http.rb
@@ -49,8 +49,7 @@ module Net; module SSH; module Proxy
# Return a new socket connected to the given host and port via the
# proxy that was requested when the socket factory was instantiated.
def open(host, port, connection_options)
- socket = Socket.tcp(proxy_host, proxy_port, nil, nil,
- connect_timeout: connection_options[:timeout])
+ socket = establish_connection(connection_options[:timeout])
socket.write "CONNECT #{host}:#{port} HTTP/1.0\r\n"
if options[:user]
@@ -68,7 +67,12 @@ module Net; module SSH; module Proxy
raise ConnectError, resp.inspect
end
- private
+ protected
+
+ def establish_connection(connect_timeout)
+ Socket.tcp(proxy_host, proxy_port, nil, nil,
+ connect_timeout: connect_timeout)
+ end
def parse_response(socket)
version, code, reason = socket.gets.chomp.split(/ /, 3)
@@ -89,7 +93,6 @@ module Net; module SSH; module Proxy
:headers => headers,
:body => body }
end
-
end
end; end; end
diff --git a/lib/net/ssh/proxy/https.rb b/lib/net/ssh/proxy/https.rb
new file mode 100644
index 0000000..e36ea0a
--- /dev/null
+++ b/lib/net/ssh/proxy/https.rb
@@ -0,0 +1,49 @@
+require 'socket'
+require 'openssl'
+require 'net/ssh/proxy/errors'
+require 'net/ssh/proxy/http'
+
+module Net; module SSH; module Proxy
+
+ # A specialization of the HTTP proxy which encrypts the whole connection
+ # using OpenSSL. This has the advantage that proxy authentication
+ # information is not sent in plaintext.
+ class HTTPS < HTTP
+
+ # Create a new socket factory that tunnels via the given host and
+ # port. The +options+ parameter is a hash of additional settings that
+ # can be used to tweak this proxy connection. In addition to the options
+ # taken by Net::SSH::Proxy::HTTP it supports:
+ #
+ # * :ssl_context => the SSL configuration to use for the connection
+ def initialize(proxy_host, proxy_port=80, options={})
+ @ssl_context = options.delete(:ssl_context) ||
+ OpenSSL::SSL::SSLContext.new
+ super(proxy_host, proxy_port, options)
+ end
+
+ protected
+
+ # Shim to make OpenSSL::SSL::SSLSocket behave like a regular TCPSocket
+ # for all intents and purposes of Net::SSH::BufferedIo
+ module SSLSocketCompatibility
+ def self.extended(object) #:nodoc:
+ object.define_singleton_method(:recv, object.method(:sysread))
+ object.sync_close = true
+ end
+
+ def send(data, _opts)
+ syswrite(data)
+ end
+ end
+
+ def establish_connection(connect_timeout)
+ plain_socket = super(connect_timeout)
+ OpenSSL::SSL::SSLSocket.new(plain_socket, @ssl_context).tap do |socket|
+ socket.extend(SSLSocketCompatibility)
+ socket.connect
+ end
+ end
+ end
+
+end; end; end