Exposing any system, no matter how briefly, to an untrusted network is suicidal. A firewall is absolutely vital, and fortunately, the Linux world offers an excellent free firewall utility in netfilter/iptables. Carla Schroder takes a deeper look at iptables with additional rules and scripts for basic firewalling and sharing Internet connections.
Last week in Part 1 we began uncovering some of the mysteries of tables and chains, and how to build iptables rules. This week we will dig more into writing rules for basic firewalling, sharing an Internet connection, and scripting.
Paying for Our SYNs
We can't close off all ports; that will shut us off completely. We also can't just specify that certain ports will remain open, since it's impossible to predict which ports non-service programs will grab. And simply allowing traffic destined for specific ports does nothing to prevent malicious bits from waltzing right on in. So what exactly can we do to set up an effective rule that allows the good guys to pass through while preventing the bad ones from accessing our network?
For starters, we can take advantage of the syn flag set to prevent unauthorized access. While iptables examines only headers, not payload, it still does a lot of useful packet analysis based on the headers. For example, when Web surfing, a request goes from your PC to a web server out there somewhere. The web server then responds and sends packets back to you, grabbing the first convenient ephemeral (temporary) port on your system. Other than responding to your request, the server has no reason whatsoever to be sending traffic your way. We can take advantage of this by setting up a rule that blocks all incoming TCP connections that are not initiated by your system:
# iptables -t filter -A INPUT -i eth0 -p tcp --syn -j DROP
-i names the network interface, -p names which protocol, and --syn means TCP packets with the syn flag set. This also illustrates the importance of understanding TCP/IP. SYN is used to initiate a TCP connection. If you're not running any servers on your end, there's no reason for anyone to be sending you SYN packets.
At this point, someone usually wails, "Why can't it be EASY?" Yes, there are easier ways to build firewalls. There are nice hardware widgets as well as software utilities for constructing rulesets (see Resources), but Grasshopper, you know as well as I do, the easy way is not always the best way. And if an old fossil like me can figure this stuff out, anyone can.
Stateful Packet Inspection
The previous example rule looks at each packet individually, rather than in context, and relies on the information in the header. If everyone were truthful and benevolent, this would be enough. (Heck, if everyone were truthful and benevolent, we wouldn't need firewalls in the first place, would we?) iptables inspects the source and destination IP addresses, the source and destination ports, the sequence numbers of incoming packets, the TCP sequencing information, and the status from the header flags (SYN, ACK, FIN, RST, etc.). In other words, it tracks entire connection sessions, making filtering decisions in context.
Page 2: Sharing an Internet Connection
Sharing an Internet Connection
Network address translation/IP masquerading allows sharing a single Internet connection among several hosts -- a mixed LAN with Linux and Windows systems, for example. Assume a firewall box with two NICs and a static, routable IP address. eth0 is the "public" NIC, eth1 the "private." In other words, eth0 is assigned the static, routable IP, while eth1 is assigned a private, non-routable IP, and belongs to the LAN subnet. We need to add chains to the nat and filter tables:
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# iptables -t filter -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -t filter -A FORWARD -i eth1 -o eth0 -j ACCEPT
This illustrates the great value of stateful packet inspection. Notice how only incoming packets that belong to an existing connection are allowed. All packets from the LAN headed outbound are allowed to pass. (Note: filter is the default table; it is not necessary to explicitly name it. Many iptables examples leave it out.) The first rule makes all outgoing traffic appear as though it comes only from the firewall machine, with no indication there is an entire LAN lurking behind it.
This example sets the default policies for the FORWARDand POSTROUTING chains. It is important to have a default POSTROUTING DROP policy when using masquerading; otherwise, it is possible for a malicious user to tunnel through your gateway and masquerade their own identity.
# iptables -t filter -P FORWARD DROP
# iptables -t nat -P POSTROUTING DROP
This example is for dialup connections, with dynamically-assigned IPs:
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
A popular way to pass time is to engage in arguments about whether it is better to put servers behind firewalls, or outside of them. If you choose to put them behind your firewall, iptables needs to know where to pass the packets:
# iptables -t nat -A PREROUTING -i eth0 -p tcp -dport 80 -j DNAT -to 192.168.0.10:80
# iptables -t nat -A PREROUTING -i eth0 -p tcp -dport 25 -j DNAT -to 192.168.0.11:25
Page 3: Scripting
So far, all the examples have been run from the command line. This is a good way to test new rules. Once they are working to your satisfaction, preserve them in a script. This sample is not a complete script, though, as it only illustrates using variables and provides additional sample rules.
#Any kernel modules that need to be loaded go here
#IP forwarding is usually disabled in the kernel, by default. To enable it:
echo "1" > /proc/sys/net/ipv4/ip_forward
#Sers with dynamically assigned IPs need this
echo "1" > /proc/sys/net/ipv4/ip_dynaddr
###Every time this script is restarted, it is a good idea to flush all rules and start over
#Many tutorials recommend setting OUTPUT to DROP. This is very restrictive, so
#do what suits your needs
$IPTABLES -P INPUT DROP
$IPTABLES -F INPUT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -F OUTPUT
$IPTABLES -P FORWARD DROP
$IPTABLES -F FORWARD
$IPTABLES -F -t nat
###Random useful rule examples
#Allow ssh connections inside the LAN only
$IPTABLES -A INPUT -s LAN_NET -p tcp --destination-port ssh -j ACCEPT
#Must enable loopback!
$IPTABLES -A INPUT -i lo -p all -j ACCEPT
$IPTABLES -A OUTPUT -o lo -p all -j ACCEPT
###Foil source IP spoofing; drop incoming packets that claim to be from us,
#and drop outgoing packets that are not from us
$IPTABLES -A INPUT -i $IFACE -s $LAN_NET -j DROP
$IPTABLES -A OUTPUT -o $IFACE -s ! $LAN_NET -j DROP
###Some outgoing traffic must be restricted, to
#foil spyware and trojans from phoning home
$IPTABLES -A OUTPUT -o eth0 -p tcp -dport 31337 -j DROP
$IPTABLES -A OUTPUT -o eth0 -p tcp -sport 31337 -j DROP
###Other good ports to block include 31335, 27444, 27665, 20034 NetBus, 9704, 137-139 (smb)
#...etc.... it may be easier to OUTPUT DROP and then define what is allowed!
Big Fat Warning
We have used only tcp in our examples to this point, but don't forget there are UDP and ICMP packets to contend with as well. In other words, by no means is this a complete firewall tutorial! Hopefully, you now understand the basic concepts and terminology. If you are new to iptables, I recommend starting with some serious TCP/IP study, followed by a review of Oskar Andreasson's wonderful iptables tutorial.
iptables Tutorial 1.1.19 by Oskar Andreasson
Netfilter/iptables home page - includes downloads, documentation, and mail lists
LinuxGuruz - offers a mondo collection of iptables scripts
Building Secure Servers with Linux by Michael D. Bauer
See All Articles by Columnist Carla Schroder