ipfwadm and ipchains
A simple, yet powerful packet filtering firewall
Packet filters are different from dynamic filters in a couple of ways. First of all, they are static. You give them rules and they use them literally, with no bending. No macros can be written to adapt to specific network content. In general, dropped packets are not logged, so you never know if you are under attack. ipfw and ipchains are the Linux version of a packet filter. ipfwadm and ipchains are a bit better than a number of packet filters - mainly because of its ability to log attacks based on certain filters you set up. This will give you a better grip on the status and security of your network utilizing syslogd.
It is also important that you set up tcp wrappers correctly - along with hosts.allow and hosts.deny. You may also wish to explore the free TIS-FWTK (firewall toolkit) which can be downloaded from the TIS ftp site after a short license agreement (shortly after generating this page - Network Associates changed their site layout and I have been unable to locate the license agreement and download for fw-tk). If you have already read the agreement, and agreed, you may pick the source and documentation here.
As a packet enters the machine, ipfwadm is consulted by first checking the input rules, then if it is to be routed the forward filters are checked, and finally the outbound filters. This is important to remember. If you are setting up a firewall, a packet must pass both the Incoming , the Forward and the Outbound filters to be passed along. The easiest way to accomplish this is to follow this simple strategy : Set Incoming to deny, Outbound to accept and Forward to accept. Then build your rules to allow specific incoming traffic, and deny unwanted forwarded traffic. This will ease the rule burden. The default policy is not consulted unless the packet does not match a rule. In other words, an incoming policy of accept does not mean that the rules are bypassed. Policy is consulted last.
A great deal of information can be gathered from executing /sbin/ipfwadm -h, or /sbin/ipchains -h, or by viewing the man page.
You start by defining the default policy for the filter....i.e. accept or deny. You generally deny everything first, then allow what you need. I tend to say 'accept' then specifically deny the bad stuff and log it (using -o under ipfwadm or -l under ipchains). The definitions at the top of the attached filters make it easier to understand what a rule is doing. That is important! Don't just blindly use these - go through, understand, and edit them heavily.
To execute the firewall at startup, I added the line "/etc/rc.d/rc.firewall" to the end of my /etc/rc.d/rc.local startup script file. I then created a new document (rc.firewall) that looks like the following script. I warn you - this is not a full firewall solution. It will give you some basic protection, but you must adapt it to fit your needs.
This ipfwadm filter has been written for use on a machine that acts as a router/DNS server between two large networks. For use under ipchains, you could change ipfwadm to ipfwadm-wrapper - utilizing a wonderful script that converts to ipchains. This script only allows DNS traffic, and specific access from pre-defined hosts. IP addresses have been changed to protect the innocent.
#!/bin/sh
#
# /etc/rc.d/rc.firewall, define the firewall configuration,
# invoked from rc.local. Linked from /etc/firewall.conf
PATH=/sbin:/bin:/usr/sbin:/usr/bin
# ====== SETUP
# Some definitions for easy maintenance.
INTERNNET="192.168.50.0/29"; # Subnetted local lan segment
EXTERNNET="172.160.50.0/24"; # Subnetted external segment
IFEXTERN="172.16.50.1"; # External adapter
IFINTERN="192.168.50.1"; # Physical local ethernet
LOCALHOST="127.0.0.1"; # ---Does not change
ANYWHERE="any/0"; # ---Does not change
UNPRIVPORTS="1024:65535"; # ---Does not change
# ====== BASIC RULES
# Set a clean slate
ipfwadm -I -f
ipfwadm -O -f
ipfwadm -F -f
# Generic packet policy
ipfwadm -I -p accept
ipfwadm -O -p accept
ipfwadm -F -p accept
# Refuse spoofed packets and log them
ipfwadm -I -a deny -V $IFEXTERN -S $INTERNNET -o
ipfwadm -I -a deny -V $IFINTERN -S $EXTERNNET -o
# Allow DNS Requests
ipfwadm -I -a accept -P udp -D $IFINTERN 53 -S $ANYWHERE
# Allow DNS Zone transfer from one host
ipfwadm -I -a accept -P tcp -D $IFINTERN 53 -S 192.168.50.10
# Allow telnet from certain hosts
ipfwadm -I -a accept -P tcp -D $IFINTERN 23 -S 192.168.50.15
ipfwadm -I -a accept -P tcp -D $IFEXTERN 23 -S 200.200.50.1
# Allow incoming syslog
ipfwadm -I -a accept -P udp -D $IFINTERN 514 -S 192.168.50.15
# Allow time sync
ipfwadm -I -a accept -P udp -D $IFINTERN 37 -S $ANYWHERE
ipfwadm -I -a accept -P udp -D $IFINTERN 123 -S 192.168.50.15 123
# Deny any potentially hazardous low port connections
ipfwadm -I -a deny -P tcp -D $IFINTERN 1:1023 -o
ipfwadm -I -a deny -P udp -D $IFINTERN 1:1023 -o
ipfwadm -I -a deny -P tcp -D $IFEXTERN 1:1023 -o
ipfwadm -I -a deny -P udp -D $IFEXTERN 1:1023 -o
# ======END OF FILTERS
To better understand what everything in the filter, you may wish to review this section on the ipfwadm -h output :
ipfwadm 2.3.0, 1996/07/30
Usage: ipfwadm -A [direction] command [options] (accounting)
ipfwadm -F command [options] (forwarding firewall)
ipfwadm -I command [options] (input firewall)
ipfwadm -O command [options] (output firewall)
ipfwadm -M [-s | -l] [options] (masquerading entries)
ipfwadm -h (print this help information))
Commands:
-i [policy] insert rule (no policy for accounting rules)
-a [policy] append rule (no policy for accounting rules)
-d [policy] delete rule (no policy for accounting rules)
-l list all rules of this category
-z reset packet/byte counters of all rules of this category
-f remove all rules of this category
-p policy change default policy (accept/deny/reject)
-s tcp tcpfin udp
set masuerading timeout values
-c check acceptance of IP packet
Options:
-P protocol (either tcp, udp, icmp, or all)
-S address[/mask] [port ...]
source specification
-D address[/mask] [port ...]
destination specification
-V address network interface address
-W name network interface name
-b bidirectional match
-e extended output mode
-k match TCP packets only when ACK set
-m masquerade packets as coming from local host
-n numeric output of addresses and ports
-o turn on kernel logging for matching packets
-r [port] redirect packets to local port (transparent proxying)
-t and xor and/xor masks for TOS field
-v verbose mode
-x expand numbers (display exact values)
-y match TCP packets only when SYN set and ACK cleared
Here is a simple ipchains filter to get you started under the 2.2.x +
kernels. It was built for a home machine that uses diald to autodial my
ISP, and masquerade my home network. It assumes your external interface is
ppp0 and internal is eth0:
#!/bin/sh
#
# /etc/rc.d/rc.firewall, define the firewall configuration,
# invoked from rc.local. Linked from /etc/firewall.conf
PATH=/sbin/bin/usr/sbin/usr/bin# Set a clean slate
ipchains -F;
ipchains -X;# Generic packet policy
ipchains -P input ACCEPT
ipchains -P output ACCEPT
ipchains -P forward DENY# Masquerade
ipchains -A forward -i ppp0 -j MASQ# Allow local net
ipchains -A input -i eth0 -j ACCEPT# Allow external DNS replies
ipchains -A input -p udp --source-port 53 -i ppp0 -j ACCEPT# Allow incoming ping
ipchains -A input -p icmp -i ppp0 -j ACCEPT# Deny all incoming low port traffic
ipchains -A input -i ppp0 -p tcp --destination-port 1:1024 -j DENY -l
ipchains -A input -i ppp0 -p udp --destination-port 1:1024 -j DENY -l
You may also with to view the ipchains -h help screen output:
ipchains 1.3.9, 17-Mar-1999
Usage: ipchains -[ADC] chain rule-specification [options]
ipchains -[RI] chain rulenum rule-specification [options]
ipchains -D chain rulenum [options]
ipchains -[LFZNX] [chain] [options]
ipchains -P chain target [options]
ipchains -M [ -L | -S ] [options]
ipchains -h [icmp] (print this help information, or ICMP list)
Commands:
Either long or short options are allowed.
--add -A chain Append to chain
--delete -D chain Delete matching rule from chain
--delete -D chain rulenum
Delete rule rulenum (1 = first) from chain
--insert -I chain [rulenum]
Insert in chain as rulenum (default 1=first)
--replace -R chain rulenum
Replace rule rulenum (1 = first) in chain
--list -L [chain] List the rules in a chain or all chains
--flush -F [chain] Delete all rules in chain or all chains
--zero -Z [chain] Zero counters in chain or all chains
--check -C chain Test this packet on chain
--new -N chain Create a new user-defined chain
--delete-chain
-X chain Delete a user-defined chain
--policy -P chain target
Change policy on chain to target
--masquerade -M -L List current masqerading connections
--set -M -S tcp tcpfin udp
Set masquerading timeout values
Options:
--bidirectional -b insert two rules: one with -s & -d reversed
--proto -p [!] proto protocol: by number or name, eg. `tcp'
--source -s [!] address[/mask] [!] [port[:port]]
source specification
--source-port [!] [port[:port]]
source port specification
--destination -d [!] address[/mask] [!] [port[:port]]
destination specification
--destination-port [!] [port[:port]]
destination port specification
--icmp-type [!] typename specify ICMP type
--interface -i [!] name[+]
network interface name ([+] for wildcard)
--jump -j target [port]
target for rule ([port] for REDIRECT)
--mark -m [+-]mark number to mark on matching packet
--numeric -n numeric output of addresses and ports
--log -l turn on kernel logging for matching packets
--output -o [maxsize] output matching packet to netlink device
--TOS -t and xor and/xor masks for TOS field
--verbose -v verbose mode
--exact -x expand numbers (display exact values)
[!] --fragment -f match second or further fragments only
[!] --syn -y match TCP packets only when SYN set
[!] --version -V print package version.
Once you understand your firewall, you should test it. There are many great tools for checking open ports and scanning for problem areas. Once I had the ipchains filter (above) installed, I used strobe remotely to scan the dial-up machine. Everything was logged in syslog, and nothing got through that wasn't supposed to. I have provided a few common tools for you here.