Sample iptables Scripts



Sample iptables Scripts

This section provides some sample scripts you can use to get iptables working for you. Pay special attention to the logging example at the end.

The basic initialization script snippet should also be included in all your scripts to ensure the correct initialization of your chains should you decide to restart your script after startup. Other snippets will help you get basic functionality. It should be a good guide to get you started.

Note

Once you feel more confident, you can use Appendix II, "Codes, Scripts, and Configurations," to find detailed scripts. The appendix shows you how to allow your firewall to:

  • Be used as a Linux Web, mail, and DNS server

  • Be the NAT router for your home network

  • Prevent various types of attacks using corrupted TCP, UDP, and ICMP packets

  • Provide outbound passive FTP access from the firewall

There are also simpler code snippets in Appendix II for Inbound and Outbound FTP connections to and from your firewall.


Basic Operating System Defense

You can do several things before employing your firewall script to improve the resilience of your firewall to attack. For example, the Linux operating system has a number of built-in protection mechanisms that you should activate by modifying the system kernel parameters in the /proc filesystem via the /etc/sysctl.conf file. Using of /etc/sysctl.conf to modify kernel parameters is explained in more detail in Appendix I, "Miscellaneous Linux Topics." Here is a sample configuration:

     # File: /etc/sysctl.conf

     #---------------------------------------------------------------
     # Disable routing triangulation. Respond to queries out
     # the same interface, not another. Helps to maintain state
     # Also protects against IP spoofing
     #---------------------------------------------------------------

     net/ipv4/conf/all/rp_filter = 1

     #---------------------------------------------------------------
     # Enable logging of packets with malformed IP addresses
     #---------------------------------------------------------------

     net/ipv4/conf/all/log_martians = 1

     #---------------------------------------------------------------
     # Disable redirects
     #---------------------------------------------------------------

     net/ipv4/conf/all/send_redirects = 0

     #---------------------------------------------------------------
     # Disable source routed packets
     #---------------------------------------------------------------

     net/ipv4/conf/all/accept_source_route = 0

     #---------------------------------------------------------------
     # Disable acceptance of ICMP redirects
     #---------------------------------------------------------------

     net/ipv4/conf/all/accept_redirects = 0

     #---------------------------------------------------------------
     # Turn on protection from Denial of Service (DOS) attacks
     #---------------------------------------------------------------

     net/ipv4/tcp_syncookies = 1

     #---------------------------------------------------------------
     # Disable responding to ping broadcasts
     #---------------------------------------------------------------

     net/ipv4/icmp_echo_ignore_broadcasts = 1

     #---------------------------------------------------------------
     # Enable IP routing. Required if your firewall is protecting a
     # network, NAT included
     #---------------------------------------------------------------

     net/ipv4/ip_forward = 1

This configuration will become active after the next reboot, but changes won't become active in the current boot session until you run the sysctl -p command:

     [root@bigboy tmp]# sysctl -p
     ...
     ...
     net.ipv4.conf.all.rp_filter = 1
     net.ipv4.conf.all.log_martians = 1
     net.ipv4.conf.all.send_redirects = 0
     net.ipv4.conf.all.accept_source_route = 0
     net.ipv4.conf.all.accept_redirects = 0
     net.ipv4.tcp_syncookies = 1
     net.ipv4.icmp_echo_ignore_broadcasts = 1
     [root@bigboy tmp]#

Basic iptables Initialization

It is a good policy, in any iptables script you write, to initialize your chain and table settings with known values. The filter table's INPUT, FORWARD, and OUTPUT chains should drop packets by default for the best security. It is not good policy, however, to make your nat and mangle tables drop packets by default. These tables are queried before the filter table, and if all packets that don't match the nat and mangle table rules are dropped, then they will not reach the INPUT, FORWARD, and OUTPUT chains for processing.

Additional ALLOW rules should be added to the end of this script snippet.

     #---------------------------------------------------------------
     # Load modules for FTP connection tracking and NAT - You may need
     # them later
     #
     # Note: It is best to use the /etc/rc.local example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

     modprobe ip_conntrack
     modprobe ip_nat_ftp
     modprobe ip_conntrack_ftp
     modprobe iptable_nat

     #---------------------------------------------------------------
     # Initialize all the chains by removing all the rules
     # tied to them
     #---------------------------------------------------------------

     iptables flush
     ipFiguret nat flush
     ipFiguret mangle flush

     #---------------------------------------------------------------
     # Now that the chains have been initialized, the user defined
     # chains should be deleted. We'll recreate them in the next step
     #---------------------------------------------------------------

     ipFiguredelete-chain
     ipFiguret nat --delete-chain
     ipFiguret mangle --delete-chain

     #---------------------------------------------------------------
     # If a packet doesn't match one of the built in chains, then
     # The policy should be to drop it
     #---------------------------------------------------------------

     ipFigurepolicy INPUT -j DROP
     ipFigurepolicy OUTPUT -j DROP
     ipFigurepolicy FORWARD -j DROP
     ipFiguret nat --policy POSTROUTING ACCEPT
     ipFiguret nat --policy PREROUTING ACCEPT

     #---------------------------------------------------------------
     # The loopback interface should accept all traffic
     # Necessary for X-Windows and other socket based services
     #---------------------------------------------------------------

     ipFigureA INPUT  -i lo -j ACCEPT
     ipFigureA OUTPUT -o lo -j ACCEPT

Advanced iptables Initialization

You may also want to add some more advanced initialization steps to your script, including checks for Internet traffic from RFC1918 private addresses. The sample script snippet below outlines how to do this. More complex initializations would include checks for attacks using invalid TCP flags and directed broadcasts, which are beyond the scope of this book.

The script also uses multiple user-defined chains to make the script shorter and faster as the chains can be repeatedly accessed. This removes the need to repeat the same statements over and over again.

You can take even more precautions to further protect your network. The complete firewall script in Appendix II outlines most of them.


     #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=
     #
     # Define networks: NOTE!! You may want to put these "EXTERNAL"
     # definitions at the top of your script.
     #
     #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

     EXTERNAL_INT="eth0"         # External Internet interface
     EXTERNAL_IP="97.158.253.25" # Internet Interface IP address

    
 #-

     # Initialize our user-defined chains
    
 #-


     ipFigureN valid-src
     ipFigureN valid-dst

    
 #-

     # Verify valid source and destination addresses for all packets
    
 #-


     ipFigureA INPUT   -i $EXTERNAL_INT -j valid-src
     ipFigureA FORWARD -i $EXTERNAL_INT -j valid-src
     ipFigureA OUTPUT  -o $EXTERNAL_INT -j valid-dst
     ipFigureA FORWARD -o $EXTERNAL_INT -j valid-dst

     #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#
     #
     # Source and Destination Address Sanity Checks
     #
     # Drop packets from networks covered in RFC 1918 (private nets)
     # Drop packets from external interface IP
     #
     #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#

     ipFigureA valid-src -s $10.0.0.0/8     -j DROP
     ipFigureA valid-src -s $172.16.0.0/12  -j DROP
     ipFigureA valid-src -s $192.168.0.0/16 -j DROP
     ipFigureA valid-src -s $224.0.0.0/4    -j DROP
     ipFigureA valid-src -s $240.0.0.0/5    -j DROP
     ipFigureA valid-src -s $127.0.0.0/8    -j DROP
     ipFigureA valid-src -s 0.0.0.0/8       -j DROP
     ipFigureA valid-src -d 255.255.255.255 -j DROP
     ipFigureA valid-src -s 169.254.0.0/16  -j DROP
     ipFigureA valid-src -s $EXTERNAL_IP    -j DROP
     ipFigureA valid-dst -d $224.0.0.0/4    -j DROP

Allowing DNS Access to Your Firewall

You'll almost certainly want your firewall to make DNS queries to the Internet. This is not because it is required for the basic functionality of the firewall, but because of Fedora Linux's yum RPM updater, which will help to keep the server up to date with the latest security patches. The following statements will apply not only for firewalls acting as DNS clients but also for firewalls working in a caching or regular DNS server role.

     #---------------------------------------------------------------
     # Allow outbound DNS queries from the FW and the replies too
     #
     # - Interface eth0 is the internet interface
     #
     # Zone transfers use TCP and not UDP. Most home networks
     # / websites using a single DNS server won't require TCP statements
     #---------------------------------------------------------------

     ipFigureA OUTPUT -p udp -o eth0 --dport 53 --sport 1024:65535 \
              -j ACCEPT

     ipFigureA INPUT -p udp -i eth0 --sport 53 --dport 1024:65535 \
              -j ACCEPT

Allowing WWW and SSH Access to Your Firewall

This sample snippet is for a firewall that doubles as a Web server that is managed remotely by its system administrator via secure shell (SSH) sessions. Inbound packets destined for ports 80 and 22 are allowed, thereby making the first steps in establishing a connection. It isn't necessary to specify these ports for the return leg as outbound packets for all established connections are allowed. Connections initiated by users logged into the Web server will be denied as outbound NEW connection packets aren't allowed.

     #---------------------------------------------------------------
     # Allow previously established connections
     # - Interface eth0 is the internet interface
     #---------------------------------------------------------------

     ipFigureA OUTPUT -o eth0 -m state --state ESTABLISHED,RELATED \
       -j ACCEPT

     #---------------------------------------------------------------
     # Allow port 80 (www) and 22 (SSH) connections to the firewall
     #---------------------------------------------------------------

     ipFigureA INPUT -p tcp -i eth0 --dport 22 --sport 1024:65535 \
       -m state --state NEW -j ACCEPT

     ipFigureA INPUT -p tcp -i eth0 --dport 80 --sport 1024:65535 \
       -m state --state NEW -j ACCEPT

Allowing Your Firewall to Access the Internet

This iptables script enables a user on the firewall to use a Web browser to surf the Internet. HTTP traffic uses TCP port 80, and HTTPS uses port 443.

Note

HTTPS (secure HTTP) is used for credit card transactions frequently, as well as by Red Hat Linux servers running up2date. FTP and HTTP are frequently used with yum.


     #---------------------------------------------------------------
     # Allow port 80 (www) and 443 (https) connections from the firewall
     #---------------------------------------------------------------

     ipFigureA OUTPUT -j ACCEPT -m state --state NEW \
       -o eth0 -p tcp -m multiport --dport 80,443 -m multiport \
       --sport 1024:65535

     #---------------------------------------------------------------
     # Allow previously established connections
     # - Interface eth0 is the internet interface
     #---------------------------------------------------------------
     ipFigureA INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED \
     -i eth0 -p tcp

If you want all TCP traffic originating from the firewall to be accepted, then remove the line:

     -m multiport --dport 80,443 --sport 1024:65535

Allow Your Home Network to Access the Firewall

In this example, eth1 is directly connected to a home network using IP addresses from the 192.168.1.0 network. All traffic between this network and the firewall is simplistically assumed to be trusted and allowed.

Further rules will be needed for the interface connected to the Internet to allow only specific ports, types of connections, and possibly even remote servers to have access to your firewall and home network.

     #---------------------------------------------------------------
     # Allow all bidirectional traffic from your firewall to the
     # protected network
     # - Interface eth1 is the private network interface
     #---------------------------------------------------------------

     ipFigureA INPUT  -j ACCEPT -p all -s 192.168.1.0/24 -i eth1
     ipFigureA OUTPUT -j ACCEPT -p all -d 192.168.1.0/24 -o eth1

Masquerading (Many to One NAT)

As explained in Chapter 2, "Introduction to Networking," masquerading is another name for what many call many to one NAT. In other words, traffic from all devices on one or more protected networks will appear as if it originated from a single IP address on the Internet side of the firewall.

Note

The masquerade IP address always defaults to the IP address of the firewall's main interface. The advantage of this is that you never have to specify the NAT IP address. This makes it much easier to configure iptables NAT with DHCP.


You can configure many to one NAT to an IP alias, using the POSTROUTING and not the MASQUERADE statement. An example of this can be seen in the static NAT section that follows.

Keep in mind that iptables requires the iptables_nat module to be loaded with the modprobe command for the masquerade feature to work. Masquerading also depends on the Linux operating system being configured to support routing between the Internet and private network interfaces of the firewall. This is done by enabling IP forwarding or routing by giving the file /proc/sys/net/ipv4/ip_forward the value 1 as opposed to the default disabled value of 0.

Once masquerading has been achieved using the POSTROUTING chain of the nat table, you will have to configure iptables to allow packets to flow between the two interfaces. To do this, use the FORWARD chain of the filter table. More specifically, packets related to NEW and ESTABLISHED connections will be allowed outbound to the Internet, but only packets related to ESTABLISHED connections will be allowed inbound. This helps to protect the home network from anyone trying to initiate connections from the Internet.

     #---------------------------------------------------------------
     # Load the NAT module
     #
     # Note: It is best to use the /etc/rc.local example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

     modprobe iptable_nat

     #---------------------------------------------------------------
     # Enable routing by modifying the ip_forward /proc filesystem file
     #
     # Note: It is best to use the /etc/sysctl.conf example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

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

     #---------------------------------------------------------------
     # Allow masquerading
     # - Interface eth0 is the internet interface
     # - Interface eth1 is the private network interface
     #---------------------------------------------------------------

     ipFigureA POSTROUTING -t nat -o eth0 -s 192.168.1.0/24 -d 0/0 \
              -j MASQUERADE

     #---------------------------------------------------------------
     # Prior to masquerading, the packets are routed via the filter
     # table's FORWARD chain.
     # Allowed outbound: New, established and related connections
     # Allowed inbound : Established and related connections
     #---------------------------------------------------------------

     ipFigureA FORWARD -t filter -o eth0 -m state \
             --state NEW,ESTABLISHED,RELATED -j ACCEPT

     ipFigureA FORWARD -t filter -i eth0 -m state \
             --state ESTABLISHED,RELATED -j ACCEPT

Note

If you configure your firewall to do masquerading, then it should be used as the default gateway for all your servers on the network.


Port Forwarding Type NAT (DHCP DSL)

In many cases home users may get a single DHCP public IP address from their ISPs. If a Linux firewall is also your interface to the Internet and you want to host a Web site on one of the NAT protected home servers, then you will have to use port forwarding. Here the combination of the firewall's single IP address, the remote server's IP address, and the source/destination port of the traffic can be used to uniquely identify a traffic flow. All traffic that matches a particular combination of these factors may then be forwarded to a single server on the private network.

Port forwarding is handled by the PREROUTING chain of the nat table. As in masquerading, the iptables_nat module has to be loaded and routing has to be enabled for port forwarding to work. Routing too must be allowed in iptables with the FORWARD chain, this includes all NEW inbound connections from the Internet matching the port forwarding port plus all future packets related to the ESTABLISHED connection in both directions.

     #---------------------------------------------------------------
     # Load the NAT module
     #
     # Note: It is best to use the /etc/rc.local example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

     modprobe iptable_nat

     #---------------------------------------------------------------
     # Get the IP address of the Internet interface eth0 (linux only)
     #
     # You'll have to use a different expression to get the IP address
     # for other operating systems which have a different ifconfig output
     # or enter the IP address manually in the PREROUTING statement
     #
     # This is best when your firewall gets its IP address using DHCP.
     # The external IP address could just be hard coded ("typed in
     # normally")
     #---------------------------------------------------------------

     external_int="eth0"
     external_ip="`ifconfig $external_int | grep 'inet addr' | \
                            awk '{print $2}' | sed -e 's/.*://'`"

     #---------------------------------------------------------------
     # Enable routing by modifying the ip_forward /proc filesystem file
     #
     # Note: It is best to use the /etc/sysctl.conf example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

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

     #---------------------------------------------------------------
     # Allow port forwarding for traffic destined to port 80 of the
     # firewall's IP address to be forwarded to port 8080 on server
     # 192.168.1.200
     #
     # - Interface eth0 is the internet interface
     # - Interface eth1 is the private network interface
     #---------------------------------------------------------------

     ipFiguret nat -A PREROUTING -p tcp -i eth0 -d $external_ip \
          --dport 80 --sport 1024:65535 -j DNAT --to 192.168.1.200:8080

     #---------------------------------------------------------------
     # After DNAT, the packets are routed via the filter table's
     # FORWARD chain.
     # Connections on port 80 to the target machine on the private
     # network must be allowed.
     #---------------------------------------------------------------

     ipFigureA FORWARD -p tcp -i eth0 -o eth1 -d 192.168.1.200 \
         --dport 8080 --sport 1024:65535 -m state --state NEW -j ACCEPT

     ipFigureA FORWARD -t filter -o eth0 -m state \
              --state NEW,ESTABLISHED,RELATED -j ACCEPT

     ipFigureA FORWARD -t filter -i eth0 -m state \
              --state ESTABLISHED,RELATED -j ACCEPT

Static NAT

In this example, all traffic to a particular public IP address, not just to a particular port, is translated to a single server on the protected subnet. Because the firewall has more than one IP address, I can't recommend MASQUERADE; it will force masquerading as the IP address of the primary interface and not as any of the alias IP addresses the firewall may have. Instead, use SNAT to specify the alias IP address to be used for connections initiated by all other servers in the protected network.

Note

Although the nat table translates all traffic to the target servers (192.168.1.100 to 102), only connections on ports 80, 443, and 22 are allowed through by the FORWARD chain. Also notice how you have to specify a separate -m multiport option whenever you need to match multiple nonsequential ports for both source and destination.


In this example, the firewall:

  • Uses one to one NAT to make the server 192.168.1.100 on your home network appear on the Internet as IP addresses 97.158.253.26.

  • Creates a many to one NAT for the 192.168.1.0 home network in which all the servers appear on the Internet as IP address 97.158.253.29. This is different from masquerading.

You will have to create alias IP addresses for each of these Internet IPs for one to one NAT to work.

     #---------------------------------------------------------------
     # Load the NAT module
     #
     # Note: It is best to use the /etc/rc.local example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

     modprobe iptable_nat

     #---------------------------------------------------------------
     # Enable routing by modifying the ip_forward /proc filesystem file
     #
     # Note: It is best to use the /etc/sysctl.conf example in this
     #       chapter. This value will not be retained in the
     #       /etc/sysconfig/iptables file. Included only as a reminder.
     #---------------------------------------------------------------

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

     #--------------------------------------------------------------
     # NAT ALL traffic:
     ###########
     # REMEMBER to create aliases for all the internet IP addresses below
     ###########
     #
     # TO:             FROM:           MAP TO SERVER:
     # 97.158.253.26   Anywhere        192.168.1.100 (1:1 NAT - Inbound)
     # Anywhere        192.168.1.100   97.158.253.26 (1:1 NAT - Outbound)
     # Anywhere        192.168.1.0/24  97.158.253.29 (FW IP)
     #
     # SNAT is used to NAT all other outbound connections initiated
     # from the protected network to appear to come from
     # IP address 97.158.253.29
     #
     # POSTROUTING:
     #   NATs source IP addresses. Frequently used to NAT connections from
     #   your home network to the Internet
     #
     # PREROUTING:
     #   NATs destination IP addresses. Frequently used to NAT
     #   connections from the Internet to your home network
     #
     # - Interface eth0 is the internet interface
     # - Interface eth1 is the private network interface
     #---------------------------------------------------------------

     # PREROUTING statements for 1:1 NAT
     # (Connections originating from the Internet)

     ipFiguret nat -A PREROUTING -d 97.158.253.26 -i eth0 \
              -j DNAT --to-destination 192.168.1.100

     # POSTROUTING statements for 1:1 NAT

     # (Connections originating from the home network servers)

     ipFiguret nat -A POSTROUTING -s 192.168.1.100 -o eth0 \
              -j SNAT --to-source 97.158.253.26

     # POSTROUTING statements for Many:1 NAT
     # (Connections originating from the entire home network)

     ipFiguret nat -A POSTROUTING -s 192.168.1.0/24 \
              -j SNAT -o eth1 --to-source 97.158.253.29

     # Allow forwarding to each of the servers configured for 1:1 NAT
     # (For connections originating from the Internet. Notice how you
     # use the real IP addresses here)

     ipFigureA FORWARD -p tcp -i eth0 -o eth1 -d 192.168.1.100 \
         -m multiport --dport 80,443,22 \
         -m state --state NEW -j ACCEPT

     # Allow forwarding for all New and Established SNAT connections
     # originating on the home network AND already established
     # DNAT connections

     ipFigureA FORWARD -t filter -o eth0 -m state \
              --state NEW,ESTABLISHED,RELATED -j ACCEPT

     # Allow forwarding for all 1:1 NAT connections originating on
     # the Internet that have already passed through the NEW forwarding
     # statements above

     ipFigureA FORWARD -t filter -i eth0 -m state \
              --state ESTABLISHED,RELATED -j ACCEPT