Skip to content
Advertisement

How to do dynamic port forwarding using Ruby

How do I do SSH dynamic port forwarding on Ruby?

I tried to use gems such as “net/ssh/socks” and “net/ssh/gateway”, but it looks like they are already outdated because I can’t even require them.

All I need to do is run this shell command

ssh -D 5555 user@host -f -N

and receive the PID of this process.

I also tried to use Kernel#system and Kernel#spawn.

For example:

pid = spawn("ssh -D 5555 user@host -f -N")
Process.wait pid

This works fine for me, but the PID is always returned 3 units less than the real PID of the process that started. For example, the returned PID is 1555 and the real PID is 1558.

Another question: why is the difference in the PID always 3 and can there be another difference? Can I use pid + 3 reliably?

Advertisement

Answer

Using the SSH binary

You are running SSH with -f (fork). In Ruby, Kernel.spawn will automatically fork the process into the background, so you do not need to use -f. If you use -f you will create a double fork situation, which is the reason for the PID anomaly.

This should be enough to make it work:

pid = spawn("ssh -N -D 5555 user@host")

Using Net::SSH with Net::SSH::Socks

If you want to use net-ssh-socks you will have to clone the repository manually, since the Rubygems version has not been updated for the latest Net::SSH.

git clone https://github.com/cristianbica/net-ssh-socks

Then your Ruby code would look like this, assuming you cloned into the same folder that your script is running in:

$:.push('net-ssh-socks/lib')  # Add the cloned repo to load path
require 'net/ssh/socks'

ssh = Net::SSH.start('host', 'user')
ssh.forward.socks(5555)
ssh.loop { true }
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement