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 }