Redirecting traffic to another machine with Linux's iptables

August 22, 2007

Let us suppose, as a not entirely hypothetical example, that you have added an A record for your subdomain name that points to one of your login servers, so that people can do 'ssh subdomain' and have it work. Let us further suppose that this login server is not your web server and you now want to make http://subdomain/ also do something useful, instead of giving connection refused errors.

One way to do this is to use iptables on the login server to redirect any connections to its port 80 off to the actual web server machine. Assuming that W is the IP address of your web server, what you need on your login server is:

  1. echo 1 >/proc/sys/net/ipv4/ip_forward

    Without IP forwarding enabled, the kernel will just drop our redirected packets instead of (re)routing them as we want.

  2. iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination W

    This sends the traffic off by rewriting the destination of attempts to connect to the login server's port 80 to be attempts to connect to the web server. Because it is in the PREROUTING table it does not affect connections made on the login server itself.

  3. iptables -t nat -A POSTROUTING -p tcp -d W --dport 80 -j MASQUERADE

    This rewrites the origin of connections to the web server's port 80 to appear to come from the login server. (Using -j SNAT --to-source L where L is the IP address of the login server is equivalent but longer, and the difference is unimportant for machines with permanently up interfaces.)

The last step is necessary because we need to make reply packets from the web server go through the login server so that it can reverse the transformation. Otherwise when a client connects to port 80 on the login server, the web server will see a connection from the client to it and send reply packets directly back to the client, where the client will ignore them because as far as it is concerned it connected to the login server, not the web server.

(Well, technically the client sends RSTs to the web server instead of completely ignoring the packets, assuming that no firewalls intervene.)

The drawback of dealing with the situation this way is that the web server will see (and log) all of this traffic as coming from the login server instead of from its real origin. This may or may not matter to you.

If the packets were already going through the login server on the way back (perhaps it is also your PPP server), you wouldn't need the third step but you'd want to be more specific in the second step, so that only packets to port 80 on the login server itself are affected. (Otherwise you would be creating a not so transparent proxy, where all websites are your web server.)

(To answer an obvious question: one reason to not just do this on your firewall is if you want even internal attempts to use the URL http://subdomain/ to do something useful.)

Written on 22 August 2007.
« The dilemma of website facing
The excessive cleverness of some people's reverse DNS »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Aug 22 23:22:37 2007
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.