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
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.
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"...
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.
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.
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.
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.
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.
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.
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 .
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.
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.
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.
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):
This goes for most any service which you'd like to redirect.
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.
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...)
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:
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:
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.
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:
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:
After that, you would use the tunnel for all traffic. The
routing table should now look something like:
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.
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.
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.
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.
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.
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.
Incoming connections
remote# redir 192.168.1.2 2323 23
Redir and FTP
Redirection limitations
Outgoing connections
remote# redir 1.2.3.4 5555 7777
local# route add -host 1.2.3.4 gw 192.168.1.2
Always using the tunnel
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
(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
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
Other considerations
Which tunnel is right for me?
Non-tunneling options
Linux+IP Masquerade
This is the end... my only friend, the end...
Copyright information