summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordelano <delano@delanotes.com>2014-02-01 11:32:20 -0500
committerdelano <delano@delanotes.com>2014-02-01 11:32:20 -0500
commitd181edf8c3c9c71b3683a1752012ffd19df13148 (patch)
tree504b1f38efdcf42684fc3f6a371947f48aec2a2d
parentf41ba9750e549ee1822201c9fabf37fd49150638 (diff)
parentcbe2861162e4bd5f8658a008566d98b3f01c6cd9 (diff)
downloadnet-ssh-aderouineau-master.tar.gz
Merge branch 'master' of github.com:aderouineau/net-ssh into aderouineau-masteraderouineau-master
-rw-r--r--THANKS.txt1
-rw-r--r--lib/net/ssh/service/forward.rb25
-rw-r--r--test/manual/test_forward.rb41
3 files changed, 47 insertions, 20 deletions
diff --git a/THANKS.txt b/THANKS.txt
index dc5b0ad..dbe8a7f 100644
--- a/THANKS.txt
+++ b/THANKS.txt
@@ -83,3 +83,4 @@ watsonian
Grant Hutchins
Michael Schubert
mtrudel
+Aurélien Derouineau
diff --git a/lib/net/ssh/service/forward.rb b/lib/net/ssh/service/forward.rb
index 3b0face..0d5d55d 100644
--- a/lib/net/ssh/service/forward.rb
+++ b/lib/net/ssh/service/forward.rb
@@ -47,8 +47,12 @@ module Net; module SSH; module Service
# If three arguments are given, it is as if the local bind address is
# "127.0.0.1", and the rest are applied as above.
#
+ # To request an ephemeral port on the remote server, provide 0 (zero) for
+ # the port number. In all cases, this method will return the port that
+ # has been assigned.
+ #
# ssh.forward.local(1234, "www.capify.org", 80)
- # ssh.forward.local("0.0.0.0", 1234, "www.capify.org", 80)
+ # assigned_port = ssh.forward.local("0.0.0.0", 0, "www.capify.org", 80)
def local(*args)
if args.length < 3 || args.length > 4
raise ArgumentError, "expected 3 or 4 parameters, got #{args.length}"
@@ -69,6 +73,7 @@ module Net; module SSH; module Service
end
end
+ local_port = socket.addr[1] if local_port == 0 # ephemeral port was requested
remote_host = args.shift
remote_port = args.shift.to_i
@@ -89,6 +94,8 @@ module Net; module SSH; module Service
channel[:socket].close
end
end
+
+ local_port
end
# Terminates an active local forwarded port. If no such forwarded port
@@ -120,15 +127,21 @@ module Net; module SSH; module Service
# forwarded immediately. If the remote server is not able to begin the
# listener for this request, an exception will be raised asynchronously.
#
- # If you want to know when the connection is active, it will show up in the
- # #active_remotes list. If you want to block until the port is active, you
- # could do something like this:
+ # To request an ephemeral port on the remote server, provide 0 (zero) for
+ # the port number. The assigned port will show up in the # #active_remotes
+ # list.
+ #
+ # If you want to block until the port is active, you could do something
+ # like this:
#
- # ssh.forward.remote(80, "www.google.com", 1234, "0.0.0.0")
- # ssh.loop { !ssh.forward.active_remotes.include?([1234, "0.0.0.0"]) }
+ # old_active_remotes = ssh.forward.active_remotes
+ # ssh.forward.remote(80, "www.google.com", 0, "0.0.0.0")
+ # ssh.loop { !(ssh.forward.active_remotes.length > old_active_remotes.length) }
+ # assigned_port = (ssh.forward.active_remotes - old_active_remotes).first[0]
def remote(port, host, remote_port, remote_host="127.0.0.1")
session.send_global_request("tcpip-forward", :string, remote_host, :long, remote_port) do |success, response|
if success
+ remote_port = response.read_long if remote_port == 0
debug { "remote forward from remote #{remote_host}:#{remote_port} to #{host}:#{port} established" }
@remote_forwarded_ports[[remote_port, remote_host]] = Remote.new(host, port)
else
diff --git a/test/manual/test_forward.rb b/test/manual/test_forward.rb
index 8e27818..5794077 100644
--- a/test/manual/test_forward.rb
+++ b/test/manual/test_forward.rb
@@ -1,4 +1,4 @@
-# $ ruby -Ilib -Itest -rrubygems test/test_forward.rb
+# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb
# Tests for the following patch:
#
@@ -30,14 +30,6 @@ class TestForward < Test::Unit::TestCase
[localhost ,ENV['USER'], {:keys => "~/.ssh/id_rsa", :verbose => :debug}]
end
- def find_free_port
- server = TCPServer.open(0)
- server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR,true)
- port = server.addr[1]
- server.close
- port
- end
-
def start_server_sending_lot_of_data(exceptions)
server = TCPServer.open(0)
Thread.start do
@@ -77,12 +69,34 @@ class TestForward < Test::Unit::TestCase
return server
end
+ def test_local_ephemeral_port_should_work_correctly
+ session = Net::SSH.start(*ssh_start_params)
+
+ assert_nothing_raised do
+ assigned_port = session.forward.local(0, localhost, 22)
+ assert_not_nil assigned_port
+ assert_operator assigned_port, :>, 0
+ end
+ end
+
+ def test_remote_ephemeral_port_should_work_correctly
+ session = Net::SSH.start(*ssh_start_params)
+
+ assert_nothing_raised do
+ session.forward.remote(22, localhost, 0, localhost)
+ session.loop { !(session.forward.active_remotes.length > 0) }
+ assigned_port = session.forward.active_remotes.first[0]
+ assert_not_nil assigned_port
+ assert_operator assigned_port, :>, 0
+ end
+ end
+
def test_loop_should_not_abort_when_local_side_of_forward_is_closed
session = Net::SSH.start(*ssh_start_params)
server_exc = Queue.new
server = start_server_sending_lot_of_data(server_exc)
remote_port = server.addr[1]
- local_port = find_free_port
+ local_port = 0 # request ephemeral port
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
@@ -104,7 +118,7 @@ class TestForward < Test::Unit::TestCase
server_exc = Queue.new
server = start_server_sending_lot_of_data(server_exc)
remote_port = server.addr[1]
- local_port = find_free_port
+ local_port = 0 # request ephemeral port
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
@@ -163,7 +177,7 @@ class TestForward < Test::Unit::TestCase
session = Net::SSH.start(*ssh_start_params)
server = start_server_closing_soon
remote_port = server.addr[1]
- local_port = find_free_port
+ local_port = 0 # request ephemeral port
session.forward.local(local_port, localhost, remote_port)
client_done = Queue.new
Thread.start do
@@ -203,8 +217,7 @@ class TestForward < Test::Unit::TestCase
client_exception = Queue.new
client_data = Queue.new
remote_port = server.addr[1]
- local_port = find_free_port
- session.forward.local(local_port, localhost, remote_port)
+ local_port = session.forward.local(0, localhost, remote_port)
Thread.start do
begin
client = TCPSocket.new(localhost, local_port)