Freedom, Horrible Freedom -- or How I Learned to Quit Worrying, and Love Firewalls
A strategy guide for the victims of facist routing policies...
Version 1.0
Copyright 1998 Sam Creasey
Table of Contents:
Introduction
About this document
Tunneling basics
Creating your tunnel
Fake serial links
Emulating a modem
Fake SLIP links
Fake PPP links
PPP with slirp
Non-serial tunnels
Tunneling with crackpipe
Other tunnel methods
Using your tunnel
Incoming connections
Redirecting FTP connections
Redirection limitations
Outgoing connections
Using your tunnel as a primary link
Other considerations
Choosing a tunneling method
Crossing a firewall without a tunnel
Linux+IP Masquerading
Closing comments
Copyright information

Introduction

This document is written as a guide for those unfortunate folk who, for some reason, find themselves trapped under the control of Netadmins who have decided to curtail the traffic to/from their address, and who want to do something about it. It is intended to be a basic guide to getting around their restrictions, and, with some effort, to making the connections you always wanted.

Hopefully, after reading this, you will be able to work your way around the limitations placed on you by those who control your routers... and, with any luck, you'll have learned the tricks necessary to be the master of your own uplink. At any rate, it should teach the unfortunate a bit about their plight.

Personally, I'm writing this because, while my own connectivity is clear at the moment, I'm tired of watching friends flail around not being able to telnet to their own machines, and wishing there were something they could do about it... It somehow disturbs me that in the quest against w4r3z/mp3 distribution, people who just want an incoming telnet, or to ftp documents home, or a remote X display, or one of 8 million other legitimate services can't get to their own machine when they need it. (For a non-technical parallel of locking down everyone to stop a few people, I always like the phrase "What are the politicians going to tell people when the constitution's gone and we still have a drug problem?" -- I think the same mentality applies to a lot of network admins.) I considered the alternate title "Principia Securitatis, or How I Found Admin, and What I Did to Him When I Found Him," but I decided that such names are only worth of documents written entirely within the span of an acid trip, which this one was not...

-- Sam Creasey 11/11/98

Document Scope

I'll be discussing the basic ideas involved in freeing oneself from port restrictions... This will probably touch on other ideas of generic routing interest, but only when relevant to the larger goal... I'll try not to assume any great familiarity with unix/networking in general. Most of this will be largely specific to linux, but some will not. Your milage may vary.

The Basic Concept

Basically, freeing oneself from a firewall involves finding an alternate route for the packets to travel through. Generally, you're going to need somewhere on the outside to use as a relay point -- a friendly machine to serve as an alternate point of entry/exit for your system. This can be anything from a buddy who's willing to bend over backwards for you, to just a shell machine where you've got some range to do as you please.

The main approach I'll be taking is to find a way to tunnel your packets through a connection which will pass through your firewall, and to use this tunnel to handle the dreaded "forbidden traffic"...

Creating your tunnel

There are 2 approaches to creating your tunnel. The most generic way, which works in almost all situations, but if far less elegant, is to fake a serial link. Alternately, you can use some kind of "true" packet tunnel to free yourself from the serial overhead. This section will discuss setting the link up initially, using it will be discussed later.

Fake serial links

To fake a serial link, you've got to have a device which can look like a modem on your end for the serial link to use. The easiest way to do this is with modemu. Find this on sunsite.unc.edu in /pub/Linux/apps/serialcomm/dialout. Modemu will set up a device for you to use, read the modemu docs for information about how to actually use it.

The other end: Assuming that your other system is friendly, whoever is root there can set up a slip or ppp connection for you to use, creating an address on that side. For slip connections, "dip" is the program to use. this comes with most common linux distributions, dunno about other unixes. pppd will be what to run for a PPP link.

If you're not able to get your other end to set up things for you, you can still use slirp to get your connection. I'll go through bringing up all 3 of these links now. In the first 2 examples, the address of the remote host will be 192.168.1.1, and the address of your machine will be 192.168.1.2 for setting up the tunnel. Slirp is a little different, we'll cover that there.

Starting modemu

First thing, use modemu to bring up your fake serial connection. Here's an example of doing this under linux with minicom.

(local# is the prompt for your machine...)

local# modemu -s &
p0 (this means modemu is using /dev/ttyp0...  if it said p1. use
    /dev/ttyp1, you get the idea...)

local# minicom -p /dev/ttyp0
   (minicom will now open, and you can "dial" to the remote hose)
  
atd"remote-host" (this is the name of the remote host, in quotes)
   (you will now get a login prompt.  login as usual)

Now, you are at the shell prompt on the remote machine. The following 3 examples, for slip, ppp, and slirp all start at this point. remote# is the prompt for the remote machine, local# is still the prompt for your machine.

Starting a SLIP connection

dip is, in my opinion, a pain in the goddamn ass, because it tries to do things "right", which means that you've gotta jump through some hoops to get it to behave. There was a nice utility called "slattach" in the olden days which would kindly let you do everything by hand, but I can't find the source to the beast now. So, you've got to create a file called /etc/dipusers on the remote machine. The format of this file is discussed in the man pages, here's our example for simplicity.


slipuser::192.168.1.2:192.168.1.1:::cslip,512

After some mucking about with this, I can come only to the conclusion that dip is a fucking cunt of a slip program, and I'm not finishing this section. I'll do it later.

Starting a PPP connection

You've probably been stuck on the ass end of some dialup link before, so I'm betting you're familiar with having to use a ppp connection. Hopefully, this one will be a little bit faster. :) Once you're logged into the remote machine, you'll have to bring up their pppd, and then yours. This is fairly simple.

remote# pppd 192.168.1.1:192.168.1.2
(now suspend minicom --  alt-j)
(you'll now need to delete the lockfile that minicom made so that pppd 
will run.  this file will probably be in /var/lock, or maybe
/usr/spool/uucp for some people.  anyway...)

local# rm /var/lock/LCK..ttyp0  (or whatever your tty was)
local# pppd /dev/ttyp0 (or your tty)

Now, typing ifconfig should show a ppp interface on the address 192.168.1.2. telnetting to 192.168.1.1 ought to get you a telnet connection to the other machine. Voila, you've got a PPP tunnel made.

Obviously, this could be scripted to make matters much nicer. Look around for examples of using a "chat" script with pppd, etc, but instead of using the modem commands, you'd use the modemu stuff you did above.

Starting a Slirp connection

Slirp is an interesting beast, but it's pretty damn convenient for this sort of thing. The idea is, slirp will pretend to establish a PPP connection with you, but you don't really get an address on the other machine, it's all emulated. But, it's still a tunnel which you can work with. If you're using redhat linux, there are slirp RPM's available in the contrib directory on your favorite redhat mirror. Otherwise, the source code can be found on sunsite.unc.edu in /pub/Linux/system/network/serial/slirp-*.tar.gz. Compiling it is left as an exercise to the reader. it's pretty painless.

Ok, so you've got your modemu session running, you're ready to bring up slirp. I would start slirp in ppp mode, by doing something like:


remote# slirp -P
(slirp will then announce that it's starting in PPP mode)
(as above, suspend minicom and remove the lock)
local# pppd /dev/ttyp0 (or your tty)

Slirp will now have started. It should have given you the address 10.0.2.15, which is fine. You should add a route for slirp's network by typing:

local# route add -net 10.0.2.0 netmask 255.255.255.0 ppp0

Further information about what you can do with slirp can be found in the slirp documentation.

Creating "real" tunnels

Faking a serial link is, well, neither the most elegant, nor the fastest, nor the most versatile, way of beating a firewall. Using this method limits you to having to dick with modemu, and support a telnet connection, and use rather kludgy workarounds to manipulate software which wasn't designed for this purpose.

There are numerous other tunneling methods -- there is IPIP protocol encapsulation, which is probably the "proper" way to do this, but I haven't ever looked at it, and your firewall may not even let such packets through. My solution, which is flexible, is to use crackpipe .

Tunneling with crackpipe

The primary downside to crackpipe is that it requires both ends of the connection to be running linux, and, more specifically, both sides need to be using fairly new Linux 2.1 kernels, as crackpipe relies on facilities which have only recently become available. There is some documentation for crackpipe at the end of the source file, which explains which options you need compiled into your kernel. I'm not going into how to actually compile a linux kernel now, that is also left as a exercise to the reader.

Before you compile crackpipe, you will need to decide if you are going to use TCP or UDP to create your tunnel. Near the beginning of the source are 2 lines which you must edit to specify your protocol. UDP is generally going to be faster, and it will also probably be able to cross more firewalls, as most netadmins are more gung-ho on blocking TCP connections than UDP ones. If UDP is not available for you, choose TCP. The 2 lines should look like either:

(to use UDP)
#define UDP
#undef TCP
(or, to use TCP)
#undef UDP
#define TCP

One line should start with #undef, and one with #define. If they're both the same, you fucked up, and it's not going to work. To compile crackpipe, you should only need to type:

local# gcc -o crackpipe crackpipe.c

This ought to produce an executable called "crackpipe" in the current directory. You need to do this on both the local and remote systems. Next, in a seperate xterm/console/whatever, login to the remote system, and become root. First, configure the interface on the local machine:

local# ifconfig tap0 192.168.1.2 mtu 1000

Next, configure the remote network interface with something like:

remote# ifconfig tap0 192.168.1.1 mtu 1000

Both systems are now ready for you to start crackpipe. (A note about the MTU value: This is discussed in crackpipe.c, but the general rule is that the mtu for the tunnel must be smaller than the mtu used for the real network connection (which is usually 1500). 1000 seems to be a good value. Consult the source for more discussion.) The crackpipe command line syntax is:

crackpipe [host | -] port

When starting crackpipe, one side must listen, and the other must connect. The side which is listening will specify - for the first arguement, and the connecting side would specify the address of the other machine. How you do this basically depends on how connections can be made through the firewall. In this example, the remote end will listen, and the firewall victim will connect. We will also use port 9999 for this example, you can choose any port which you know will pass through the firewall.

local# crackpipe remote-host 9999

remote# crackpipe - 9999

Now, the local machine (address 192.168.1.2) should be able to telnet (or otherwise connect) to 192.168.1.1... If that works, you have a tunnel. (A note about UDP connections: Due to the nature of UDP, the machine which did NOT specify '-' to listen must make the first transmission through the tunnel to properly initialize the network. After this has happened, the network will be fully functional in both directions.)

Crackpipe has not been extensively tested, but it's worked in the few tests I've done. If you're POSITIVE that you've done everything else right (see the crackpipe docs) and it's not working, then mail me with a description of exactly what you've done, and the problem, and I'll try to fix it.

Other tunneling methods

I've never personally used any other method of "real" IP tunneling besides crackpipe, but, yes, they exist. Linux people can check out the IPIP and GRE stuff in newer kernels to look for other solutions. There's not much documentation on them, unfortunately, but I'd start with the help available when configuring the kernel and work my way out from there. If you successfully set up a tunnel using a method I haven't described here, mail me and tell me what you did, and I'll try to reproduce it and document it here.

Using your tunnel

Well, you've got a tunnel, what the hell good is it, anyway? Sure, you can connect directly to any port on some remote machine, and it can connect freely to you, but you probably wanted more than that... We'll now take a look at what tricks are available for getting connections through the tunnel, and making use of the hole you've dug through the proverbial prison wall.

Incoming connections

There's a good chance that you'd like to use this tunnel in order to allow some kind of incoming connection to the barricaded system. What you need to do now is to redirect connections made to a port on the remote host down to your machine. (If you're using slirp, these methods will not apply. slirp has the ability to redirect connections internally, and I've not tested it out. Consult the slirp documentation. I can definately see problems with using the slirp redirection, but I've not played with it enough to help you out at this stage.)

You'll need something which can redirect the ports. Since I've been tooting my own horn so far in this document, I'll talk about using redir to handle your port redirections... Consult the redir documentation for information on getting in compiled and running on the remote machine. Basically, your redir commands are going to look something like (this is an example to use port 2323 on the remote end to telnet to your system):

remote# redir 192.168.1.2 2323 23

This goes for most any service which you'd like to redirect.

Redir and FTP

FTP is a rather interesting bitch to attempt to run through some sort of redirection. Specifying --ftp as an option to redir when you redirect the port will cause "passive mode" (an option in most FTP clients, and the default FTP mode for most web browsers) to be correctly passed through the tunnel. This does, unfortunately, limit your FTP's a bit, since all the data must pass through your remote partner. (This next bit is all theoretical talk about FTP, you can quite probably just skip it unless you're curious)... However, there IS the possibility that you can only use the tunnel for the command part of the FTP session, and make the data connections directly. It is worth noting that these ideas will probably not work with most FTP clients and servers.

Passive FTP -- "Passive" FTP means that, whenever data is transferred, the server tells the client to connect to a certain port on the server machine, and then to transfer data through that connection. If your firewall permits incoming TCP connections on some ports, redirecting the ftp connection without the --ftp option to redir may allow data connections to skip the tunnel and be made directly (--ftp causes redir to also redirect the port for the passive transfer). This probably will not work because... 1) The server may not let the client connect. When the client connects to the "passive" data port on the server, the connection will come directly from the client's address, and not from the address used for the other side of the tunnel. The server will probably think this is wrong, and, for security reasons, refuse the connection. 2) The client may refuse to make the connection. The client may, as the true address of the server is not the address that it originally connected to, also for security reasons, refuse to make the connection, as someone could be trying to intercept the data.

Non-passive FTP: In "normal" or "port" ftp mode, the client tells the server what port to connect to. This probably will not work because... 1) The server will reject the new address. Because it is a security risk for the FTP server to agree to connect to anywhere and send some random data, it will probably refuse a PORT command which tells it to connect to an address other than the one which the client originally connected from. (a good example of why this is a bad idea is ftp bounce attacks). 2) The client may reject the server's connection. When the server connects to the client, the address it connects from will not be the one which the client originally connected to. To prevent someone from feeding the client false data, it may refuse the connection.

Basically, it's possible to make your data connection without the tunnel, but it's probably isn't going to happen in practice.

Redirection limitations

There are some limitations on redirection. Primarily, because of necessities related to the routing tables on the machine inside the firewall, all connections coming through the firewall MUST appear as if they are coming directly from the machine on the other end of the tunnel. This is the normal behavior of redir. While there are software solutions to the origin address issue which do work for normal networks, this is a special case. Say, for example, that the remote end of the tunnel was fixing the source address. Now, let's say a connection comes in across the tunnel bound for 192.168.1.2, and appearing to come from 111.222.111.222. Now, when the inside machine (192.168.1.2) wants to send a packet back, this packet would not be send through the tunnel, because 111.222.111.222, in the trapped system's routing tables, is reachable directly across the normal ethernet. Hence, it sends the packet back, with the origin address on the return packet incorrect, and so it will never be recieved. (remember, 111.222.111.222 thinks that it's connected to the address of the remote machine...)

Outgoing connections

There may be a situation in which you would like to make an outgoing connection which is forbidden by your firewall. This is a tricky issue, but it can be done in the proper circumstances. (this is much easier with slirp, as it will behave like a masquerading linux machine (discussed below))

The easiest way is to run a redirector on the remote host which will forward your connection. Let's say there is a MUD running on port 7777 on a machine at address 1.2.3.4. In this case, we'll assume your firewall blocks outgoing TCP connection on port 7777, so you can't link up directly. However, running redir on the remote host will fix this, by doing:

remote# redir 1.2.3.4 5555 7777

Now, you can telnet to 192.168.1.1 (through the tunnel) to port 5555, and redir will then connect you to port 7777 on 1.2.3.4 -- your mud. Not a very flexible method, but it works.

Alternately, if your either using slirp, or if the remote machine is a linux system which is set to masquerade connections coming through the tunnel, you can route connections for your destination through the tunnel. (There is plenty of material on the web discussing masquerading in linux, and we'll touch on this later in this paper). If the masquerading is configured properly, the blocked machine could add a host route for a given system which would then always use the tunnel. Let's use the example above, where you want to be able to connect to 1.2.3.4 through the tunnel. In linux, this route would be added by typing:

local# route add -host 1.2.3.4 gw 192.168.1.2

And, presto, all connections to 1.2.3.4 will now be made through the tunnel. It's probably quite unlikely that this is going to be a functionality often desired, but it can still be conveinent.

Always using the tunnel

It's always possible that in the case of EXTREMELY restrictive firewalls, you might desire simply to use the tunnel for everything, always. As above, this requires either a properly configured masquerading setup, or slirp. After you have established the tunnel (however you did this through your firewall from hell) you can route all other connections through it by default. In this case, we will assume that the remote end of the tunnel uses the IP address 2.3.4.5. You will still need to route packets directly to this host. (this example for linux routing tables only). We'll say that your real address, behind the firewall, is 3.4.5.6. This example also assumes that this is a crackpipe tunnel. "tap0" may be "ppp0", or whatever interface your tunnel is using. So your routing table might now look like:

local# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
3.0.0.0         *               255.0.0.0       U     0      0        0 eth0
127.0.0.0       *               255.0.0.0       U     0      0        0 lo
0.0.0.0         3.0.0.1         0.0.0.0         UG    0      0        0 eth0
192.168.1.0     *               255.255.255.0   U     0      0        0 tap0

You need to preserve your direct route to 2.3.4.5 for the tunnel to work, but route all other traffic through it. These commands would accompilsh that:

(add a host-specific route through the normal path)
local# route add -host 2.3.5.4 gw 3.0.0.1 
(erase the old default route)
local# route del 0.0.0.0
(add a new default through the tunnel)
local# route add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.1.1

After that, you would use the tunnel for all traffic. The routing table should now look something like:

local# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
3.0.0.0         *               255.0.0.0       U     0      0        0 eth0
127.0.0.0       *               255.0.0.0       U     0      0        0 lo
2.3.4.5         3.0.0.1         255.255.255.255 UG    0      0        0 eth0
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 tap0
192.168.1.0     *               255.255.255.0   U     0      0        0 tap0

And, bang, you're default routed through the tunnel. As a side benefit to this, you are now free of the restriction on the origin IP address of redirected connections. It's a small gain for having to access all of the internet through a tunnel, imho.

Other considerations

Which tunnel is right for me?

If you're fortunate enough to be linking 2 machines running recent linux 2.1 kernels, I would strongly advise using crackpipe, or, if you can get one going, one of the other tunnel variations possible with recent linux kernels. You are probably going to get better milage that way that faking a serial link.

If you're not linking 2 linux 2.1 machines, but you've still got a friend out there who has root on a machine he can use to help you, the modemu+ppp option should be compatible with your situation. I was able (with some effore) to pull this off on my NeXTstation running NeXTstep 3.3 connecting to a Linux 2.0 system.

If you don't have a friend out there to link up with, you still have the slirp option. Find an ISP which will sell you a shell account, and permit you to run slirp (or "tia" which is similar) from it. There are ISP's out there who are quite friendly about this (Eskimo North used to be very enthusiastic about slirp/tia in the past, I haven't dealt with them recently, but it appears they still provide suck services). Hopefully you can find an ISP which is fairly cheap, and which you've got a pretty quick link to.

Non-tunneling options

Aside from the tunneling options listed above, there are other methods which can be used to get your connections across a firewall. SOCKS proxies, provided that you have someplace to run one which you can reach through your firewall, can provide a great deal of functionality (including forwarding incoming connections) in many cases. SOCKS is also an option for those of you who wish to circumvent your firewally, but aren't running unix. I haven't explored this option in much depth, if I happen to, I may add a section on it. Also, you may be able to find an ISP who will sell you a true SLIP/PPP connection (you would get a real IP address) which you could connect to via modemu. This would probably eliminate the issue of redirection, but, again, I can see issues here involving the origin address problems discusses above. It could be made to work with some effort.

I'm also considering writing some sort of "poor-man's tunnel" which could be used to redirect ports to your machine from a remote host, without actually tunneling a real TCP connection. This would be rather limited functionality, but it could also quite probably be made to work correctly across most flavors of unix. I'll think about it.

Linux+IP Masquerade

This section remains to be written, but I'll spew down my thoughts in a form which may or may not be useful. One issue would be if your remote peer machine for your tunnel was located behind a masq'ing router (say, for example, you're using crackpipe with a 2.1 machine behind a 2.0 masq gateway) -- this would necessitate the use of lots more port redirection to get everything where it should belong. Another possibility would be if the firewall victim had multiple machines all connected to his firewalled ethernet using a masq'ing router... a tunnel could be linked up to the router, and, with the proper routing tables on both sides, fairly complicated redirection would be possible across the tunnel be setting up routes to link the private subnet on the inside with the remote machine directly across the tunnel... I should go into this stuff in more detail.

This is the end... my only friend, the end...

If you've read this, and you're still totally puzzled because I explained things poorly, or because there's something extremely bizarre about your situation mail me and let me know what I left out, so it can be added. Please, however, don't mail me if your not running unix, and want help, because I don't want to deal with other operating systems. Also, if something is simply not working for you, and you're TOTALLY POSITIVE that you've done everything correctly, send me a description of your exact situation, in as much detail as possible, exactly what you've tried, and, if you've got a tunnel you can't seem to use, a dump of your routing tables on both ends (route -n) and ifconfig output, and I'll try to revise this to cover in more detail whatever you were snagged on. Please don't send me messages because you can't find some package, or something won't compile (unless redir or crackpipe won't compile, as I do maintain those, and should fix them). Good luck, and don't let the man get you down.

Copyright information

This document is Copyright 1998 Sam Creasey, and is distributed under the terms of the GNU Public License, version 2 or later. A copy of this document can be found at ftp://prep.ai.mit.edu/gnu/COPYING.

Sam Creasey
Last modified: Sun Jan 17 18:19:26 EST 1999