forwarding approaches exercise

Ordinary port forwarding

A machine can perform port forwarding. Port forwarding manipulates received udp or tcp packets having a particular port number in their destination port fields. The machine sluffs them off to some other machine by re-writing the destination IP field's value. When it arrives, that value is the machine's own (that's what got it there!), which the machine overwrites with the IP address of the other machine. It then injects the new, modified packet into the network where the other machine resides. Call this machine "forwarder;" the other "target."

We use this network architecture:

At the remote site the forwarder is (aka The "target" is I will run the needed command on the forwarder to make it forward to the target all port 9999 packets it gets, and I'll start a server to be available on the target's port 9999 (server3.c). 

So what's the magic command for forwarding that I'm going to run? It's iptables with a syntax like this:

iptables -t nat -A PREROUTING -p tcp -d <forwarder's IP>/32 --dport 9999 -j DNAT --to <target's IP>

To break that down in English:

-A means add
-t nat refers to a table of to-be-performed address re-writes (nat=network address "translation"). So the first part means "set up a new address re-write task." The rest of the command specifies what the task is.

 -p tcp says it applies to tcp packets specifically. More narrowly,
 -d <forwarder's IP>/32 specifies those tcp packets addressed to this machine. Narrower still,
 --dport 9999 focuses among those packets on just the ones slated for port 9999.

Now that we know which packets are to be affected, the rest of the command tells what to do with them.
-j DNAT says that the item to be changed (NATted) is the destination address of the packet (D). OK, changed to what?
--to <target's IP> responds; the new value is to be the IP of the target machine.

PREROUTING says to make this change before deciding where to route this packet. That amounts to choosing the new address as the one presented to the routing mechanism, and therefore the one determining the routing decision.

The address-specific syntax is:

iptables -t nat -A PREROUTING -p tcp -d --dport 9999 -j DNAT --to

That constructs the desired packet. If there is no obstruction to its being forwarded, nothing else is required. Most environments obstruct forwarding by default and require explicit, particular permission for non-default behavior (ie, forwarding that works). The additional rule would be:

iptables -A FORWARD -p tcp -d --dport 9999 -j ACCEPT

These are commands I will run on the forwarder; you don't have to run them. As your job, please edit client3.c to send a letter of your choice to the forwarder address ( with the designated forwarded port number (9999). Compile it. 

gcc client3.c -o client3

I will launch dynamic network sniffs (tcpdump) from both forwarder and target, for you to watch on screen in class. Run your client. I will delete the forwarding rule. Run client3 again. Under both conditions (with/without forwarding), observe the packet behavior at both remote machines.

Ordinary ssh port forwarding

Now let's do it another way, through ssh. ssh is most commonly used for remote login sessions, as a kind of encrypted telnet. Run it that way:

ssh student01@<forwarder address>

answer "yes" to any question about host authenticity that may appear. You should get the prompt and be able to operate on the remote forwarder as student1 much as if you had used telnet. Exit the remote forwarder by quitting from ssh:


Reconnect with the remote server, this time amending your ssh invocation to afford the additional, port forwarding feature ssh offers. In doing so choose a random port number like, say, 3350.

ssh -L 3350:<target address>:9999 student01@<forwarder address>

It looks no different, you will still just see a prompt from the server. However a port forwarding arrangement beyond the server has been set up. It extends to the target machine on the server's LAN at the remote site. Specifically, to that machine's port 9999. You can regard the forwarding arrangement as a secondary side-effect of the remote login. ssh is now listening on port 3350. Observe it doing so:

netstat -pant  |  grep 3350

You now want to run, on your class machine, the client for the server that is running on the target machine. The server is server3.c, so the client is client3.c. (You'll need to get into another virtual terminal or terminal window, since the one where you're working no longer shows your local machine's prompt but that of the remote server.) Edit client3.c to talk to your machine (at either or your NIC's address). And to talk to your machine's port 3350. Compile it

gcc -o client3 client3.c

Run it.


You should see the server's response. But the server isn't running on your machine, to which you directed your connection. It is however running over on the remote target machine. Who produced the server response that you saw? How did it get to you?


ssh's X11 forwarding

ssh has an "X11 forwarding" feature that allows an X client on one computer to deliver its display to an X server on another (provided so configured in /etc/ssh/sshd_config). Of course, X can do this all by itself. However that's insecure. ssh X11 forwarding's value lies in the encryption it affords to the datastream. Technically neither of these is a form of port forwarding, which takes existing packets as given and manipulates them to change their path of travel. Both X remote display and ssh X11 forwarding are initiators of network communication, they create their own packet stream and packets rather than "forwarding" somebody else's. First, let's exercise X remote display, to display an X application's output on another computer without ssh. After that we'll incorporate ssh into the operation.

X remote display without ssh

Work in pairs. Identify your two machines distinctively. It is tempting to call one of them client and the other server. But in the activities below each machine will play both roles-- client in respect of some software and server in respect of other. So those terms won't be  accurate or useful. Therefore, arbitrarily choose one machine to be called FIRST, the other SECOND. Boot both into character mode (ie, no GUI running please). On FIRST:

xinit /usr/bin/mwm &  (or possibly it's /usr/X11R6/bin/mwm; "which mwm" reveals)

then in the resultant gui open a terminal window (right click, "New Window") in which, set an environment variable to SECOND's IP address. Then give SECOND permission to play with your hardware:

xhost +$SECOND

Launch a new terminal window, but first export the SECOND variable so that it'll be available in that window:

export SECOND
xterm &

Arrange the windows to be simultaneously visible on your desktop, and widen the new one to span the width of the screen. In it:

tcpdump -nnti eth0 host $SECOND

You will be able to watch the packet movie that's "now playing" in this new monitor window.

At SECOND set an environment variable to hold FIRST's IP address. Then run xclock with a distinctive title, connecting it to the X server you've just launched on FIRST:

xclock -title "you're late" -display $FIRST:0

At either SECOND (ctrl-C) or FIRST (window controls), kill xclock (running on SECOND and appearing on FIRST). Study the tcpdump output and determine what port FIRST (the X server) used. Accordingly, what protocol delivered the timely screen imagery between computers?

ssh X11 forwarding (X display forwarding with ssh)

Above, xclock (a GUI application) was initiated by a command given to SECOND's cpu, so ran there (where there's no GUI!), with its display sent to FIRST. We'll now do the same through ssh. But the xclock command will be given to SECOND's cpu by an operator at FIRST who has remote access to SECOND through ssh. Set up that access, at FIRST:


You get SECOND's command prompt. Actually, just for fun before we proceed, there's no reason you can't now repeat exactly the above non-ssh interaction from here. By executing the exact same command. The only difference being that to launch it you were at the computer that ran it launching it locally where now you'll be at the other computer launching it remotely. ssh just happens to be the launching device this time. But the display forwarding will still be done by X, because it's still the very same command getting run on the very same cpu:

xclock -title "you're late" -display $FIRST:0

Note from tcpdump that it ran on the same service port as before. That's not what we want though. We want to exercise ssh's own X11 forwarding feature instead. How? It's pretty much automatic. Close the clock, then just run:

xclock -title "you're late"

Don't even mention the target display. The result is the same, except when you look at the tcpdump output in the monitor window. Study it and determine what port SECOND (the sshd server) used. Accordingly, what protocol delivered the screen imagery between computers? What's up? Why did the display show up on FIRST without our asking? Terminate xclock and run:


Read the section titled "X11 and TCP forwarding" in the ssh man page, and look up the variable DISPLAY in the section titled ENVIRONMENT in the X man page.

special cases for remote control of whole machines, instructor demo

VNC via ssh port forwarding

VNC via ssh X11 forwarding

rdesktop via ssh port forwarding