drb, firewall, ssh tunneling, and yield

J

Joel VanderWerf

I've noticed that I can run a drb server on a firewalled host, and talk
to it from outside the firewall, if the client uses ssh tunneling to
forward the port. At least, this works for simple method calls without
blocks. The problem I'm seeing is that if a method on the server side
yields to a block on the client side, the connection hangs. There is no
problem with the same code within the firewall. I'm guessing that drb is
trying to open another port, which hasn't been forwarded thru the tunnel.

Is there an easy solution to this problem? Other than avoid using yield,
that is...

==== server.rb ====
require 'drb'

class Test
def each
4.times do |i|
yield i
end
end

def to_a
[0,1,2,3]
end
end

DRb.start_service('druby://your.host.here:9876', Test.new)

puts '[interrupt] to exit.'
sleep
===================

==== client.rb ====
require 'drb'

DRb.start_service

x = DRbObject.new(nil, 'druby://localhost:9876')

p x.to_a # works fine

x.each do |i| # hangs here
p i
end
===================

==== forwarding ====
$ ssh -N -L 9876:your.host.here:9876 your.host.here
====================
 
N

Nathaniel Talbott

I've noticed that I can run a drb server on a firewalled host, and
talk to it from outside the firewall, if the client uses ssh tunneling
to forward the port. At least, this works for simple method calls
without blocks. The problem I'm seeing is that if a method on the
server side yields to a block on the client side, the connection
hangs. There is no problem with the same code within the firewall. I'm
guessing that drb is trying to open another port, which hasn't been
forwarded thru the tunnel.

Is the client side firewalled also? Basically callbacks work by running
a DRb server on the client, which the server then connects back to. If
your client is firewalled, the server won't be able to connect to your
client.

Is there an easy solution to this problem? Other than avoid using
yield, that is...

DRbFire might interest you:

http://rubyforge.org/projects/drbfire/

It's still very much in development, but it allows bi-directional
communication through a firewall. It's more oriented towards
circumventing client-side firewalls, but in your case I think it would
work fine if you just forwarded the additional port it needs (your
normal DRb port + 1).

I'd love some outside feedback on how it works (or doesn't work) for
you. Documentation is minimal at this point, consisting only of a
sample client and server (and tests), but it's pretty simple to use,
and you're welcome to drop me an email with any questions you have.

HTH,


Nathaniel

<:((><
 
J

Joel VanderWerf

Nathaniel said:
Is the client side firewalled also? Basically callbacks work by running
a DRb server on the client, which the server then connects back to. If
your client is firewalled, the server won't be able to connect to your
client.

Yes, that's probably it. The client is behind a NAT.
DRbFire might interest you:

http://rubyforge.org/projects/drbfire/

It's still very much in development, but it allows bi-directional
communication through a firewall. It's more oriented towards
circumventing client-side firewalls, but in your case I think it would
work fine if you just forwarded the additional port it needs (your
normal DRb port + 1).

That makes sense. But I haven't got the incantation right. On the client
side, I do:

$ ssh -N -L 9876:remote.host:9876 -R 9877:localhost:9877 remote.host

But I still have the same behavior: it hangs on the callback.
I'd love some outside feedback on how it works (or doesn't work) for
you. Documentation is minimal at this point, consisting only of a sample
client and server (and tests), but it's pretty simple to use, and you're
welcome to drop me an email with any questions you have.

DRbFire sounds great... I'll check it out!
 
N

Nathaniel Talbott

Yes, that's probably it. The client is behind a NAT.

That'd do it.

That makes sense. But I haven't got the incantation right. On the
client side, I do:

Oh, I wasn't very clear. I meant that's what you'd need to do if you
were using DRbFire. If you're not, you'd need to specify the url to use
on the client side when you do your DRb.start_service:

DRb.start_service("druby://localhost:9877")

Otherwise DRb picks any available port, and specifies your actual
hostname (instead of localhost). Once you do that, this incantation...
$ ssh -N -L 9876:remote.host:9876 -R 9877:localhost:9877 remote.host

...should work.

DRbFire sounds great... I'll check it out!

I'm not sure how much of an advantage it would be in your case, since
you're already using SSH tunneling. I wrote it to avoid having to do
that myself. It (obviously) can't handle a firewalled server on its
own; it would still need the ssh tunnel for that.

HTH,


Nathaniel

<:((><
 
J

Jim Freeze

DRbFire might interest you:

http://rubyforge.org/projects/drbfire/

It's still very much in development, but it allows bi-directional
communication through a firewall. It's more oriented towards
circumventing client-side firewalls, but in your case I think it would
work fine if you just forwarded the additional port it needs (your
normal DRb port + 1).


Ok, I'm not too bright on things like this, but it sounds cool.
What would be the value of such a thing? Can you provide some
example uses that are subversive, legal, sly or whatever? :)
 
E

Evan Webb

If you extend the normal drb tcp protocol a little bit, you could let it
poke holes in NATs for you. When the client is doing a callback (ie, the
server is sending data in to the client on a new port), just have the
client open a blind tcp connection on that port to the server, that way
the connection tracking will get setup and and the server can connect
back to the client. Or, since the client is doing a connection to the
server anyway to poke the hole, just do the new connection on that
channel. It boils down to only the client create new connections.

Evan
 
J

Joel VanderWerf

Nathaniel said:
Oh, I wasn't very clear. I meant that's what you'd need to do if you
were using DRbFire. If you're not, you'd need to specify the url to use
on the client side when you do your DRb.start_service:

DRb.start_service("druby://localhost:9877")

That works perfectly, and it all makes sense now... Thanks!
 
N

Nathaniel Talbott

If you extend the normal drb tcp protocol a little bit, you could let
it
poke holes in NATs for you. When the client is doing a callback (ie,
the
server is sending data in to the client on a new port), just have the
client open a blind tcp connection on that port to the server, that way
the connection tracking will get setup and and the server can connect
back to the client. Or, since the client is doing a connection to the
server anyway to poke the hole, just do the new connection on that
channel. It boils down to only the client create new connections.

You have just described almost exactly what DRbFire does... want to
write docs? ;-)


Nathaniel

<:((><
 
N

Nathaniel Talbott

Ok, I'm not too bright on things like this, but it sounds cool.
What would be the value of such a thing? Can you provide some
example uses that are subversive, legal, sly or whatever? :)

It's not really subversive... basically, it just allows the server to
call back to clients that are behind firewalls. So the client can pass
the server a proxied (DRbUndumped) object, and at some later time, the
server can call a method on that object and have that method call
relayed back to the client. Normally this is done via the server
initiating the connection, but if the client is behind a firewall (or
NAT), that doesn't work. So we have the client initiate connections to
the server that the server then uses for calling back to the client.

Does that make more sense?


Nathaniel

<:((><
 
J

Jim Freeze

On Jan 15, 2004, at 20:16, Jim Freeze wrote:

It's not really subversive... basically, it just allows the server to
call back to clients that are behind firewalls. So the client can pass
the server a proxied (DRbUndumped) object, and at some later time, the
server can call a method on that object and have that method call
relayed back to the client. Normally this is done via the server
initiating the connection, but if the client is behind a firewall (or
NAT), that doesn't work. So we have the client initiate connections to
the server that the server then uses for calling back to the client.

Does that make more sense?

I think so. How about this example:

|
[A] |
work | home
firewall

Let's say I have two machines, one work machine
behind a firewall and a home machine. I cannot
connect to A from B because of the firewall, but
I can connect from A to B. So, while at work, I
make a connection to B. Then when I get home, I
assume there is a way that I can call back into
A with that open connection. Is this correct?
If so, what type of calls can I make back to A.
I am limited to ruby code through drb?
Could I ever get an ssh open from B to A?
 
G

Gregory Millam

Received: Fri, 16 Jan 2004 12:48:55 +0900
And said:
Let's say I have two machines, one work machine
behind a firewall and a home machine. I cannot
connect to A from B because of the firewall, but
I can connect from A to B. So, while at work, I
make a connection to B. Then when I get home, I
assume there is a way that I can call back into
A with that open connection.
(I assume one of those is B to A)

SSH can create port forwarding tunnels in either direction.

Suppose you can't log into your home network from work, but you can log into your work network from home. All via SSH

On your home server:

ssh -R 9877:localhost:1234 (e-mail address removed)

This will both log you into your work computer from home, AND open port 1234 on yourcomputer.at.work.com - if you connect to yourcomputer.at.work.com:1234, it is essentially the same as connecting to home.server.net:9877. You can use 9877 local and remote, I just used 1234 so you know which number is which. You can also use this with port 22 as the local port to allow SSH connections in that normally can't.

To do the reverse:

Suppose only your port 22 outgoing from home to work is allowed out by your firewall. Simply switch -R to -L

ssh -L 1234:localhost:9877 (e-mail address removed)

Then if you connect to home.server.net:1234, you get whatever service is listening on yourcomputer.at.work.com:9877

So to let a script at work connect to a druby server at your home, run the -R version. To let a script on your home box connect to a druby server at work, run the -L version. In both cases, run them from your home server.

Also, you might want to consider appending "-f sleep 86400" to either command, if you don't want a login prompt. Instead, it will background SSH, and it'll listen for 86400 seconds (1 day) So ...

ssh -R 9877:localhost:9877 (e-mail address removed) -f sleep 86400

That'll make the port forwarder active for 1 day. Tweak at will.

Hope this helped, and wasn't overly in depth.

- Greg
 
J

Jim Freeze

Received: Fri, 16 Jan 2004 12:48:55 +0900
And lo Jim wrote:

SSH can create port forwarding tunnels in either direction.

Suppose you can't log into your home network from work, but you can log into your work network from home. All via SSH

On your home server:

ssh -R 9877:localhost:1234 (e-mail address removed)

Ok, I did this then ssh'd into the work computer, but how do I now
get contact back to the home computer?
 
J

Joel VanderWerf

Jim said:
Ok, I did this then ssh'd into the work computer, but how do I now
get contact back to the home computer?

This is what worked for me:

home.host$ ssh -R 9022:localhost:22 (e-mail address removed)
remote.host$ ssh -p 9022 localhost

The 9022 can be anything, of course. Also, if your username is different
on the two hosts, the second line might need to be (untested):

remote.host$ ssh -p 9022 username@localhost
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top