cde8 Iptables - Telecomix Crypto Munitions Bureau

Iptables

From Telecomix Crypto Munitions Bureau

Jump to: navigation, search

iptables is the default firewall for linux since some years back. If you do not like iptables, consider switching to OpenBSDs pf. It is better at being paranoid :)

I translated this tutorial from swedish to english just for your pleasure. It took quite some time. If you want to, please do copy it. You do not have to give any form of attribution or anything, it is released into public domain. If you feel like contributing, you are welcome! Just edit the page :D

This tutorial does not go into the any deepths (at all) about the various iptables commands. Instead of just repeating what the man-page says, it describes the basic stuff that gets you going. To properly understand how iptables works, you will need to have a look in the man-page.

Contents

[edit] TODO

This tutorial needs to be updated. If you have any knowledge with the following, you could help :D

  1. More info on how to avoid giving away information about what type of computers are running behind the firewalls/routers. Scrubbing packets like in OpenBSD. Helps to avoid losing anonymity in a darknet.
  2. ...more information needs to be gathered in general. Is this tutorial good enough?
  3. more info on ip and other iptables-related programs/commands

[edit] Tables

All packets that enters or leaves your computer goes through a lot of tables, where decisions about what to do with the packets are made. There are five tables: PREROUTING, INPUT, OUTPUT, FORWARD and POSTROUTING. Each table contains chains that in turn contains rules. A rule could for example be to drop the packet, or to rewrite its content. Rewriting the content of a packet is rather good if you want to handle NAT.

Tables contains chains, that contains rules. When a packet enters a table, each rule in each chain inside the table is executed. Inside every one of the tables there are a few default chains, that always exists. For example: When a packet enters the PREROUTING chain, the rules in the "raw" chain is executed first, then the rules in the "mangle" table, then the rules in "nat" chain. When a packet has finished going through a table, the kernel decides what to do next. It might be sent to yet another table, sent to a program that is running on the computer, or fed to an virtual or physical network interface.

You can manufacture your own chains and write rules that sends packets to different chains. Only your imagination will stop you :)

[edit] Think of it like this

  • Tables are programs that contains functions. There exists only five tables in your computer, and you can not change this (without editing the kernel source code).
  • Chains are the functions, that your tables consists of. You can create your own functions and populate them with rules if you want to. Actually, you will need to create your own chains sometimes, if you want to do anything slightly else than the default stuff. There are a few chains that always exists, but they are empty by default.
  • Rules are the building blocks, if-cases, stuff that changes the packets content, stuff that drops packets and so on. You can call and GOTO subroutines (chains) with the rules.

If you add your own chains that contains your own rules, you will need to call or GOTO them from the existing default chains. Your own chains are not part of any of the tables, they exists outside of them. Think of your own chains like libraries that needs to be linked. More information about this later.

[edit] A nice, handy ASCII graph of all tables and their default chains


         { network }   <---------------------- packets enter your computer via a
              |                                physical or virtual interface
              | (PREROUTING)                   *nom nom nom nom*
             raw
              |
            mangle
              |
             nat
              |
 { kernel decides which table should be used }   <---- if the packet has destination equals to any
              /        \                               of the computers own IP-addresses, it will
  (FORWARD)  /          \  (INPUT)                     be sent to the INPUT table. Otherwise it is
        mangle         mangle                          sent to the FORWARD table, assuming that
          |              |                             net.ipv4.conf.*.forwarding = 1, otherwise
        filter         filter                          it should be dropped.
          |              |
          |         { program }   <----------- Programs that run on the computer AND is listening on
          |              |                     the destination protocol AND port of arriving packets
          |             raw  (OUTPUT)          from the INPUT chain will be fed with them. Programs
          |              |                     running on your computer poops their packets out at
          |            mangle                  the OUTPUT table.
          |              |
          |             nat                    
          |              |                     
          |            filter                    legend:
           \             /                          (X) -> X is a table
            \           /                           {X} -> X is something obvious
  { the packet is put in POSTROUTING }               X  -> X is a chain
                |
              mangle (POSTROUTING)
                |
               nat                              The packet is ejected by some network interface. It
                |                               could mean that the packet is put on a physical network
           { network }   <--------------------- or that it is sent by a virtual network interface to a
                                                real network interface (in which case it could *again*
                                                enter the PREROUTING table.)
:)
By creating your own chains and populating the existing ones with rules that calls them, you can change how packets flow through you machine. For example, you could make special rules for packets that come from a certain network and keep them in a special chain.

[edit] How to create your own rules

We will only have a look at the most basic stuff here. When you have understood this, you can have a look at the man-page, to learn more. There are lots and lots of different words you can use to define your rules. Normally, you append rules to the chains, with -A. Example:

iptables -A INPUT (exchange this parenthesis with your rule)

By default iptables will put the rule in the correct chain automagically. If you want to be specific of which chain you want your rule to enter, you can specify it with -t. In the case of adding rules to the nat chain inside the PREROUTING table, you could type something like

iptables -A PREROUTING -t nat (Your SNAT rule here)

Remember that your rules are appended to the chains, that is: If you append a rule, it will be the last one in the chain. Do not forget to flush (-F) the chain before you start adding stuff to it. If there are rules in the chain and you add stuff to the bottom of it, your rules might not be executed at all. I have got stuck on debugging that several times.

[edit] Flushing chains

You can flush chains by using -F. Flushing a chain removes all rules in it.

iptables -F INPUT

This flushes the INPUT table. Or does it? Unfortunatly, they never mention this in the man page, but this actually only flushes the default chain in the INPUT table. All other chains are left untouched. You will need to specify the chains you want to flush explicitly.

iptables -F PREROUTING -t raw

Unless you type this, the raw chain will still keep its content after the PREROUTING table has been flushed. The reason is that the raw chain is not the default chain. I have forgotten about this a few times. It will not tell you what is wrong, it will just silently stop working.

If you add stuff to non-default chains, make sure that your script also contains the flushing of the same non-default chains in the beginning. Otherwise, it will fuck up.

[edit] Jump to chains

With -j you can create rules that calls your very own special chain, where the packet can be manipulated or examined. Examples:

iptables -A INPUT -p udp -j hello                  Jump to the chain named "hello"
iptables -A INPUT -p tcp -dport 22 -j DROP         Drops ("jump to DROP") all packets going to the TCP protocol, port 22 (ssh)
iptables -A INPUT -p icmp -j ACCEPT                Sends the packet to the next table. ("Jump to ACCEPT")

Jumping to ACCEPT does not mean that you will do not drop the packet at some later point. Jumping to ACCEPT in the PREROUTING table instead means that the packet is sent to the INPUT or FORWARD table (depending on its destination address.)

Ok, so we have seen that it is possible to jump to our own chains, and that some predefined chains such as DROP and ACCEPT also exists. I do not think it is possible to redefine DROP and ACCEPT by flushing them and then filling them with new rules, but I am not sure.

[edit] How to create your own chains

Create a new chain with the name cloudmachine

iptables -N cloudmachine

Example of how to create and populate a chain that drops packets with a destination equals to any of the RFC1918 addresses.

iptables -N test_src
iptables -A test_src -s 10.0.0.0/8 -j DROP
iptables -A test_src -s 172.16.0.0/12 -j DROP
iptables -A test_src -s 192.168.0.0/16 -j DROP

At some other chains, in some of the tables, you need to call your chain to check that they have valid destination addresses:

iptables -A FORWARD -t filter -j test_src
iptables -A INPUT -t filter -j test_src

This will append rules to the filter chains in the FORWARD and INPUT tables that calls our chain that checks for invalid addresses.

[edit] How to fight against firewalls

A simple tool to use is nmap. (apt-get install nmap)

Assume that the computer you want to test is 192.168.0.4.

nmap 192.168.0.4                 connect()-scan, performs lots of ordinary TCP handshakes with the good old chap. Nothing but the most
                                   obvious information can be gathered.

nmap -sS 192.168.0.4             SYN-scan, performs the first part of the TCP handshake, but does not finish it.
                                   It was used back in the old days when computers only were aware of completed handshakes. It could also 
                                   be used to flood a computers memory with new sessions. This no longer applies.
                                   The target answers with a SYN+ACK if the port is open, otherwise it does something else. For example,
                                   it could reply with a RST or nothing at all if the port is closed.

nmap -sA 192.168.0.4             ACK-scan, can be used to decide if the firewall guarding the machine is aware of states or not. Cheap,
                                   crappy or misconfigured routers are not aware of states. The default behaviour is to reply with a RST
                                   if an ACK packet is arriving. (ACK packets are the last part of a TCP handshake, which is rather
                                   strange to receive on its own.) If a computer answers with RST packets from an ACK scan, we know that
                                   the port is unguarded, or guarded by a flawed firewall. It also means that the potentially flawed
                                   firewall is letting through traffic at that port, which means that we can begin to guess what type of
                                   rules the firewall has been configured with. Which services runs on the computers, even though we can
                                   not access them (yet)?
                                   DANGER: It is easy to by accident configure iptables to allow for an ACK scan. "-m --state NEW" (a rule
                                   that matches states equals to "NEW") does in fact say that packets belong to the state NEW even if they
                                   have not been preceded by SYN-packets. You will specifically need to tell iptables to NOT accept NEW
                                   packets that do not have the SYN-flag set to avoid letting ACK-scans through. See the examples below
                                   for how to do this.

nmap -sS --scanflags PSHSYN 192.168.0.4
                                 Glue your own packets together with whatever flags you wish. You can check if the target replies to wierd
                                   formations such as SYN+RST and how it handles them. 
                                   Possible flags are: CWR (Congestion Window Reduced), ECN (echo), URG (Urgent), ACK (Acknowledge),
                                   PSH (Push), RST (Reset), SYN (Synchronize), FIN (Finish), ECE (ECE-Echo), NS (Nouce Sum),
                                   ECT (ECN-Capapable Transport), CE (Congestion Experienced). Write them together without any spaces.
                                   Example: --scanflags ECNURGACKPSHRSTSYNFIN
                                   (CWR, ECN, ECE, ECT and CE are used for congestion avoidance, that is to tell the TCP protocol about
                                   how much bandwidth is available at any given moment. Most operating systems ignore them, it seems.)

                                   People does not really agree with me here, but I really think that it is BAD if non-standard packets
                                   are allowed to pass the firewall. If you wish to scrub away all wierd stuff from your connection, I
                                   would recommend using OpenBSDs pf. Linux iptables is happy with many of the combinations of the flags
                                   that I would call wierd.

Heretic note: It is probably more important that your programs is not exploitable, than that your firewall is PERFECT. However, if you are building a firewall to protect yourself at a darknet, you can not really afford to give away any information about yourself. If you can, please consider blocking and dropping everything that you have not carefully thought through in advance. The information your firewall gives away can seriously harm your anonymity in a darknet.

[edit] How to fight against nmap

I. Do not allow access to any service that you do not absolutely positively have to: If you only need to offer that service occassionaly to a few trusted individuals then consider installing FWKNOP (Firewall Knock Operator) or one of the other port knocking solutions to keep the service hidden behind the firewall until the trusted user requests it. And then it's only accessible by the user that requested it for a limited time.

For the services you do have to leave open, when you complete your firewall script run fwsnort to convert Snort rules to iptables rules for any open service. This can mean that even if they can use nmap to see that you offer a service that when they try to exploit it, you may be able to block them (assuming a Snort rule has been written for the exploit).

II. Invalid State: The majority of nmap's TCP scans are seen as being in an invalid state by iptables and can be blocked by a few simple rules near the beginning of your firewall script.

iptables -A INPUT -m state --state INVALID -p TCP -j LOG --log-prefix "Invalid TCP Reject: "
iptables -A INPUT -m state --state INVALID -p TCP -j REJECT --reject-with tcp-reset

III. ICMP Flooding: (near the beginning of your firewall script)

 
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -m limit --limit 1/s -j LOG --log-prefix "ICMP Flood Drop: "
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP

This means that your system will only accept a single ping request per second so people will be able to confirm that they can communicate with it but will not be able to ping flood it.

IV. TCP SYN Flooding: (near the beginning of your firewall script)

iptables -N synfld

# For a server, these limits may be preferable.
#iptables -A synfld -p TCP -m limit --limit 8/s --limit-burst 16 -j RETURN
#iptables -A synfld -p TCP -m limit --limit 30/s --limit-burst 90 -j RETURN

# For a workstation with limited publicly accessible services, this limit may
# be more desirable.
iptables -A synfld -p TCP -m limit --limit 1/s --limit-burst 1 -j RETURN

iptables -A synfld -p TCP -j LOG --log-prefix "SYN Flood Reject: "
iptables -A synfld -p TCP -j REJECT --reject-with tcp-reset

iptables -A INPUT -p TCP --syn -j synfld

It is difficult for iptables to differentiate between valid SYN packets that start a new session and SYN Floods. The 'invalid' checks above will not prevent them. What we can do is monitor the frequency that they attempt to connect. To do so, we use the 'synfld' chain to limit the number of TCP sessions allowed to connect within any given second to something reasonable. If you're lucky, anyone using nmap to scan you system will have scanned enough closed ports that by the time they reach an open service that they will be rejected for going over the flood limits.

However, these rules will not protect you from targeted scans. If you have a certain port open and they are scanning for just that port, it will be exposed. If this is a concern, then you may wish to consider if using a port knocking solution like FWKNOP is appropriate for your needs.

For flood protection, we use a seperate chain that ends in RETURN rather than ACCEPT so that any packet that reaches the end of the chain is subject to any rules that follow and isn't simply accepted.

V. Reject rather than Drop: While it is common to configure iptables to DROP any session that we don't want to allow, that is often interpreted (correctly or not) as a open or filtered port by nmap. On the other hand, if we add the following rules near the end of our script:

iptables -A INPUT -p TCP -j REJECT --reject-with tcp-reset
iptables -A INPUT -p UDP -j REJECT --reject-with icmp-port-unreachable
iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
iptables -A INPUT -j DROP

For nmap's TCP and UDP scans that get passed the invalid and flood rules, all ports will be reported as closed.

For nmap's protocol scans, they will be able to see that our system responds to TCP, UDP and ICMP but nothing else.

And the final DROP rule is there for paranoia that something could slip past the other three.

[edit] Example

[edit] A simple firewall that only accepts SSH and HTTP traffic

This is just about how small an iptables script can get, without losing any security. It will let you do whatever you want on the internets. It will silently drop almost all connections to your computer, except for inbound SSH and HTTP traffic. If you experience problems with this, you could try to change the ICMP rules to something that smells less of paranoid fascism.

Properties:

  • You are allowed to initiate all types of connections to others
  • Others are only allowed to initiate SSH and HTTP sessions to your computer, everything else will be silently dropped
  • Almost no ICMP-packets are accepted. This can result in longer waiting times, before your programs realize that services are offline. You can change this in the script, I made some notes in the script about different ICMP-types you can allow.
  • This iptables script will not make your computer forward any traffic. The script is intended for a server, not a router.
  • It does let through strange packets to your SSH/HTTP-daemons. SYN+URG, SYN+PSH are allowed. I think that most people consider this perfectly OK. These flags ARE useful sometimes (sending OOB data). Anyways, I am not sure that there is any simple way to clean them away.
#!/bin/sh

# module to track the state of connections
modprobe ip_conntrack

# load the iptables active FTP module, requires ip_conntrack 
# (makes linux kernel aware of how the insanely old ftp protocol works. 
# ftp was designed for an intertubes without NAT, before RFC1631 came along in 1994.)
modprobe ip_conntrack_ftp

# sets somewhat sane sysctl stuff
sysctl -w net.ipv4.conf.all.forwarding=0           # we are not a router
#sysctl -w net.ipv4.conf.all.mc_forwarding=0        # do not propagate multicasts  (not supported since some version, i guess.)
sysctl -w net.ipv4.conf.all.rp_filter=1            # drop all packets that the kernel think are spoofed
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1   # avoid being part of smurf attacks
sysctl -w net.ipv4.conf.all.accept_source_route=0  # uncomment this if you have a complex network with multiple routers ;)
sysctl -w net.ipv4.tcp_syncookies=1                # saves some memory if syn-flooded

# sets default policy DROP for everything not explicitly allowed.
iptables -P INPUT DROP
iptables -P FORWARD DROP
# your programs are allowed to talk with the internets by default.
iptables -P OUTPUT ACCEPT

# drop everything that has to do with IPv6
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT             # accept that your own computer sends IPv6 packets to others

# flush all previous firewall rules.
iptables -F
# nulls all counters, eg. how many packets eth0 has sent, et.c.
iptables -Z

# accept all incoming traffic to the loopback interface
# you should be allowed to talk with yourself :d
iptables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT  # accepts incomming IPv6 packets only at loopback interface (::1), se ip6tables default above

# setting ICMP rules...
# uncomment stuff if you think you need them. they could make life easier.
# uncommenting stuff marked with X could make life easier without loosing almost any security at all.
iptables -A INPUT --protocol icmp --icmp-type 0/0 -j ACCEPT  # echo reply (you want to be able to ping others)
#iptables -A INPUT --protocol icmp --icmp-type 3/0 -j ACCEPT  # network unreachable                          X
#iptables -A INPUT --protocol icmp --icmp-type 3/1 -j ACCEPT  # host unreachable                             X
#iptables -A INPUT --protocol icmp --icmp-type 3/2 -j ACCEPT  # protocol unreachable                         X
#iptables -A INPUT --protocol icmp --icmp-type 3/3 -j ACCEPT  # port unreachable                             X
#iptables -A INPUT --protocol icmp --icmp-type 4/0 -j ACCEPT  # source quench (source runs out of bandwidth) X
#iptables -A INPUT --protocol icmp --icmp-type 5 -j ACCEPT  # router redirects etc, be careful & see sysctl above
#iptables -A INPUT --protocol icmp --icmp-type 8/0 -j ACCEPT  # echo request (respond to ping?)
#iptables -A INPUT --protocol icmp --icmp-type 30/0 -j ACCEPT  # traceroute (use tcptraceroute instead?)
# the rest of the ICMP types/codes could be ignored, i think ;)

# avoid the *feature* of "--state NEW" that allows NEW TCP packets with SYN=0 to pass (see the text about ACK-scans above)
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# accepts initializing, eg. SYN, connections to port 22 and 80.
iptables -A INPUT --protocol tcp --destination-port 22 -m state --state NEW -j ACCEPT
iptables -A INPUT --protocol tcp --destination-port 80 -m state --state NEW -j ACCEPT

# accepts all traffic that is part of some session. eg. you created it or it is part of an
# already established connection to your SSH or HTTP servers.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# do not forget to update your firewall script if you add more services :b

[edit] Router for 3 networks - One physical and two VPNs

This is an example of a little bit more complicated script, based on the previous one. There are three interfaces on the router: One hardware-interface (int_if, for internal interface, using the device ZZZ. Replace it with something like "eth0") and two software-interfaces named ext_if (think of it as the main VPN tunnel), and darknet_if (interface connecting to another VPN-tunnel, used to connect to some darknet.) The router is a computer that is located on a physical LAN, where it is used to route traffic to the internets via the main VPN-tunnel (ext_if), and to a closed VPN-network (darknet_if.) The darknet connected to darknet_if has a DHCP server that allocates addresses to the users. The DHCP server runs on the router for which this script is supposed to be executed on. All packets going out to the internets is routed and SNATed through the ext_if. All traffic from the internets is silently dropped unless they are part of an session that anyone from the inside has already established. There is a few exceptions to this rule; it should be possible to initate traffic to server_0 and server_1 from the outside.

Note: I do not trust this script, but it kind of works :) It needs more attention. Maybe it is not possible to write good rules for iptables about this :/

Map of the networks

   lan --- router --- darknet
              |
          internets (via VPN)

The script

#!/bin/sh

# sets some constants (obviously, you should change these!)
ext_if="XXX"
ext_ip="a.b.c.d"
darknet_if="YYY"
int_if="ZZZ"
int_ip="e.f.g.h"
server_0="i.j.k.l"
server_1="m.n.o.p"

#------------------ initialization -----------------

# load some modules for state keeping
modprobe ip_conntrack        # keep track of connections
modprobe ip_conntrack_ftp    # keep special track of TCP sessions
modprobe ip_conntrack_irc    # and you want to be able to IRC also :)

# sets somewhat sane sysctl stuff
sysctl -w net.ipv4.conf.all.forwarding=1           # we are a router
sysctl -w net.ipv4.conf.all.mc_forwarding=0        # do not propagate multicasts
sysctl -w net.ipv4.conf.all.rp_filter=1            # drop all packets that the kernel think are spoofed
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1   # avoid being part of smurf attacks
sysctl -w net.ipv4.conf.all.accept_source_route=0  # think twice before setting this to 1
sysctl -w net.ipv4.tcp_syncookies=1                # saves some memory if syn-flooded


#------------------ policy & sane defaults -----------------

# sets default policy DROP for everything not explicitly allowed.
iptables -P INPUT DROP
iptables -P FORWARD DROP
# your programs are allowed to talk with the internets by default.
iptables -P OUTPUT ACCEPT

# drop everything that has to do with IPv6
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP

# flush all previous firewall rules. notice that we have to flush the nat chains explicitly.
# this is because flushing only applies to the default chain otherwise. note to linux developers:
# it is not just a matter of RTFM always, perhaps you should try to Write The Fucking Manual !!!
iptables -F
iptables -F PREROUTING -t nat
iptables -F INPUT
iptables -F FORWARD
iptables -F OUTPUT
iptables -F POSTROUTING -t nat

# nulls all counters, eg. how many packets eth0 has sent, et.c.
iptables -Z


#------------------ prerouting rules ------------------

# redirect $ext_ip port 22,80 -> $server_0

# port 22 and 80 to server_0
iptables -t nat -A PREROUTING --in-interface $ext_if --destination $ext_ip \
   -p tcp --destination-port 22 -j DNAT --to-destination $server_0
iptables -t nat -A PREROUTING --in-interface $ext_if --destination $ext_ip \
   -p tcp --destination-port 80 -j DNAT --to-destination $server_0

# port 7777, 8080, 8081 to server_1
iptables -t nat -A PREROUTING --in-interface $ext_if --destination $ext_ip \
   -p tcp --destination-port 7777 -j DNAT --to-destination $server_1:22
iptables -t nat -A PREROUTING --in-interface $ext_if --destination $ext_ip \
   -p tcp --destination-port 8080 -j DNAT --to-destination $server_1
iptables -t nat -A PREROUTING --in-interface $ext_if --destination $ext_ip \
   -p tcp --destination-port 8081 -j DNAT --to-destination $server_1


#------------------ user defined chains -----------------

echo logDROP
iptables -X logDROP
iptables -N logDROP
iptables -A logDROP -j LOG
iptables -A logDROP -j DROP

echo noSpoof

iptables -X noSpoof       # delete the chain if it already exists
# noSpoof drops packets comming from strange addresses
iptables -N noSpoof
iptables -A noSpoof --source 10.0.0.0/8     -i $ext_if -j logDROP
iptables -A noSpoof --source 172.16.0.0/12  -i $ext_if -j logDROP
iptables -A noSpoof --source 192.168.0.0/16 -i $ext_if -j logDROP
iptables -A noSpoof --source 127.0.0.0/8    ! -i lo    -j logDROP  # probably pointless

# it is kind of important to have noSpoof FIRST in our chains please :)
iptables -A INPUT   -j noSpoof
iptables -A FORWARD -j noSpoof


#------------------ obvious loopback rules --------------------

# accept all incoming traffic to the loopback interface
# you should be allowed to talk with yourself :d
iptables -A INPUT -i lo -j ACCEPT


#------------------ incoming icmp rules -----------------

echo icmp

# setting ICMP rules...
# uncomment stuff if you think you need them. they could make life easier.
# uncommenting stuff marked with X could make life easier without loosing almost any security at all.
iptables -A INPUT --protocol icmp --icmp-type 0/0 -j ACCEPT  # echo reply (you want to be able to ping)
#iptables -A INPUT --protocol icmp --icmp-type 3/0 -j ACCEPT  # network unreachable                          X
#iptables -A INPUT --protocol icmp --icmp-type 3/1 -j ACCEPT  # host unreachable                             X
#iptables -A INPUT --protocol icmp --icmp-type 3/2 -j ACCEPT  # protocol unreachable                         X
#iptables -A INPUT --protocol icmp --icmp-type 3/3 -j ACCEPT  # port unreachable                             X
#iptables -A INPUT --protocol icmp --icmp-type 4/0 -j ACCEPT  # source quench (source runs out of bandwidth) X
#iptables -A INPUT --protocol icmp --icmp-type 5 -j ACCEPT  # router redirects etc, be careful & see sysctl above
#iptables -A INPUT --protocol icmp --icmp-type 8/0 -j ACCEPT  # echo request (respond to ping?)
#iptables -A INPUT --protocol icmp --icmp-type 30/0 -j ACCEPT  # traceroute (use tcptraceroute instead?)
# the rest of the ICMP types/codes could be ignored, i think ;)


#------------------ incoming tcp rules -----------------

echo tcp

# drop incomming NEW TCP packets that that does not have the SYN flag
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# accepts initializing, eg. SYN, connections to port 22 (SSH).
iptables -A INPUT --protocol tcp --destination-port 22 -m state --state NEW -j ACCEPT

# accepts all traffic that is part of some session.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT


#------------------ forwarding rules -----------------

echo forward

# *all* LAN traffic is allowed out to internets (this rule needs to be first in the chain if you should be able to send spoofed and crazy packets)
iptables -A FORWARD -i $int_if -j ACCEPT

# drop NEW TCP packets that does not have the SYN-flag set
iptables -A FORWARD -p tcp ! --syn -m state --state NEW -j DROP

# accepts initializing, eg. SYN, connections to port 22 and 80 to server_0.
iptables -A FORWARD --protocol tcp --destination-port 22 --destination $server_0 -m state --state NEW -j ACCEPT
iptables -A FORWARD --protocol tcp --destination-port 80 --destination $server_0 -m state --state NEW -j ACCEPT

# accepts initializing, eg. SYN, connections to port 22, 8080, 8081 to server_1
iptables -A FORWARD --protocol tcp --destination-port 22 --destination $server_1 -m state --state NEW -j ACCEPT
iptables -A FORWARD --protocol tcp --destination-port 8080 --destination $server_1 -m state --state NEW -j ACCEPT
iptables -A FORWARD --protocol tcp --destination-port 8081 --destination $server_1 -m state --state NEW -j ACCEPT

# and accpet packets belonging to already existing sessions are allowed into the LAN and the darknet
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -i $ext_if -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -i $darknet_if -j ACCEPT


#------------------ postrouting rules -----------------

echo postrouting

# always randomize the ports that are used when SNATing
iptables -A POSTROUTING -t nat -o $ext_if --protocol tcp -j SNAT --to-source $ext_ip:1024-65335 --random
iptables -A POSTROUTING -t nat -o $ext_if --protocol udp -j SNAT --to-source $ext_ip:1024-65335 --random
iptables -A POSTROUTING -t nat -o $ext_if -j SNAT --to-source $ext_ip --random

# you can uncomment this block if you want to, it will make all traffic from the *outside* appear as it
# originated from the router itself. it might be useful if the server_0 and server_1 computers are not using
# the router this script is intended for as gateway. (think about the logs!)
#iptables -A POSTROUTING -t nat -o $int_if --protocol tcp -j SNAT --to-source $int_ip:1024-65335 --random
#iptables -A POSTROUTING -t nat -o $int_if --protocol udp -j SNAT --to-source $int_ip:1024-65335 --random
#iptables -A POSTROUTING -t nat -o $int_if -j SNAT --to-source $int_ip --random

# because the darknet_if is configured with DHCP or whatever, we need to use MASQUERADE instead of SNAT, which
# is a bit lame unfortunately.
iptables -A POSTROUTING -t nat -o $darknet_if -j MASQUERADE --random
Personal tools
1 0