Tuesday, January 26, 2010

Simple iptables port forwarding

Preface


I always enjoy learning new things, specially when it is about iptables. This beauty has been in my toolbox for so long, it's hard to even remember what life was like without it...

Today, I ran into some issues. I needed to capture all inbound traffic on a specific port and redirect it to another because of a change in server software.

Preparation


Before you even think about changing your firewall rules, there's 2 very important things to do first:

  1. Enable packet forwarding
  2. Load the iptables NAT module
You can either do those two things manually, but better is to write a script that does it, which you can put in your init.d or rc.d directory to load before loading iptables

Put whatever logic you need in that script, but always make sure that it successfully executes these commands:

# turn on support for packet forwarding

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

# load the iptables nat module

modprobe iptable_nat


I'm not going to show you what command lines to use with iptables to accomplish the port forwarding. I disagree with people always saying you shouldn't edit the iptable rules file directly.

The iptable rules


If you know a bit about generic iptables filtering, you probably already know that the layout commonly employed is this:

INPUT filtering
OUTPUT filtering

COMMIT


If you already have that kind of filtering in your rules, then that is fine, you needn't change any of those.

Instead, we are going to work on what happens before it reaches the INPUT, and OUTPUT filters, what happens during the PREROUTING stage; the stage that packets are in before they go to the INPUT/OUTPUT filters.

In our example, we are going to route all inbound packets on port 8080 to port 80, without the daemon listening on port 80 being any the wiser. Users can then use either port 8080 or port 80 and they will always go to the same service.

In your iptable rules file, above any existing rules or preface, place the following rules:

# Redirect traffic on port 8080 to port 80

*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A PREROUTING -d 222.222.222.2 -p tcp -m tcp --dport 8080 -j DNAT --to-destination :80

COMMIT



# `normal' filtering goes here


Remember to test if you rules pass a cursory test by running

iptables-restore -v --test < rules_file

Although you should know that iptables-restore mostly checks syntax so when you deploy your new rules for the first time, either make sure you are on a physical console, or have set up a cron job to run every two minutes and stop the iptables service

Notes


In the above example, the things to note most, are the parts colored in red.

To begin, there's the -d 222.222.222.2 part; it basically says, look for packets sent to the private address 222.222.222.2. You should adapt this to match the private ip address of your server.

Next, there's the --dport 8080 part; change this to the port you want to forward

Last, the --to-destination :80 means that all the packets that match the rule should be forwarded to port 80 on the same interface as they were received.

See the manual page for some more information:

http://www.netadmintools.com/html/8iptables.man.html#lbBI

Now, remember a bit back I said you didn't have to change your `normal' iptable rules? I might have mislead you a bit there...

If you haven't already got rules that will allow access to the port you are forwarding to, then you will need to add filter rules for those.

Here's a simple iptable rules file that will do the port forwarding from above, plus some `normal' traffic filtering to allow access to that port.



# REMEMBER TO ENABLE PACKET FORWARDING
# AND REMEMBER TO LOAD THE iptable_nat MODULE

# Reroute inbound traffic from port 8080 to port 80
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

-A PREROUTING -d 222.222.222.2 -p tcp -m tcp --dport 8080 -j DNAT --to-destination :80

COMMIT

# `Normal' traffic filter

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]


#** FILTER INBOUND TRAFFIC

# Accept packets from localhost

-A INPUT -i lo -j ACCEPT

# Accept data relating to an existing or related connection

-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow access to port 80

-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT

# Allow access to ssh (remove as needed)

-A INPUT -p tcp -m tcp --dport ssh -j ACCEPT

# Everything else is rubbish

-A INPUT -j DROP

COMMIT



That about sums it up. Let me know should you need some clarification.

No comments:

Post a Comment