Iptables NAT Tutorial
Results 1 to 8 of 8

Thread: Iptables NAT Tutorial

  1. #1
    Senior Member
    Join Date
    Mar 2002
    Posts
    425

    Post Iptables NAT Tutorial

    Here's the next installment of my iptables tutorials. There are actually 9 scripts that I use to build the firewall, one primary script that calls 8 subscripts. All nine are included in the zip file and the primary script is posted below for your perusal. As always, comments are appreciated. I've been through this thing several times already, but I'm sure as you read it, you'll find errors. It's always hard to proofread your own work. I hope you enjoy it, and I hope you learn something. Perhaps if I missed something, I can learn from you too.

    Code:
    #############################################################################
    #                                                                             #
    # File: build_firewall                                                        #
    #                                                                             #
    # Written by: str34m3r                                                        #
    #                                                                             #
    # Purpose: designed for a firewall/router with three legs: an internal LAN,   #
    #       an external LAN, and a demilitarized zone. Network diagram:           #
    #                                                                             #
    #    INT Box 1   -------|       EXT Internet        |------- DMZ Box 1        #
    #                       |             |             |                         #
    #    INT Box 2   ----|  |             |             |  |---- DMZ Box 2        #
    #                    |  |             |             |  |                      #
    #    INT Box ... ---Switch-----Router/Firewall-----Switch--- DMZ Box ...      #
    #                    |  |                           |  |                      #
    #    INT Box 253 ----|  |                           |  |---- DMZ Box 253      #
    #                       |                           |                         #
    #    INT Box 254 -------|                           |------- DMZ Box 254      #
    #                                                                             #
    # Additional files:                                                           #
    #       getIP                   Used to obtain IP info for an interface       #
    #       getNM                   Used to obtain netmask info for an interface  #
    #       build_ext_firewall      Used to firewall the external interface       #
    #       build_int_firewall      Used to firewall the internal interface       #
    #       build_dmz_firewall      Used to firewall the DMZ interface            #
    #       build_int_ext_firewall  Used between the internal and external LAN's  #
    #       build_int_dmz_firewall  Used between the internal and DMZ LAN's       #
    #       build_ext_dmz_firewall  Used between the external and DMZ LAN's       #
    #                                                                             #
    #############################################################################
    
    # For those that are newbies, the term DMZ will be used to refer to the
    # demilitarized zone, where you would put any box that offers a service to the
    # Since these boxes offer services, they're more likely to be hacked, so we put
    # them on their own network. INT is used to refer to your internal LAN where
    # the workstations will be. And of course EXT refers to the big bad internet
    # where all the blackhats and skiddies live.
    #
    # I'm not going to teach all the basics of iptables again in this tutorial. For
    # a beginners reference to iptables, check my iptables tutorial at:
    # http://www.antionline.com/showthread...hreadid=230338
    
    # Since this script uses several other scripts for modularity, you'll need to
    # tell it where the others are.
    export FW_DIR="/usr/local/firewall"
    
    # In preparation for the rules, we'll load all the modules we'll be needing.
    modprobe ip_tables
    modprobe iptable_nat
    modprobe ip_conntrack_ftp
    
    # Now, from the beginning... As we did before, we'll start by setting the
    # default policy for each chain to drop. If you've looked at the previous
    # tutorial, you may notice that there are three new chains I'm using this time
    # around: PREROUTING, POSTROUTING, and a new OUTPUT. You should also notice the
    # -t option. This option controls which table you're working with. There are
    # three tables available: filter, nat, and mangle. The filter table is the
    # default and is the table used for filtering most traffic. It's default tables
    # are INPUT, OUTPUT, and FORWARD. The nat table is only applied to new
    # connections and can be used to modify sources and/or destinations. Its
    # built-in tables are PREROUTING, POSTROUTING, and OUTPUT. The mangle table
    # allows some specialized packet manipulation, but it isn't applicable to our
    # firewall, so I'm going to ignore it.
    
    iptables -t filter -P INPUT DROP
    iptables -t filter -P OUTPUT DROP
    iptables -t filter -P FORWARD DROP
    iptables -t nat    -P PREROUTING DROP
    iptables -t nat    -P POSTROUTING DROP
    iptables -t nat    -P OUTPUT ACCEPT
    
    # The packet traversal in the machine looks something like this:
    #
    #    Entry         INPUT ----- Firewall ----- OUTPUT          Exit
    #      |             |                          |              |
    #      |             |                          |              |
    #      |             |                          |              |
    #  PREROUTING --- Decision --- FORWARD ----- Decision --- POSTROUTING
    #
    # The areas marked decision are where the kernel itself makes about where to
    # route the packet. These routing decisions are outside the realm of itables.
    # The nat PREROUTING table is where you can alter packets as they come in.
    # The nat POSTROUTING table is where you can alter packets before they go out.
    # The nat OUTPUT table is actually between the Firewall and the normal OUTPUT
    # table, and this is where you could alter packets before routing decisons are
    # made, but I've never had much of a use for it. Since I don't use its
    # alteration features, and filter OUTPUT is there, I set it to accept and do
    # all of my filtering in filter OUTPUT. If any of you use nat OUTPUT, let me
    # know how, because I always enjoy learning.
    
    # Next we flush the old rules and clean up the old tables.
    
    iptables -t filter -F
    iptables -t filter -X
    iptables -t nat    -F
    iptables -t nat    -X
    
    # Before adding rules to our defaults, I'll set up two chains that I use
    # extensively throughout the rules. The LOGDROP taget allows me to easily
    # log rogue packets before dropping them. By creating a target like this, I
    # avoid having to write two rules for each packet I want to log and drop later
    # on. And since the LOGDROP targets are in two separate tables, the names don't
    # conflict.
    
    iptables -t filter -N LOGDROP
    iptables -t filter -A LOGDROP -j LOG --log-level 7
    iptables -t filter -A LOGDROP -j DROP
    
    iptables -t nat    -N LOGDROP
    iptables -t nat    -A LOGDROP -j LOG --log-level 7
    iptables -t nat    -A LOGDROP -j DROP
    
    # I allow everything on the loopback interface to pass through unharmed. If you
    # are truly anal, you'll want to filter this too, but even I'm not that anal.
    
    iptables -t nat    -A PREROUTING  -j ACCEPT -i lo
    iptables -t filter -A INPUT       -j ACCEPT -i lo
    iptables -t filter -A OUTPUT      -j ACCEPT -o lo
    iptables -t nat    -A POSTROUTING -j ACCEPT -o lo
    
    # Since you probably won't (shouldn't) be running Xwindows on your firewall box
    # you can probably afford to be a little pickier with your loopback this time,
    # so once again, I've included picky settings too. :)
    
    
    # iptables -t nat    -A PREROUTING  -j ACCEPT -i lo -s 127.0.0.1 -d 127.0.0.1
    # iptables -t filter -A INPUT       -j ACCEPT -i lo -s 127.0.0.1 -d 127.0.0.1
    # iptables -t filter -A OUTPUT      -j ACCEPT -o lo -s 127.0.0.1 -d 127.0.0.1
    # iptables -t nat    -A POSTROUTING -j ACCEPT -o lo -s 127.0.0.1 -d 127.0.0.1
    
    # Now we need to define our interfaces.
    export EXT_IF="eth0"
    export INT_IF="eth1"
    export DMZ_IF="eth2"
    
    # Since most of the rules in this service are designed for use with entire
    # subnets, it's important that we get them right. For each interface, we need
    # the IP and the netmask for that interface. I've included two scripts (getIP
    # and getNM) to do the work for you so that this script will still work
    # with DHCP. 'getIP' and 'getNM' first attempt to gather the necessary
    # information from ifconfig because its information should be the most current.
    # If, however, the information cannot be obtained from ifconfig (possibly
    # because the interface isn't up yet), the scripts parse the interface's
    # configuration file to ascertain the IP address and the netmask. Each of these
    # scripts looks in '/etc/sysconfig/network-scripts'. If this is not where your
    # netowrk config files are, then you can edit the first line in getIP and getNM
    # to point to the correct config files.
    
    # Get IP and netmask for the internal interface and build the network variable
    
    export INT_IP=`$FW_DIR/getIP $INT_IF`
    if [ ! "INT_IP" ]; then exit 1; fi
    export INT_NM=`$FW_DIR/getNM $INT_IF`
    if [ ! "INT_NM" ]; then exit 1; fi
    export INT_NET="$INT_IP/$INT_NM"
    echo "Internal net:$INT_NET"
    
    # Get IP and netmask for the internal interface and build the network variable
    
    export DMZ_IP=`$FW_DIR/getIP $DMZ_IF`
    if [ ! "DMZ_IP" ]; then exit 1; fi
    export DMZ_NM=`$FW_DIR/getNM $DMZ_IF`
    if [ ! "DMZ_NM" ]; then exit 1; fi
    export DMZ_NET="$DMZ_IP/$DMZ_NM"
    echo "Demilitarized zone:$DMZ_NET"
    
    # Get the IP for the external interface. Since this will be the default route,
    # there is no point in worrying about the netmask or network variables.
    
    export EXT_IP=`$FW_DIR/getIP $EXT_IF`
    if [ ! "EXT_IP" ]; then exit 1; fi
    export EXT_NET="$EXT_IP/0.0.0.0"
    echo "External net:$EXT_NET"
    
    # Validate that the packets coming in the internal interface have source IP's
    # from the internal IP block. Check the same things on the DMZ packets. If the
    # packets aren't what we're expecting, drop them.
    
    iptables -t nat -A PREROUTING   -j ACCEPT  -i $INT_IF -s $INT_NET
    iptables -t nat -A PREROUTING   -j LOGDROP -i $INT_IF
    iptables -t nat -A PREROUTING   -j ACCEPT  -i $DMZ_IF -s $DMZ_NET
    iptables -t nat -A PREROUTING   -j LOGDROP -i $DMZ_IF
    
    # Validate that the packets going out the internal interface have destination
    # IP's in the internal IP block. Check the same things on the DMZ packets. If
    # the packets aren't what we expect, drop them.
    
    iptables -t nat -A POSTROUTING  -j ACCEPT  -o $INT_IF -d $INT_NET
    iptables -t nat -A POSTROUTING  -j LOGDROP -o $INT_IF
    iptables -t nat -A POSTROUTING  -j ACCEPT  -o $DMZ_IF -d $DMZ_NET
    iptables -t nat -A POSTROUTING  -j LOGDROP -o $DMZ_IF
    
    # At this point, everything we're dealing with should deal with the external
    # interface. For external packets, the legal IP range isn't simple. The first
    # check we need to make is for local IP's, internal IP's, and DMZ IP's. These
    # IP's should never appear on our external interface, so we'll drop any we see.
    
    iptables -t nat -A PREROUTING   -j LOGDROP -i $EXT_IF -s 127.0.0.1/8
    iptables -t nat -A PREROUTING   -j LOGDROP -i $EXT_IF -s $INT_NET
    iptables -t nat -A PREROUTING   -j LOGDROP -i $EXT_IF -s $DMZ_NET
    
    iptables -t nat -A POSTROUTING  -j LOGDROP -o $EXT_IF -d 127.0.0.1/8
    iptables -t nat -A POSTROUTING  -j LOGDROP -o $EXT_IF -d $INT_NET
    iptables -t nat -A POSTROUTING  -j LOGDROP -o $EXT_IF -d $DMZ_NET
    
    # We will assume at this point that all incoming packets are from a legal
    # external IP and all outgoing packets are to an external IP. This isn't
    # technically true due to reserved and unassigned IP blocks, but I rarely see
    # any traffic from these IP's, so I'm not going to bother. If you're anal, you
    # can check IANA and add the rules to drop these IP blocks yourself. It'll be a
    # good learning experience. For now, we're going to move on to the fun stuff:
    # Network Address Translation. For the purposes of this tutorial, we'll assume
    # that I have a mail server on my DMZ at 192.168.2.2 and a web server at
    # 192.168.2.3. Since the world only knows my firewall's external IP address,
    # they simply send the packets to the firewall and it reroutes the packets to
    # their correct destinations. The mail server has port 25 open to the world and
    # also has port 22 open for ssh access. The web server has port 80 open of
    # course and is also running an ssh server on port 22. Since we can't redirect
    # the firewall's port 22 to both machines, we'll have to do some
    # port-translation for at least one of the hosts in addition to doing IP
    # translation. And since we're learning, we may as well do port redirection for
    # both hosts.
    
    export MAIL_IP="192.168.2.2"
    export WEB_IP="192.168.2.3"
    
    # We'll start by redirecting all packets destined for port 25 on the external
    # interface to the mail server in the DMZ. We'll also redirect port 2599 to
    # port 22 on the mail server. It's important to note that these packets, which
    # would have originally passed to the input chain for filtering, will now be
    # passed to the forward chain instead.
    
    iptables -t nat    -A PREROUTING  -j DNAT   --to-destination $MAIL_IP \
                    -p tcp --dport 25   -d $EXT_IP -i $EXT_IF
    
    iptables -t nat    -A PREROUTING  -j DNAT   -p tcp --dport 2599 \
                    --to-destination $MAIL_IP:22 -d $EXT_IP -i $EXT_IF
    
    # Next we'll redirect all packets destined for port 80 on the external
    # interface to the DMZ's web server. We'll also redirect port 2601 to port 22
    # on the web server.
    
    iptables -t nat    -A PREROUTING  -j DNAT   --to-destination $WEB_IP \
                    -p tcp --dport 80   -d $EXT_IP -i $EXT_IF
    
    iptables -t nat    -A PREROUTING  -j DNAT   -p tcp --dport 2601 \
                    --to-destination $WEB_IP:22 -d $EXT_IP -i $EXT_IF
    
    # NOTE: Using high port numbers will make it a little harder for the script
    # kiddies to happen upon your SSH servers, but if anyone is really looking,
    # they will find them, so never base your entire defense on an obscure port
    # number. Remember: Defense in depth is crucial for network security.
    
    # The last thing we'll do with prerouting is to accept packets destined for
    # the firewall.
    
    iptables -t nat -A PREROUTING  -j ACCEPT -i $EXT_IF -d $EXT_IP
    
    # We still have one trick up our sleeves for postrouting: masquerading.
    # When internal or DMZ boxes connect to boxes out on the internet, we have
    # to change the source IP and source port so that our internal IP's don't
    # show up on the internet. This process is known as masquerading and is
    # handled natively by iptables. So we'll masquerade all packets coming from
    # the internal subnet and the DMZ subnet that are going out the external
    # interface.
    
    iptables -t nat -A POSTROUTING -j MASQUERADE -o $EXT_IF -s $INT_NET
    iptables -t nat -A POSTROUTING -j MASQUERADE -o $EXT_IF -s $DMZ_NET
    
    # The only thing left is postrouting for outbound packets.
    
    iptables -t nat -A POSTROUTING -j ACCEPT -o $EXT_IF -s $EXT_IP
    
    # Build the input and output filters for the internal interface.
    
    $FW_DIR/build_int_firewall
    
    
    # Build the input and output filters for the internal interface.
    
    $FW_DIR/build_dmz_firewall
    
    # Build the input and output filters for the internal interface.
    
    $FW_DIR/build_ext_firewall
    
    # Build the forward filters between the internal and DMZ interfaces.
    
    $FW_DIR/build_int_dmz_firewall
    
    # Build the forward filters between the internal and external interfaces.
    
    $FW_DIR/build_int_ext_firewall
    
    # Build the forward filters between the external and DMZ interfaces.
    
    $FW_DIR/build_dmz_ext_firewall
    
    # These rules should only trigger when the system doesn't know what to do with
    # a packet. I'll send these to LOGDROP since these packets are generally a
    # result of something misconfigured on my system and they will help me with
    # troubleshooting.
    
    iptables -t nat    -A PREROUTING  -j LOGDROP
    iptables -t filter -A INPUT       -j LOGDROP
    iptables -t filter -A FORWARD     -j LOGDROP
    iptables -t filter -A OUTPUT      -j LOGDROP
    iptables -t nat    -A POSTROUTING -j LOGDROP

  2. #2
    Senior Member
    Join Date
    Nov 2001
    Posts
    1,255
    Again, another excellent post. You covered pretty much everything.

    Keep in mind that the MASQUERADE target is being deprecated (at least, IIRC), so you may wish to swap MASQUERADE for SNAT. Appart from that, they are virtually the same.

    You might wish to contact the existing maintainers of the current iptables NAT HOWTO and offer this version up to them. It's very well planned, and looks like you put a tonne of effort into it.

    EDIT: Streamer, you might wish to hang out in IRC. You have quite a bit of apparent firewall expertise, and there are quite a few questions floating around about iptables, and hey, some of us aren't always around.

    Just grab an IRC client and head on over to services.antionline.com. That is, if you haven't already.
    Chris Shepherd
    The Nelson-Shepherd cutoff: The point at which you realise someone is an idiot while trying to help them.
    \"Well as far as the spelling, I speak fluently both your native languages. Do you even can try spell mine ?\" -- Failed Insult
    Is your whole family retarded, or did they just catch it from you?

  3. #3
    Senior Member
    Join Date
    Mar 2002
    Posts
    425
    The reason I used the masquerade target in the past was because iptables did all of the translations for you, and was significantly easier if you had a dynamic IP address. I just haven't made the leap to SNAT, but if masquerade is being deprecated, then I guess I will have to jump then, eh? As far as IRC goes, I generaly show up in the evenings (I'm on EDT) and just listen to people talk. Preacherman has caught me there a few times with iptables questions and I'm always glad to help. I'll try to check out IRC a little more often, but I do have a wife and I don't want to neglect her to spend time in IRC. Oh, and thanks for the comments.

  4. #4
    Senior Member
    Join Date
    Jan 2002
    Posts
    227
    Really good post. This kind of posts makes AO what it should be
    http://promote.opera.com/small/opera94x15.gif

    [gloworange]Sun7dots[/gloworange]

  5. #5
    Senior Member
    Join Date
    Nov 2001
    Posts
    1,255
    Originally posted here by str34m3r
    The reason I used the masquerade target in the past was because iptables did all of the translations for you, and was significantly easier if you had a dynamic IP address. I just haven't made the leap to SNAT, but if masquerade is being deprecated, then I guess I will have to jump then, eh? As far as IRC goes, I generaly show up in the evenings (I'm on EDT) and just listen to people talk. Preacherman has caught me there a few times with iptables questions and I'm always glad to help. I'll try to check out IRC a little more often, but I do have a wife and I don't want to neglect her to spend time in IRC. Oh, and thanks for the comments.
    Actually, in iptables, SNAT is naerly identical in usage and processing to MASQUERADE. The translation is done in a similar manner, but gives you more control of your choice of output IP and interface. Also, I *THINK* it's being deprecated, but I'm not 100% sure on that.

    An example:
    Where one might have a rule that reads:
    iptables -t nat -A POSTROUTING -j MASQUERADE -o $EXT_IF -s $INT_NET
    you could replace it with:
    iptables -t nat -A POSTROUTING -o $EXT_IF -s $INT_NET -j SNAT --to $EXTIP
    and it would still remain functional.
    Chris Shepherd
    The Nelson-Shepherd cutoff: The point at which you realise someone is an idiot while trying to help them.
    \"Well as far as the spelling, I speak fluently both your native languages. Do you even can try spell mine ?\" -- Failed Insult
    Is your whole family retarded, or did they just catch it from you?

  6. #6
    Senior Member
    Join Date
    Mar 2002
    Posts
    425
    Chsh > You are correct about how SNAT works, and now that I know how to do things like dynamically determine my network variables, I suppose I should use that target more often. My use of the masquerade is a historical remnant of my original cluelessness when I was learning iptables. When I first started working with iptables, I didn't know how to dynamically determine what my IP address was, but I learned that if I used the masquerade target, I really don't need to know. So I just used masquerade because it was easier. I just never bothered to switch my rules to SNAT because MASQUERADE still works (for the time being).

    Souleman asked me some questions in a PM, and since the answers may help others, I'd like to answer the questions here.

    You didn't state what the file name/location was in either one of your tutorials. For someone who wants to write their own rules, this may be necessary....
    Well, the reason I didn't specify a specific filename is because it really doesn't matter where you put these scripts. There's a variable inside the primary script where you need to tell it where the rest of the scripts are located, but that's about it. You can run these scripts from wherever directory you choose to put them in and they will still work. Now if you wanted to turn these into a service that is started automatically it would take a bit of work, but if there's some interest, then I think I could write it up.

    Also, are you dealing with filter, nat, or mangle. I assume the first was filter, the second was nat, and you will be writing a third on mangle, but just thought that some noob might like clarification....
    The first iptables tutorial did deal with the filter table exclusively, and this table incorporated both the nat table and the filter table. I really didn't have any plans to write a tutorial on mangle simply because I don't have much use for it in my environment, but I do know a bit about it and I can write something up about that too if anyone is interested. It's just sort of a niche of iptables that isn't very useful to the majority of people.

  7. #7
    Junior Member
    Join Date
    Jun 2008
    Posts
    1
    Hello
    Can u put a link to the zip file
    thanks

  8. #8
    Super Moderator: GMT Zone nihil's Avatar
    Join Date
    Jul 2003
    Location
    United Kingdom: Bridlington
    Posts
    17,178
    Sorry, that tutorial is 6 years old and the link is gone.
    If you cannot do someone any good: don't do them any harm....
    As long as you did this to one of these, the least of my little ones............you did it unto Me.
    What profiteth a man if he gains the entire World at the expense of his immortal soul?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

 Security News

     Patches

       Security Trends

         How-To

           Buying Guides