http://www.linux-server-security.com/linux_servers_howtos/linux_redir_commands.html
# iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 443
There are times when, despite your
best efforts, you have little choice but to put a quick
workaround in place. Reconfiguring network-border firewalls or
moving services between machines is simply not an option because
the network’s topology is long established and definitely
shouldn’t be messed about with.
Picture the scene. You’ve lost an
inbound Mail Server due to some unusual issue with the
application which will probably take more than the few minutes
than you have spare to fix. In their wisdom the architects of
your Mail Server infrastructure didn’t separate the Web-based
interface from the backend daemons which listen out for the
incoming e-mail and both services reside on the server with a
failed IMAP Server (Internet Message Access Protocol) which
collects inbound mail for your many temperamental
users.
This leaves you in a tricky
position. Fundamentally you need both the services up and
available. Thankfully there’s a cold-swap IMAP Server with
up-to-date user configuration available but sadly you can’t move
the IP Address from the E-mail Web Interface over to that box
without breaking the interface’s connectivity with other
services.
To save the day you ultimately
rely on a smattering of lateral thinking. After all it’s only a
TCP port receiving the inbound e-mail and luckily for you the Web
Interface can refer to other servers so that users can access
their e-mails. Step forward the excellent “redir”
daemon.
This clever little daemon has the
ability to listen out for inbound traffic on a particular port on
a host and then forward that traffic onwards somewhere else. I
should warn you in advance that it might struggle with some forms
of encryption which require certificates being presented to it
but otherwise I’ve had some excellent results from the redir
utility. In this article we’ll look at how redirecting traffic
might be able to help you out of a tight spot and additionally
possible alternatives to the miniscule redir utility.
Installation
You probably won’t be entirely
surprised to read that it’s as easy as running this command on
Debian derivatives:
# apt-get install redir
On Red Hat derivatives you will
likely need to download it from here:
http://pkgs.repoforge.org/redir/
Then you simply use “rpm -i
” where “version” is the download which you
choose. For example you could do something like this:
# rpm -i redir-2.2.1-1.2.el6.rf.x86_64.rpm
Now that we have a working binary
let’s look at how the useful redir
utility works; thankfully it’s very straightforward indeed. Let’s
begin by considering the non-encrypted version of IMAP (simply
because I don’t want to promise too much with services encrypted
by SSL or TLS). Have a think about the inbound e-mail server
listening on TCP port 143 and what would be needed should you
wish to forward traffic from that port to another IP Address
first of all. This is how you could achieve that with the
excellent redir utility:
# redir --laddr=10.10.10.1
--lport=143 --caddr=10.10.10.2 --cport=143
In that example we can see our
broken IMAP Server (who has IP Address “10.10.10.1”) running on
local port 143 (set as “--lport=”) having traffic forwarded to
our backup IMAP Server (with IP Address “10.10.10.2”) to the same
TCP port number.
To run redir as a daemon in the
background you’re possibly safest to add an ampersand as we do in
this example where instead of forwarding traffic to a remote
server we simply adjust the port numbers on our local
box.
# redir --laddr=10.10.10.1
--lport=143 --laddr=10.10.10.1 --cport=1234 &
You might also explore the
“daemonize” command to assist. I should say that I have had mixed
results from this in the past however. If you want to experiment
then there’s a man page here:
http://linux.die.net/man/1/daemonize
You can also use the “screen”
command to open up a session and leave the command running in the
background. There’s a nicely written doc on the excellent
“screen” utility here from the slick Arch Linux:
https://wiki.archlinux.org/index.php/GNU_Screen
The above config example scenario
is an excellent way of catching visitors to a service whose
clients aren’t aware of a port number change too. Say for example
you have a clever daemon which can listen out for both encrypted
traffic (which would usually go to TCP port 993 on IMAP for the
sake of argument) and unencrypted traffic (usually TCP port 143).
You could redirect traffic destined for TCP port 143 to TCP port
993 for a short period of time while you tell your users to
update their software. That way you might be able to close
another port on your firewall and keep things simpler.
Another life-saving use of the
magical redir utility is when a DNS or IP Address changes take
place.
Consider that you have a busy
website listening on TCP port 80 and TCP port 443. All hell
breaks loose with your ISP and you’re told that you have ten days
to migrate to a new set of IP Addresses. Usually this wouldn’t be
too bad but the ISP in question has set your DNS TTL expiry time
(Time To Live) to a whopping seven days. This means that you need
to make the move quickly to provision for the cached DNS queries
which go past seven days and beyond. Thankfully the very slick
redir tool can come to the rescue.
Having bound a new IP Address to a
machine you simply point back at the old server IP Address using
redir on your HTTP and HTTPS ports.
Then you change your DNS to
reflect the new IP Address as soon as possible. The extra three
days of grace should be enough to catch the majority of
out-of-date DNS answers but even if it isn’t you could simply use
the superb redir in the opposite direction if you ISP let you run
something on the old IP Address. That way any stray DNS responses
which arrive at your old server are simply forwarded to your new
server. In theory (I’ve managed this in the past with a
government website) you should have zero downtime throughout and
if you drop any DNS queries to your new IP Address the percentage
will be so negligible your users probably won’t be
affected.
In case that you’re not aware the
DNS caching would only affect users who had visited in the seven
days prior to the change of IP Address. In other words any new
users to the website would simply have the new IP Address served
to them by DNS Servers, without any issue whatsoever.
Voting By Proxy
It would be remiss not to mention
that, of course IPtables also has a powerful grip on traffic
hitting your boxes too. We can deploy the mighty IPtables to
allow for a client to unwittingly push traffic via a conduit so
that a large network can filter which websites its users are
allowed to access for example.
There’s a slightly outdated
document on the excellent TLDP (The Linux Documentation Project)
website here:
http://tldp.org/HOWTO/TransparentProxy-6.html
Incidentally Transparent Proxies
are also known as Intercepting Proxies or Inline Proxies for
reasons that we’ve just covered, in case it causes
confusion.
With the super-natty redir tool we
can create a Transparent Proxy as so:
# redir --transproxy 10.10.10.10
80 4567
In this example we are
simply forwarding all traffic destined for TCP port 80 to TCP port 4567 so
that the Proxy Server can filter using its rules.
There’s also a potentially useful
option called “--connect” which will allow HTTP proxies with the
CONNECT functionality.
To use this option add the IP
Address and port of the proxy (using these options “--caddr” and
“--cport” respectively).
Shaping
I’ve expressed my reservations
about the usually-very-able redir utility handling encrypted
traffic because of certificates sometimes messing things up. The
same applies with some other two-way communication protocols or
those which open up another port such as sFTP (Secure File
Transfer Protocol) or SCP (Secure Copy Protocol).
However with some experimentation
if you put the redir utility to good use and you’re concerned
with how much bandwidth might be forwarded then the clever redir
utility can also help. Again you might have mixed
results.
You can alter how much bandwidth
is allowed through your redirection with this option
“--max_bandwidth”.
The manual in question does
warn that the algorithm employed is however a basic one and can’t
be expected to be entirely accurate all the time. Think of these
algorithms working by their considering a period of a few
seconds, the recorded throughput rate and the ceiling which
you’ve set it at. When it comes to throttling and shaping
bandwidth it’s not actually as easy to get a hundred percent
accurate as you might first think. Even shaping with the powerful
“tc” Linux tool, combined with a suitable “qdisc” for the job in
hand, is prone to errors sometimes, especially when working with
very low capacities of throughput, despite the fact it works on
an industrial scale.
My Network Is Down
The Traffic Control tool, “tc”,
which I’ve just mentioned is also capable of simulating somewhat
unusual network conditions. For example if you wanted to simulate
packets being delayed in transit (you might want to test this
with Pings) then you can use this “tc” command:
# tc qdisc add dev eth0 root netem
delay 250ms
Append another value to the end of
that command (such as “50ms”) and you then get a plus or minus
variation in the delay.
You can also simulate packet loss
with a command like this:
# tc qdisc change dev eth0 root
netem loss 10%
This should drop ten percent of
packets randomly all going well. If it doesn’t work for you then
the manual can be found here:
http://linux.die.net/man/8/tc and real life examples here:
http://www.admin-magazine.com/Archive/2012/10
I mention the fantastic “tc” at
this juncture because you might want to deploy similar settings
using the versatile redir utility. It won’t offer you the packet
loss functionality however it will add a random delay which might
be enough to make users look at their settings and then fix their
client-side config without removing all access to their
service.
One option which the redir tool supports is called
“--random_wait”.
Apparently redir will randomly multiply whatever setting you put
after that option by either zero, one or two milliseconds before
sending packets out. Note that this option can be used with
another (the “--bufsize” option). The manual explains that it
doesn’t deal directly with packets for its random delays but
instead defines them as so:
“A "packet" is a block of data
read in one time by redir. A "packet" size is always less than
the bufsize (see also --bufsize).”
By default the buffer size is
4,096 bytes; experiment as you wish if you want to alter the
throughput speeds experienced by your redirected
traffic.
IPtables Local
You can of course also use the
mighty IPtables (the kernel-based firewall, Netfilter) to alter
how your traffic is manipulated as it arrives at your server.
Let’s consider a local port redirection and then we can have a
quick a look receiving traffic to a port on one server and
dutifully forwarding it onwards to another IP Address.
Here are two examples for locally
redirecting.
# iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 25 -j
REDIRECT --to-port 2500
# iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 443
Here we use the “PREROUTING”
functionality on IPtables. The first command redirects incoming
traffic for SMTP to port 2500 and the second command intercepts
HTTP port traffic and forwards it onto the SSL/TLS port. The
syntax isn’t too hard to follow thankfully.
If you get lost then you can
easily look up any NAT (Network Address Translation) rules by
using this command:
# iptables -nvL -t nat
Should you feel your blood
pressure rising, get caught out and break something horribly then
just flush the problematic rules away like this:
# iptables -F; iptables -t nat -F
Adding these “-F” commands to a
Bash Alias is sometimes a good idea so you can recover
quickly.
IPtables Remote
What about palming off traffic to
another machine by using IPtables, along the same lines that we
saw with the redir utility?
Needless to say you should know
what you’re doing (and experiment on a test machine ideally
before trying these in production). To start us off we need to
enable forwarding on our local machine (“forwarding” essentially
equals “routing” to all intents and purposes, allowing traffic to
move between network interfaces on a local machine). We can
achieve that with this command:
# sysctl net.ipv4.ip_forward=1
If you remove the “sysctl” part
and add the remainder of that command (“net.ipv4.ip_forward=1”)
to the foot of the file “/etc/sysctl.conf” then that new config
will survive a reboot.
Next we simply declare our rule,
let’s use TCP port 80 again as our example:
# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.10.10.123:80
Finally we add this line to enable
masquerading:
# iptables -t nat -A POSTROUTING -j MASQUERADE
As you would expect the “-p”
switch allows us to change the protocol setting from “tcp” to
“udp” or “icmp”. IPtables apparently supports all of these
protocols should you have the need to expand that
list:
tcp, udp, udplite, icmp, esp,
ah, sctp or all
Berners-Lee
Of course there needn’t be a
reliance on tools that are, admittedly, relatively complex on
occasion when other alternatives will suffice.
Since we’ve looked at a common
redirect (which is required fairly frequently in my experience),
namely those of Web-based services and TCP ports 80 and 443, we
will briefly look at how redirects are handled internally using
the world’s most popular Web Server, Apache’s httpd.
Once tested a little these rules
are relatively intuitive. Here is an example of what a simple
redirect would look like. You can see below that we send all
inbound traffic to the HTTP port onwards to the HTTPS
port:
RewriteCond %{HTTPS}
!=on
RewriteRule ^(.*)$
https://www.chrisbinnie.tld/$1
In the above example if the
traffic which hits this rule isn’t already using HTTPS (encrypted
with SSL or TLS in other words) then the condition will assume it
is unencrypted HTTP traffic and continue onwards to the next rule
beneath it. The exclamation and equals sign, “!=”, meaning
not-equal-to.
Imagine that you might for example
want all traffic except that which is being sent by one IP
Address to a new location. Note the slightly obscure exclamation
mark before the IP Address “10.10.10.10” which acts as a negatory
condition again, if met. You could add a whole subnet here easily
too.
RewriteCond %{REMOTE_ADDR}
!10.10.10.10
RewriteRule .*
http://www.chrisbinnie.tld/newer_page.html [L]
This picks up all the external
traffic to your Virtual Host which Apache is dutifully listening
out for traffic to. If you’re curious the “[L]” flag at the end
of the second line means that “mod_rewrite”, the Apache module
responsible for performing the redirects, stops at that “last”
command. There are a mountain of flags which the super-slick
Apache can use to process its rules, for Apache 2.4 have a look
here:
http://httpd.apache.org/docs/2.4/rewrite/flags.html
So that “nginx” Web Server users
don’t feel left out let’s have a quick look at one of its
examples too. The mighty nginx has gained massive traction
amongst the Web Server market, if you’re interested in one of the
reasons this highly performant piece of software took such a
large bite out of Apache’s market share then look up the “c10k”
problem using your favourite online search device.
A simple nginx example of
forwarding TCP port 80 traffic to an encrypted connection would
look something like this:
if ($host = 'www.chrisbinnie.tld'
) {
rewrite ^/(.*)$ https://secure.chrisbinnie.tld/$1 permanent;
}
rewrite ^/(.*)$ https://secure.chrisbinnie.tld/$1 permanent;
}
That’s a welcome, short piece of
config hopefully you agree and it also includes a look at how
nginx can employ “if” statements, which is highly useful at
times, and more familiar to programmers than Apache config might
be.
Incidentally you need to place
that config inside your “server { }” tag. There are different
options to this config; I’ve seen other syntax used in nginx so
if it doesn’t work then you might need to look online so that
your version’s needs are met or other config isn’t breaking
things. This following example is how you might alter the above
to catch multiple Domain Names for instance:
server {
listen 80;
server_name chrisbinnie.tld www.chris.tld;
rewrite ^ $scheme://www.chrisbinnie.tld$request_uri permanent;
listen 80;
server_name chrisbinnie.tld www.chris.tld;
rewrite ^ $scheme://www.chrisbinnie.tld$request_uri permanent;
...
}
Here we are simply grabbing what
you might consider as malformed HTTP traffic (it’s not really
malformed, users have just typed the wrong Domain Names and URLs
into the Address Bar of their Browsers) and we are then
forwarding it onto “www.chrisbinnie.tld”
so that our precious brand remains intact.
No comments:
Post a Comment