Linux has long had the capability for filtering 
packets, and it has come a long way since the early days in terms of both power 
and flexibility. The first generation of packet-filtering code was called 
ipfw (for "IP firewall") and provided basic filtering capability. Since 
it was somewhat inflexible and inefficient for complex configurations, ipfw 
is rarely used now. The second generation of IP filtering was called IP 
chains. It improved greatly on ipfw and is still in common use. The 
latest generation of filtering is called Netfilter and is manipulated with the 
iptables command. It is used 
exclusively with the 2.4.x and later series of kernels. Although Netfilter is the kernel component and 
iptables is the user-space configuration tool, these terms are often used 
interchangeably.
An important concept in Netfilter is the chain , which consists of a list of rules that 
are applied to packets as they enter, leave, or traverse through the system. The 
kernel defines three chains by default, but new chains of rules can be specified 
and linked to the predefined chains. The INPUT chain applies to packets that are 
received and are destined for the local system, and the OUTPUT chain applies to packets that are 
transmitted by the local system. Finally, the FORWARD chain applies whenever a packet will be 
routed from one network interface to another through the system. It is used 
whenever the system is acting as a packet router or gateway, and applies to 
packets that are neither originating from nor destined for this system.
The iptables command is used to make changes to 
the Netfilter chains and rulesets. You can create new chains, delete chains, 
list the rules in a chain, flush chains (that is, remove all rules from a 
chain), and set the default action for a chain. iptables also allows 
you to insert, append, delete, and replace rules in a chain.
Before we get started with some example rules, it's important 
to set a default behavior for all the chains. To do this we'll use the -P 
command-line switch, which stands for "policy":
# iptables -P INPUT DROP # iptables -P FORWARD DROP
This will ensure that only those packets covered by subsequent 
rules that we specify will make it past our firewall. After all, with the 
relatively small number of services that will be provided by the network, it is 
far easier to explicitly specify all the types of traffic that we want to allow, 
rather than all the traffic that we don't. Note that a default policy was not 
specified for the OUTPUT chain; this is because we want to allow 
traffic to proceed out of the firewall itself in a normal manner.
With the default policy set to DROP, we'll specify 
what is actually allowed. Here's where we'll need to figure out what services 
will have to be accessible to the outside world. For the rest of these examples, 
we'll assume that eth0 is the external interface on our firewall and 
that eth1 is the internal one. Our network will contain a web server 
(192.168.1.20), a mail 
server (192.168.1.21), 
and a DNS server (192.168.1.18)—a fairly minimal setup for a self-managed 
Internet presence.
# iptables -P INPUT -i lo -j ACCEPT # iptables -P OUTPUT -o lo -j ACCEPT
Now let's construct some rules to allow this traffic through. 
First, we'll make a rule to allow traffic on TCP port 80—the standard port for 
web servers—to pass to the web server unfettered by our firewall:
# iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.20 --dport 80 -j ACCEPT
And now for the mail server, which uses TCP port 25 for 
SMTP:
# iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.21 --dport 25 -j ACCEPT
Additionally, we might want to allow remote POP3, IMAP, and 
IMAP+SSL access as well:
- POP3
 # iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.21 --dport 110 -j ACCEPT
- IMAP
 # iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.21 --dport 143 -j ACCEPT
- IMAP+SSL
 # iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.21 --dport 993 -j ACCEPT
Unlike the other services, DNS can use both TCP and UDP port 
53:
# iptables -A FORWARD -m state --state NEW -p tcp \ -d 192.168.1.21 --dport 53 -j ACCEPT
Since we're using a default deny policy, it makes it slightly 
more difficult to use UDP for DNS. This 
is because our policy relies on the use of state tracking rules, and since UDP 
is a stateless protocol, there is no way to track it. In this case, we can 
configure our DNS server either to use only TCP, or to use a UDP source port of 
53 for any response that it sends back to clients that were using UDP to query 
the nameserver.
If the DNS server is configured to respond to clients using UDP 
port 53, we can allow this traffic through with the following two rules:
# iptables -A FORWARD -p udp -d 192.168.1.18 --dport 53 -j ACCEPT # iptables -A FORWARD -p udp -s 192.168.1.18 --sport 53 -j ACCEPT
The first rule allows traffic into our network destined for the 
DNS server, and the second rule allows responses from the DNS server to leave 
the network.
You may be wondering 
what the -m state and --state arguments are about. These two 
options allow us to use Netfilter's stateful packet-inspection engine. Using 
these options tells Netfilter that we want to allow only new connections to the 
destination IP and port pairs that we have specified. When these rules are in 
place, the triggering packet is accepted and its information is entered into a 
state table.
Now we can specify that we want to allow any outbound traffic 
that is associated with these connections by adding a rule like this:
# iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
The only thing left now is to allow traffic from machines 
behind the firewall to reach the outside world. To do this, we'll use a rule 
like the following:
# iptables -A FORWARD -m state --state NEW -i eth1 -j ACCEPT
This rule enters any outbound connections from the internal 
network into the state table. It works by matching packets coming into the 
internal interface of our firewall that are creating new connections. If we were 
setting up a firewall that had multiple internal interfaces, we could have used 
a Boolean NOT operator on the external interface (e.g., -i ! 
eth0). Now any traffic that comes into the firewall through the external 
interface that corresponds to an outbound connection will be accepted by the 
preceding rule, because this rule will have put the corresponding connection 
into the state table.
In these examples, the 
order in which the rules were entered does not really matter. Since we're 
operating with a default DENY policy, all our rules have an 
ACCEPT target. However, if we had specified targets of DROP or 
REJECT as arguments to the -j option, then we would have to 
take a little extra care to ensure that the order of those rules would result in 
the desired effect. Remember that the first rule that matches a packet is always 
triggered as the rule chains are traversed, so rule order can sometimes be 
critically important.
It should also be noted that rule order can have a performance 
impact in some circumstances. For example, the rule shown earlier that matches 
ESTABLISHED and RELATED states should be specified before any 
of the other rules, since that particular rule will be matched far more often 
than any of the rules that will match only on new connections. By putting that 
rule first, it will prevent any packets that are already associated with a 
connection from having to traverse the rest of the rule chain before finding a 
match.
To complete our firewall configuration, we'll want to enable 
packet forwarding. Run this command:
# echo 1 > /proc/sys/net/ipv4/ip_forward
This tells the kernel to forward packets between interfaces 
whenever appropriate. To have this done automatically at boot time, add the 
following line to /etc/sysctl.conf:
net.ipv4.ip_forward=1
If your system doesn't support /etc/sysctl.conf, you can 
put the preceding echo command in one of your startup rc scripts, such 
as /etc/rc.local. Another useful kernel parameter is rp_filter, 
which helps prevent IP spoofing. This enables source address verification by 
checking that the IP address for any given packet has arrived on the expected 
network interface. 
This can be enabled by running the following command:
# echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
Much like how we enabled IP forwarding, we can also enable 
source address verification by editing /etc/sysctl.conf on systems that 
support it, or else put the changes in your rc.local. To enable 
rp_filter in your sysctl.conf, add the following line:
net.ipv4.conf.all.rp_filter=1
To save all of our 
rules, we can either write all of our rules to a shell script or use our Linux 
distribution's particular way of saving them. 
We can do this in Red Hat by 
running the following command:
# /sbin/service iptables save
This will save all currently active filter rules to 
/etc/sysconfig/iptables. To achieve the same effect under Debian, edit 
/etc/default/iptables and set enable_iptables_initd=true.
After doing this, run the following command:
# /etc/init.d/iptables save_active
When the machine reboots, your iptables configuration will be automatically 
restored.
Happy Hacking!! 
No comments:
Post a Comment