Scriptable Iptables Firewall Tool
SIFT
http://sourceforge.net/projects/sift-io
OVERVIEW
Version 2.0
Copyright © 2006-2007 by B.B.
This document is released under the terms of the GPL FDL.
This document gives an overview of SIFT: Scriptable Iptables Firewall Tool.
Table of Contents
1 CONTENTS |
2 INTRODUCTION |
3 FIREWALL/PACKET FILTERS |
4 SIFT USAGE |
5 SUMMARY |
SIFT is an iptables firewall script generator. Iptables is the default administration tool for IPv4/6 filtering (and rewriting – NAT) on a Linux/GNU platform. The output of SIFT can be used to run as the “ /etc/init.d/iptables start ” script on a Linux/GNU platform.
Less is more. And, personally, I hate to write documents that other people don’t read. But fear not. There are several documents about SIFT available in this release. In
doc/sift-design/ you can find the design documentation, and in
doc/sift-verification/ you can find the verification documentation.
There are also some public documents in the doc/www/ folder.
This document gives an overview of SIFT, release v2.0. SIFT has been used to create iptables firewall scripts for several sites. It is reliable software.
SIFT generates a packet filter firewall script. Packet filtering firewalls are fast and reliable.
A firewall/packet filter must (at least) be able to:
block unwanted traffic
pass allowed traffic
log specific traffic.
SIFT uses the terminology borrowed from iptables by using drop for blocked traffic, accept for traffic that is allowed to pass the firewall, and log to monitor and log specific traffic.
But how to drop or accept traffic? Well, a firewall is basically some hardware box with interfaces on the outside and inside running some software that determines if IP traffic with specific IP characteristics:
may enter an interface
may leave an interface.
The most obvious IP characteristic is of course its IP address or IP address range (t.i. a subnet). And that is why we decided to build the firewall configuration on the concept of zones. A zone is the combination of an interface and a list of IP address ranges (subnets). And the configuration of a firewall must then only specify what zone to zone traffic is accepted (called a policy), and all other traffic will automatically be dropped.
Illustration 2 depicts our example setup. The firewall is placed between the internal network/DMZ and the external network. In this setup, we can identify the two networks with several zones:
External network:
“untrusted” INTERNET zone, on the external interface, with the full IP address range (set to 0.0.0.0/0)
slightly more trusted ISP zone, on the external interface, with an example IP address range (set to 194.109.0.0/16)
Internal network:
demilitarized zone (DMZ) with a Mail and Web server, on an internal interface (for example set to 235.128.0.0/16)
internal segmented LAN with 2 zones, on an internal interface, with example IP address ranges (ZONE1 with 10.0.0.0/16, ZONE2 with 192.168.0.0/16)
Note:
Here, the ISP zone is in a different zone from the INTERNET zone because in general we need an external DNS server - and we expect to trust the DNS server of an ISP more than the average DNS server on the INTERNET.
The firewall should enforce policies on the traffic that is allowed to pass through the firewall. These policies are formulated as zone to zone traffic. In Illustration 2, there are only two policies visualized: ZONE1 -> INTERNET, and INTERNET -> DMZ. Note that all policies are directed. A policy identifies the services that are allowed between two zones.
Note:
The firewall can only block traffic that goes through the firewall. Therefore, it might not be possible in this setup to enforce policies on ZONE1 to ZONE2 traffic (for example, if these LANs are connected together by a switch or hub).
A firewall must be able to pass allowed or block unwanted generic traffic, where generic traffic means that it is not based on zones or policies. For example, you might always want to block certain types of ICMP traffic. These are called shields by SIFT. Shields are attached to interfaces, and support pre-filtering, post-filtering, rewriting and mangling on both input, output and forward traffic.
Note:
Rewriting can be used to implement Network Address Translation (NAT). NAT is mostly used to hide internal LAN network addresses. With NAT only one IP address – that of the firewall - is exposed to the outside world. Because the DMZ servers are accessible from the outside world, their IP addresses should not be subjected to NAT.
Well, that's about it (I will skip logging here). Let us look in the next chapter on how to use SIFT.
Writing iptables scripts can be quite difficult. SIFT does most of the difficult work, but it requires information about the setup of the firewall. This information is contained in a configuration file that specifies:
networks
interfaces
zones
policies
shields (optional)
services
filters (optional)
We will take the above mentioned typical firewall setup as an example here.
Note:
In our case, the configuration file is actually a script entirely written in the programming language Io (see http://www.iolanguage.com).
Some definitions:
A network = a binding of interfaces, zones, shields and policies
An interface = a unique name for a physical network device of the host (e.g. eth0)
A zone = a unique name for a binding of an interface and a set of IP addresses/ranges
A policy = a binding of services between two zones
A shield = a binding of filters to an interface
A service = a unique friendly textual name for an internet service
A filter = a unique friendly textual name for a method to pass, block or rewrite traffic
Before you can run SIFT, you must therefore make an inventory of:
all logical networks
all physical interfaces of the firewall host
all zones, and all IP addresses/ranges belonging to these zones
all policies for allowed zone to zone traffic
all shields bound to interface(s)
all services used in policies
all filters used in shields.
Note:
The same IP address/range can belong to several zones if either:
The same IP addresses/ranges are on different interfaces (this might get you into trouble routing the traffic however), or
In the case of overlap on the same interface, the most specific IP address/range is matched first. In the above example, the INTERNET IP address range 0.0.0.0/0 overlaps all other IP address ranges, but for instance the IP address range of the ISP, 194.109.0.0/16 is more specific than 0.0.0.0/0.
The main object of a configuration file is called Sift. It contains all the networks. In our example, we have an external and an internal network. This would look like:
firewall := Sift create(“example”) do(
// firewall IP address should be fixed
HOST_IP := “1.2.3.4”
// networks
Network create doFile(“networks/internal.io”)
Network create doFile(“networks/external.io”)
)
firewall print
A Firewall should have a fixed IP address (no DHCP). Here, we have chosen to put the configurations for both networks in separate files, which makes the top level configuration file short and tidy.
The output is printed by calling the print method of the Sift object.
Next, we must configure both networks. First, let us start with the internal network. We must make an inventory of all:
all physical interfaces of the firewall host
=> loopback interface lo
=> for example, the ethernet device eth0 is connected to the internal interface (LAN)
=> for example, the ethernet device eth1 is connected to the DMZ
all zones, and all IP addresses/ranges belonging to these zones
=> we have a zone connected to lo with:
LOC as 127.0.0.1
=> we have zones connected to eth0 with:
ZONE1 as 10.0.0.0/24
ZONE2 as 192.168.0.0/16
=> we have a zone connected to eth1 with:
DMZ as 235.128.0.0/16
all policies for allowed zone to zone traffic
=> from ZONE1 and ZONE2 to DMZ
POP, SMTP, HTTP, HTTPS
=> from ZONE1 to ZONE2 (if connected through the firewall)
PRINTER
all shields bound to interface(s)
=> default shields on eth0 and eth1
The internal.io configuration looks like:
// fixed IP address
ETH0_IP := “10.0.0.1”
ETH1_IP := “235.128.1.1”
// interfaces
lo := Interface(“lo”) ip(“127.0.0.1”)
eth0 := Interface(“eth0”) ip(ETH0_IP)
eth1 := Interface(“eth1”) ip(ETH1_IP)
// default shields
lo add shield filter(FILTERS LOOPBACK)
eth0 add shield filter(FILTERS INTERFACE)
eth1 add shield filter(FILTERS INTERFACE)
// zones
LOC := Zone create(“loc” ) interface(lo ) subnet(lo ip)
ZONE1 := Zone create(“zone1”) interface(eth0) subnet(“10.0.0.0/16”)
ZONE2 := Zone create(“zone2”) interface(eth0) subnet(“192.168.0.0/16”)
DMZ := Zone create(“dmz” ) interface(eth1) subnet(“235.128.0.0/16”)
// anti-spoof
LOC add zone interface(eth0) subnet(eth0 ip)
LOC add zone interface(eth1) subnet(eth1 ip)
// policies
SRV_DMZ := [POP,SMTP,HTTP,HTTPS]
Policy create from(LOC) to(LOC) services(ANY)
Policy create from(ZONE1) to(DMZ) services(SRV_DMZ)
Policy create from(ZONE2) to(DMZ) services(SRV_DMZ)
Policy create from(ZONE1) to(ZONE2) services(PRINTER)
Note:
Normally, in Io, you use clone to create a new object. Here, in stead of clone, we use create to automatically attach the object to the current network object (its parent).
We add the fixed IP address of the eth0 and the eth1 interface to the local zone to avoid any spoofing attacks.
Zone names should be alpha-numeric identifiers. They become part of iptables rule names and are therefore subject to some restrictions.
Interfaces must be named and must match a physical device on the host.
Policies can be named, but their names are not used (yet).
Shields can be named, but their names are not used (yet).
SIFT supports a whole range of predefined services and predefined filters.
See sift-design.odt for more information.
Next, the external network. We must make an inventory of all:
all physical interfaces of the firewall host
=> for example, the ethernet device eth2 is connected to the external interface
all zones, and all IP addresses/ranges belonging to these zones
=> we have zones connected to eth2 with:
INTERNET as 0.0.0.0/0
ISP as 194.109.0.0/16
all policies for allowed zone to zone traffic
=> from INTERNET and ISP to DMZ
SMTP, HTTP, HTTPS
=> from ZONE1, ZONE2 to ISP
ISP (e.g. DNS)
=> from ZONE1, ZONE2 to INTERNET
WAN (e.g. HTTP, HTTPS, FTP, ...)
all shields bound to interface(s)
=> forward shield on eth2 ( eth2 will forward traffic from eth0 and eth1)
=> NAT from eth0 to eth2
The external.io configuration looks like:
// fixed IP address
ETH2_IP := HOST_IP
// interfaces
eth2 := Interface(“eth2”) ip(ETH2_IP)
// default shields
eth2 add shield filter(FILTERS INTERFACE)
// zones
INTERNET := Zone create(“wan”) interface(eth2) subnet(“0.0.0.0/0”)
ISP := Zone create(“isp”) interface(eth2) subnet(“194.109.0.0/16”)
// anti-spoof
LOC add zone interface(eth2) subnet(eth2 ip)
// policies
SRV_WAN := [HTTP,HTTPS,FTP,SSH,KAZAA,...]
SRV_ISP := [DNS]
SRV_DMZ := [SMTP,HTTP,HTTPS]
Policy create from(ZONE1,ZONE2) to(INTERNET,ISP) services(SRV_WAN)
Policy create from(ZONE1,ZONE2) to(ISP) services(SRV_ISP)
Policy create from(INTERNET,ISP) to(DMZ) services(SRV_DMZ)
// NAT
eth2 add shield nat(HOST_IP) subnets(10.0.0.0/16”,”192.168.0.0/16”)
eth2 add shield interfaces(eth0,eth1) filter(FILTERS FORWARD)
Note:
We add the fixed IP address of the eth2 interface to the local zone to avoid any spoofing attacks.
We add a NAT rule to eth2 for both subnets belonging to the LAN zones.
We add a shield from both interfaces eth0 and eth1 to eth2 .
If all networks, interfaces, z ones , policies, shields, services and filters are specified in the firewall configuration file, then you can generate and install the firewall script (roughly) as follows:
Install the SIFT distribution in /etc/sift-io
Change the current directory to /etc/sift-io
Copy the sites/template folder to sites/`hostname`
Copy the new firewall configuration file to sites/`hostname`/firewall.io
Copy etc/template/etc-init.d-iptables to /etc/init.d/iptables
Link site to sites/`hostname`
In sites/`hostname` configure Makefile settings and flags
In sites/`hostname` run make clean ; make
Run /etc/init.d/iptables restart (if you are using SysV init scripts)
For other examples, look at some of the firewall configuration files in the sites/ folder.
SIFT is well designed. It provides an excellent framework for managing iptables rules in an intuitive and straightforward way. And although the architecture is based on the functionality of iptables, it adds a lot of assurance and ease of use in stead of writing iptables rules directly.
Note that packet filters offer only limited filtering possibilities. A packet filter does not look at the packet data inside a packet. This means that tunneling (masquerading as an allowed protocol, such as HTTP) can be used to bypass filtering rules. There are extensions to the Linux/GNU firewall tools that support such application level filtering (OSI layer 7), but these are based on pattern matching (just like most virus scanners). SIFT has only rudimentary support for OSI layer 7 filtering.