We will include some brief examples. Our rule of thumb will be to deny everything as the default policy, then open up just what we need. We'll try to keep this as simple as possible since it can be an involved and complex topic, and just stick to some of the most basic concepts. See the Links section for further reading on this topic.
If constructing your own ipchains or iptables firewall rules seems a bit daunting, there are various sites that can automate the process. See the Links section. Also the included examples may be used as a starting point. And your distribution may be including a utility of some kind for generating a firewall script. This may be adequate, but it is still recommended to know the proper syntax and how the various mechanisms work as such tools rarely do more than a few very simple rules.
Various examples are given below. These are presented for illustrative purposes to demonstrate some of the concepts being discussed here. While they might also be useful as a starting point for your own script, please note that they are not meant to be all encompassing. You are strongly encouraged to understand how the scripts work, so you can create something even more tailored for your own situation. The example scripts are just protecting inbound connections to one interface (the one connected to the Internet). This may be adequate for many simple home type situations, but, conversely, this approach is not adequate for all situations! |
#!/bin/sh # # ipchains.sh # # An example of a simple ipchains configuration. # # This script allows ALL outbound traffic, and denies # ALL inbound connection attempts from the outside. # ################################################################### # Begin variable declarations and user configuration options ###### # IPCHAINS=/sbin/ipchains # This is the WAN interface, that is our link to the outside world. # For pppd and pppoe users. # WAN_IFACE="ppp0" WAN_IFACE="eth0" ## end user configuration options ################################# ################################################################### # The high ports used mostly for connections we initiate and return # traffic. LOCAL_PORTS=`cat /proc/sys/net/ipv4/ip_local_port_range |cut -f1`:\ `cat /proc/sys/net/ipv4/ip_local_port_range |cut -f2` # Any and all addresses from anywhere. ANYWHERE="0/0" # Let's start clean and flush all chains to an empty state. $IPCHAINS -F # Set the default policies of the built-in chains. If no match for any # of the rules below, these will be the defaults that ipchains uses. $IPCHAINS -P forward DENY $IPCHAINS -P output ACCEPT $IPCHAINS -P input DENY # Accept localhost/loopback traffic. $IPCHAINS -A input -i lo -j ACCEPT # Get our dynamic IP now from the Inet interface. WAN_IP will be our # IP address we are protecting from the outside world. Put this # here, so default policy gets set, even if interface is not up # yet. WAN_IP=`ifconfig $WAN_IFACE |grep inet |cut -d : -f 2 |cut -d \ -f 1` # Bail out with error message if no IP available! Default policy is # already set, so all is not lost here. [ -z "$WAN_IP" ] && echo "$WAN_IFACE not configured, aborting." && exit 1 # Accept non-SYN TCP, and UDP connections to LOCAL_PORTS. These are # the high, unprivileged ports (1024 to 4999 by default). This will # allow return connection traffic for connections that we initiate # to outside sources. TCP connections are opened with 'SYN' packets. $IPCHAINS -A input -p tcp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS ! -y -j ACCEPT # We can't be so selective with UDP since that protocol does not # know about SYNs. $IPCHAINS -A input -p udp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS -j ACCEPT ## ICMP (ping) # # ICMP rules, allow the bare essential types of ICMP only. Ping # request is blocked, ie we won't respond to someone else's pings, # but can still ping out. $IPCHAINS -A input -p icmp --icmp-type echo-reply \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT $IPCHAINS -A input -p icmp --icmp-type destination-unreachable \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT $IPCHAINS -A input -p icmp --icmp-type time-exceeded \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT ################################################################### # Set the catchall, default rule to DENY, and log it all. All other # traffic not allowed by the rules above, winds up here, where it is # blocked and logged. This is the default policy for this chain # anyway, so we are just adding the logging ability here with '-l'. # Outgoing traffic is allowed as the default policy for the 'output' # chain. There are no restrictions on that. $IPCHAINS -A input -l -j DENY echo "Ipchains firewall is up `date`." ##-- eof ipchains.sh |
See the ipchains man page for a full explanation of syntax. The important ones we used here are:
-A input: Adds a rule to the "input" chain. The default chains are input, output, and forward.
-p udp: This rule only applies to the "UDP" "protocol". The -p option can be used with tcp, udp or icmp protocols.
-i $WAN_IFACE: This rule applies to the specified interface only, and applies to whatever chain is referenced (input, output, or forward).
-s <IP address> [port]: This rule only applies to the source address as specified. It can optionally have a port (e.g. 22) immediately afterward, or port range, e.g. 1023:4999.
-d <IP address> [port]: This rule only applies to the destination address as specified. Also, it may include port or port range.
-l : Any packet that hits a rule with this option is logged (lower case "L").
-j ACCEPT: Jumps to the "ACCEPT" "target". This effectively terminates this chain and decides the ultimate fate for this particular packet, which in this example is to "ACCEPT" it. The same is true for other -j targets like DENY.
By and large, the order in which command line options are specified is not significant. The chain name (e.g. input) must come first though.
Remember in Step 1 when we ran netstat, we had both X and print servers running among other things. We don't want these exposed to the Internet, even in a limited way. These are still happily running on bigcat, but are now safe and sound behind our ipchains based firewall. You probably have other services that fall in this category as well.
The above example is a simplistic all or none approach. We allow all our own outbound traffic (not necessarily a good idea), and block all inbound connection attempts from outside. It is only protecting one interface, and really just the inbound side of that interface. It would more than likely require a bit of fine tuning to make it work for you. For a more advanced set of rules, see the Appendix. And you might want to read http://tldp.org/HOWTO/IPCHAINS-HOWTO.html.
Whenever you have made changes to your firewall, you should verify its integrity. One step to make sure your rules seem to be doing what you intended, is to see how ipchains has interpreted your script. You can do this by opening your xterm very wide, and issuing the following command:
# ipchains -L -n -v | less |
The output is grouped according to chain. You should also find a way to scan yourself (see the Verifying section below). And then keep an eye on your logs to make sure you are blocking what is intended.
Here is the same script as above, revised for iptables:
#!/bin/sh # # iptables.sh # # An example of a simple iptables configuration. # # This script allows ALL outbound traffic, and denies # ALL inbound connection attempts from the Internet interface only. # ################################################################### # Begin variable declarations and user configuration options ###### # IPTABLES=/sbin/iptables # Local Interfaces # This is the WAN interface that is our link to the outside world. # For pppd and pppoe users. # WAN_IFACE="ppp0" WAN_IFACE="eth0" # ## end user configuration options ################################# ################################################################### # Any and all addresses from anywhere. ANYWHERE="0/0" # This module may need to be loaded: modprobe ip_conntrack_ftp # Start building chains and rules ################################# # # Let's start clean and flush all chains to an empty state. $IPTABLES -F # Set the default policies of the built-in chains. If no match for any # of the rules below, these will be the defaults that IPTABLES uses. $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT ACCEPT $IPTABLES -P INPUT DROP # Accept localhost/loopback traffic. $IPTABLES -A INPUT -i lo -j ACCEPT ## ICMP (ping) # # ICMP rules, allow the bare essential types of ICMP only. Ping # request is blocked, ie we won't respond to someone else's pings, # but can still ping out. $IPTABLES -A INPUT -p icmp --icmp-type echo-reply \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT $IPTABLES -A INPUT -p icmp --icmp-type destination-unreachable \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT $IPTABLES -A INPUT -p icmp --icmp-type time-exceeded \ -s $ANYWHERE -i $WAN_IFACE -j ACCEPT ################################################################### # Set the catchall, default rule to DENY, and log it all. All other # traffic not allowed by the rules above, winds up here, where it is # blocked and logged. This is the default policy for this chain # anyway, so we are just adding the logging ability here with '-j # LOG'. Outgoing traffic is allowed as the default policy for the # 'output' chain. There are no restrictions on that. $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A INPUT -m state --state NEW -i ! $WAN_IFACE -j ACCEPT $IPTABLES -A INPUT -j LOG -m limit --limit 30/minute --log-prefix "Dropping: " echo "Iptables firewall is up `date`." ##-- eof iptables.sh |
# Accept non-SYN TCP, and UDP connections to LOCAL_PORTS. These are the high, # unprivileged ports (1024 to 4999 by default). This will allow return # connection traffic for connections that we initiate to outside sources. # TCP connections are opened with 'SYN' packets. We have already opened # those services that need to accept SYNs for, so other SYNs are excluded here # for everything else. $IPCHAINS -A input -p tcp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS ! -y -j ACCEPT # We can't be so selective with UDP since that protocol does not know # about SYNs. $IPCHAINS -A input -p udp -s $ANYWHERE -d $WAN_IP $LOCAL_PORTS -j ACCEPT |
There are many, many features of iptables that are not touched on here. For more reading on the Netfilter project and iptables, see http://netfilter.samba.org. And for a more advanced set of rules, see the Appendix.
Below is a small snippet from a typical inetd.conf file:
# Pop and imap mail services et al # #pop-2 stream tcp nowait root /usr/sbin/tcpd ipop2d #pop-3 stream tcp nowait root /usr/sbin/tcpd ipop3d #imap stream tcp nowait root /usr/sbin/tcpd imapd # |
ALL: ALL |
Now let's open up just the services we need, as restrictively as we can, with a brief example:
ALL: 127.0.0.1 sshd,ipop3d: 192.168.1. sshd: .myworkplace.com, hostess.mymomshouse.com |
As mentioned, xinetd is an enhanced inetd . It has much of the same functionality, with some notable enhancements. One is that tcpwrappers support can be compiled in, eliminating the need for explicit references to tcpd. Which means /etc/hosts.allow and /etc/hosts.deny are automatically in effect. Don't assume this is the case though. A little testing, then viewing the logs should be able to tell you whether tcpwrappers support is automatic or not.
Some of xinetd's other enhancements: specify IP address to listen on, which is a very effective method of access control; limit the rate of incoming connections and the total number of simultaneous connections; limit services to specific times of day. See the xinetd and xinetd.conf man pages for more details.
The syntax is quite different though. An example from /etc/xinetd.d/tftp:
service tftp { socket_type = dgram bind = 192.168.1.1 instances = 2 protocol = udp wait = yes user = nobody only_from = 192.168.1.0 server = /usr/sbin/in.tftpd server_args = /tftpboot disable = no } |
Notice the bind statement. We are only listening on, or "binding" to, the private, LAN interface here. No outside connections can be made since the outside port is not even opened. We are also only accepting connections from 192.168.1.0, our LAN. For xinetd's purposes, this denotes any IP address beginning with "192.168.1". Note that the syntax is different from inetd. The server statement in this case is the tftp daemon, in.tftpd. Again, this assumes that libwrap/tcpwrappers support is compiled into xinetd. The user running the daemon will be "nobody". Yes, there is a user account called "nobody", and it is wise to run such daemons as non-root users whenever possible. Lastly, the disable statement is xinetd's way of turning services on or off. In this case, it is "on". This is on here only as an example. Do NOT run tftp as a public service as it is unsafe.
Portsentry works quite differently than the other tools discussed so far. Portsentry does what its name implies -- it guards ports. Portsentry is configured with the /etc/portsentry/portsentry.conf file.
Unlike the other applications discussed above, it does this by actually becoming the listening server on those ports. Kind of like baiting a trap. Running netstat -taup as root while portsentry is running, will show portsentry as the LISTENER on whatever ports portsentry is configured for. If portsentry senses a connection attempt, it blocks it completely. And then goes a step further and blocks the route to that host to stop all further traffic. Alternately, ipchains or iptables can be used to block the host completely. So it makes an excellent tool to stop port scanning of a range of ports.
But portsentry has limited flexibility as to whether it allows a given connection. It is pretty much all or nothing. You can define specific IP addresses that it will ignore in /etc/portsentry/portsentry.ignore. But you cannot allow selective access to individual ports. This is because only one server can bind to a particular port at the same time, and in this case that is portsentry itself. So it has limited usefulness as a stand-alone firewall. As part of an overall firewall strategy, yes, it can be quite useful. For most of us, it should not be our first line of defense, and we should only use it in conjunction with other tools.
Suggestion on when portsentry might be useful:
As a second layer of defense, behind either ipchains or iptables. Packet filtering will catch the packets first, so that anything that gets to portsentry would indicate a misconfiguration. Do not use in conjunction with inetd services -- it won't work. They will butt heads.
As a way to catch full range ports scans. Open a pinhole or two in the packet filter, and let portsentry catch these and re-act accordingly.
If you are very sure you have no exposed public servers at all, and you just want to know who is up to what. But do not assume anything about what portsentry is protecting. By default it does not watch all ports, and may even leave some very commonly probed ports open. So make sure you configure it accordingly. And make sure you have tested and verified your set up first, and that nothing is exposed.
All in all, the packet filters make for a better firewall.
The dictionary defines "proxy" as "the authority or power to act on behalf of another". This pretty well describes software proxies as well. It is an intermediary in the connection path. As an example, if we were using a web proxy like "squid" (http://www.squid-cache.org/), every time we browse to a web site, we would actually be connecting to our locally running squid server. Squid in turn, would relay our request to the ultimate, real destination. And then squid would relay the web pages back to us. It is a go-between. Like "firewalls", a "proxy" can refer to either a specific application, or a dedicated server which runs a proxy application.
Proxies can perform various duties, not all of which have much to do with security. But the fact that they are an intermediary, makes them a good place to enforce access control policies, limit direct connections through a firewall, and control how the network behind the proxy looks to the Internet. So this makes them strong candidates to be part of an overall firewall strategy. And, in fact, are sometimes used instead of packet filtering firewalls. Proxy based firewalls probably make more sense where many users are behind the same firewall. And it probably is not high on the list of components necessary for home based systems.
Configuring and administering proxies can be complex, and is beyond the scope of this document. The Firewall and Proxy Server HOWTO, http://tldp.org/HOWTO/Firewall-HOWTO.html, has examples of setting up proxy firewalls. Squid usage is discussed at http://squid-docs.sourceforge.net/latest/html/book1.htm
options { directory "/var/named"; listen-on { 127.0.0.1; 192.168.1.1; }; version "N/A"; }; |
Recent versions of sendmail can be told to listen only on specified addresses:
# SMTP daemon options O DaemonPortOptions=Port=smtp,Addr=127.0.0.1, Name=MTA |
dnl This changes sendmail to only listen on the loopback device 127.0.0.1 dnl and not on any other network devices. DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA') |
SAMBA connections can be restricted in smb.conf:
bind interfaces = true interfaces = 192.168.1. 127. hosts allow = 192.168.1. 127. |
The CUPS print daemon can be told where to listen for connections. Add to /etc/cups/cupsd.conf:
Listen 192.168.1.1:631 |
This will only open a port at the specified address and port number.
So how to do this? There are several things you can do.
And then, scan yourself. nmap is the scanning tool of choice and may be available via your distribution , or from http://www.insecure.org/nmap/nmap_download.html. nmap is very flexible, and essentially is a "port prober". In other words, it looks for open ports, among other things. See the nmap man page for details.
If you do run nmap against yourself (e.g. nmap localhost), this should tell you what ports are open -- and visible locally only! Which hopefully by now, is quite different from what can be seen from the outside. So, scan yourself, and then find a trusted friend, or site (see the Links section), to scan you from the outside. Make sure you are not violating your ISPs Terms of Service by port scanning. It may not be allowed, even if the intentions are honorable. Scanning from outside is the best way to know how the rest of the world sees you. This should tell you how well that firewall is working. See the nmap section in the Appendix for some examples on nmap usage.
One caveat on this: some ISPs may filter some ports, and you will not know for sure how well your firewall is working. Conversely, they make it look like certain ports are open by using web, or other, proxies. The scanner may see the web proxy at port 80 and mis-report it as an open port on your system.
Another option is to find a website that offers full range testing. http://www.hackerwhacker.com is one such site. Make sure that any such site is not just scanning a relatively few well known ports.
Repeat this procedure with every firewall change, every system upgrade or new install, and when any key components of your system changes.
You may also want to enable logging all the denied traffic. At least temporarily. Once the firewall is verified to be doing what you think it should, and if the logs are hopelessly overwhelming, you may want to disable logging.
If relying on portsentry at all, please read the documentation. Depending on your configuration it will either drop the route to the scanner, or implement a ipchains/iptables rule doing the same thing. Also, since it "listens" on the specified ports, all those ports will show as "open". A false alarm in this case.
A nice log entry analyzer for ipchains and iptables from Manfred Bartz: http://www.logi.cc/linux/NetfilterLogAnalyzer.php3. What does all that stuff mean anyway?
LogSentry (formerly logcheck) is available from http://www.psionic.org/products/logsentry.html, the same group that is responsible for portsentry. LogSentry is an all purpose log monitoring tool with a flexible configuration, that handles multiple logs.
http://freshmeat.net/projects/firelogd/, the Firewall Log Daemon from Ian Jones, is designed to watch, and send alerts on iptables or ipchains logs data.
http://freshmeat.net/projects/fwlogwatch/ by Boris Wesslowski, is a similar idea, but supports more log formats.
Let's take a quick look at where to run our firewall scripts from.
script /usr/local/bin/ipchains.sh |
This is a lot of information to digest at all at one time and expect anyone to understand it all. Hopefully this can used as a starting point, and used for future reference as well. The packet filter firewall examples can be used as starting points as well. Just use your text editor, cut and paste into a file with an appropriate name, and then run chmod +x against it to make it executable. Some minor editing of the variables may be necessary. Also look at the Links section for sites and utilities that can be used to generate a custom script. This may be a little less daunting.
Now we are done with Steps 1, 2 and 3. Hopefully by now you have already instituted some basic measures to protect your system(s) from the various and sundry threats that lurk on networks. If you haven't implemented any of the above steps yet, now is a good time to take a break, go back to the top, and have at it. The most important steps are the ones above.
A few quick conclusions...
"What is best iptables, ipchains, tcpwrappers, or portsentry?" The quick answer is that iptables can do more than any of the others. So if you are using a 2.4 kernel, use iptables. Then, ipchains if using a 2.2 kernel. The long answer is "it just depends on what you are doing and what the objective is". Sorry. The other tools all have some merit in any given situation, and all can be effective in the right situation.
"Do I really need all these packages?" No, but please combine more than one approach, and please follow all the above recommendations. iptables by itself is good, but in conjunction with some of the other approaches, we are even stronger. Do not rely on any single mechanism to provide a security blanket. "Layers" of protection is always best. As is sound administrative practices. The best iptables script in the world is but one piece of the puzzle, and should not be used to hide other system weaknesses.
"If I have a small home LAN, do I need to have a firewall on each computer?" No, not necessary as long as the LAN gateway has a properly configured firewall. Unwanted traffic should be stopped at that point. And as long as this is working as intended, there should be no unwanted traffic on the LAN. But, by the same token, doing this certainly does no harm. And on larger LANs that might be mixed platform, or with untrusted users, it would be advisable.