>>>>>>>>>>>>>>>If you read nothing else, please read this<<<<<<<<<<<<<<<< This program offers an aid to creating firewall rules. It offers ABSOLUTELY NO intelligence in deciding what should be allowed or disallowed. It has ABSOLUTELY NO ability to understand your security policy and implement it. YOU are responsible for reviewing the rules and massaging them to fit your needs. While this documentation attempts to provide some general guidelines on how to use Mason, please remember: the author has no knowledge of what you want your firewall to do and has not tailored the documentation or program to specially fit your needs. If there is ever a discrepancy between your needs and the program output or your needs and the documentation, the program and/or documentation are _dead_ _wrong_. Copyleft: Mason interactively creates a Linux packet filtering firewall. Copyright (C) 1998 William Stearns This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author can also be reached at: William Stearns email: wstearns@pobox.com (preferred) web: http://www.pobox.com/~wstearns snail: 544 Winchester Place Colchester VT, 05446, USA This code is entirely owned by William Stearns (wstearns@pobox.com) and has no relation to any employer or employer sponsored project. ------------------------------ Mason ------------------------------ The Mason script interactively builds a (fire)wall on a Linux machine. For more details about how this is done, please read on for background, theory of operation, a quick start, and additional documentation on firewalls and firewall gotcha's. mason.txt and related documentation should have been installed to /usr/doc/mason-{version}/ . If they are missing or you would like to make sure you have the latest version, please go to http://www.pobox.com/~wstearns/mason/ . - Bill Stearns The impatient can find a "Quick Start" section near the end. Background and motivation: The built-in firewall features of the Linux kernel offer a powerful set of packet filtering features that can be used to build a firewall. The various pieces of available documentation provide an introduction on how to configure the firewall for simple setups, but can't possibly explain how to configure a firewall for more complex setups, including fine-grained allow and deny lists. This is especially obvious when trying to create a firewall with a default policy of deny. Someone looking to configure a linux firewall is simultaneously hit with the complexity of trying to understand the ipfwadm syntax, trying to understand the structure of TCP/IP connections, and trying to create and implement a security policy. No wonder firewalls are daunting! The Mason application attempts to handle the first two problems by dynamically creating the firewall based on the traffic flowing through it. For example, if you start up a telnet session through your firewall from a machine on your LAN to a machine out on the WAN while mason is running, mason will create all the rules necessary to allow this traffic. Conversely, if you're looking to block incoming NFS requests, simply launch mason, select a "deny" or "reject" policy, and make the NFS connection, and generalize the provided rules. When the firewall is restarted, voila! No more incoming NFS. Creating a firewall no longer requires understanding the ipfwadm syntax. Even novices can create a firewall under Linux. _HOWEVER_, creating a _good_ firewall _still_ requires some understanding of TCP/IP protocols and packet filtering. Many good books cover this. Check out O'Reilly and Associates (www.ora.com or www.oreilly.com) for some excellent general coverage of firewall designs. One last novice's mistake I'd like to see Mason users avoid is the false sense of security that a firewall can provide. _Truly_ securing a network requires _much_ more than simply filtering packets. The aforementioned books provide a great background in general security. Basic theory of operation: Before starting, if the user has some rules that he or she knows should be used in this machine, the user can implement them. As part of the process of running Mason, we'll add rules that log all other packets to /var/log/messages. The "tail" command is used to feed the log messages in this script. The script converts each log entry into the corresponding command necessary to allow that kind of traffic. In the previous telnet example, 6 different firewall rules would be created on the firewall, three for the original request packet, 3 for the response back from the server: pkt 1: Allow telnet request in from LAN pkt 1: Forward request through firewall pkt 1: Allow request to exit to WAN pkt 2: Allow telnet response back into firewall from WAN pkt 2: Forward response through system pkt 2: Allow response to exit back to the original machine on the LAN. All packets from 3 on are handled by these rules. There may be a short delay in the initial connection as the rules are created. The script creates the actual ipfwadm commands to accomodate the packet flow. When the command is executed the new rule is inserted at the head of the existing rules so that future packets of this type no longer reach the logging rule at the bottom. The rules are also echoed to the console so that you can see the rules as they are executed or redirect them to a file. I prefer the latter; this allows me to go back later to review the rules and massage them. I actually use the "tee" command in the Quick Start section to do both. If any of this is unclear, take a look at the Quick Start section which walks you through actually running it. It'll make more sense when you see it in action. Special considerations: Kernel: IP firewalling and firewall packet logging have to be compiled into the kernel. To see if IP firewalling is compiled into your kernel, type the command: /sbin/ipfwadm -F -l -e (while you're root) If you get "command not found", you're either not root or you haven't installed the ipfwadm package. See if it's included in your distribution. It's definitely included in RedHat 4.1 and higher. ipfwadm 2.3.0 has been around for a long time and is stable. If you get something like "/proc/net/ip_forward not found", your kernel does not support ipfwadm firewalling. One of the following three is true: - Your kernel is too old. It appears that linux firewalling switched from the old "ipfw" firewalling in 1.3.66, but some features require 2.0.0. - Your kernel is too new. Somewhere between 2.1.101 and 2.1.104 the kernel switched over from "ipfwadm" firewalling to "ipchains" firewalling. At some point I'll add a command line option to choose ipfwadm or ipchains. - You have the right version of the kernel, but firewalling is not enabled. You must recompile the kernel and turn on firewalling. See the HOWTO's at http://sunsite.unc.edu/linux/HOWTO to see how this is done. In particular, see the masquerading and kernel HOWTO's. To see if firewall packet logging is enabled in your kernel, type the following command: /sbin/ipfwadm -a deny -F -S 127.12.2.3/32 -o The "-o" at the end tells the kernel to log this particular packet type (one which should never show up). If your kernel does not support logging, I _think_ you would get an error. On the other hand, I've never had a kernel that has firewalling but does not have logging. The solution is the same - recompile your kernel to include both firewalling _and_ firewall packet logging. (If recompiling a kernel is too daunting, try my automated kernel builder, "buldkernel", which can be found at http://www.pobox.com/~wstearns/buildkernel/). DNS: If the firewall or one of the machines behind it is a DNS server, you have a situation where mason issues a steady flow of DNS requests to resolve the machine names and each DNS request requires a new rule, which in turn requires more DNS requests... ugh. There are a couple of ways around this: - Write the correct ipfwadm rules for DNS lookup for your particular setup and put them in place before running mason. - Use trusted external DNS servers, i.e. servers that do not have to resolve _through_ your firewall. This reduces the number of rules necessary to handle DNS to just a few. - Put the names of all relevant hosts in the namecache file (see below) or in /etc/hosts. Mason uses these files before going out to DNS to try to minimize the snowball effect when it occurs. - Comment out the DNS lookup code in Mason. At some point this will be command line configurable, but not quite yet. - Insert general rules for DNS in your rule set. If you're not sure what these should be, the following six rules should allow all DNS requests from anywhere to anywhere. Please note that depending on your security policy, this are very likely to be too general and should be reviewed. /sbin/ipfwadm -I -i accept -S 0/0 53 -P udp /sbin/ipfwadm -I -i accept -D 0/0 53 -P udp /sbin/ipfwadm -O -i accept -S 0/0 53 -P udp /sbin/ipfwadm -O -i accept -D 0/0 53 -P udp /sbin/ipfwadm -F -i accept -S 0/0 53 -P udp /sbin/ipfwadm -F -i accept -D 0/0 53 -P udp Note that I don't include _tcp_ dns zone transfers here. These transfers are generally rare and between a few machines. These are good candidates for having explicit rules added automatically by mason. Rule order: When a packet needs to be processed (at entry, forwarding, or exit), the firewall scans the existing list of rules to decide whether to allow, deny or reject the packet. As this scans stops at the first rule that matches the packet, the order in which your final firewall rules are executed can make a difference. This document only provides basic coverage of how to order your rules - sorry. The best place to find out more about this is in the O'Reilly and associates books. (If anyone would like to provide additional general guidelines as to how this is done, I would be glad to place them here with the appropriate disclaimers). Generalization: When a rule is created, it covers packet transfer between specific ports on specific machines. For example, here's a response packet from a specific FTP server (linux.kernel.org) to what is probably a machine on your LAN: /sbin/ipfwadm -i accept -W ppp0 -I -P tcp -S linux.kernel.org/32 ftp -D \ devel1.goober.net/32 1024:65535 # ftp/tcp If you wanted to also allow this machine to reach any other ftp server in the world, you might want to edit this rule and replace "linux.kernel.org/32" with "0.0.0.0/0" (remember that 0.0.0.0/0 is the equivalent of "anywhere" in an address field). If you simply wanted to allow more than one machine to get to linux.kernel.org, you could replace "-D devel1.goober.net/32" with "-D 210.134.12.0/24" (the fictitious network address block that covers the machines in question). This generalization could also be for protocols. If you wanted the users on devel1.goober.net to be able to reach linux.kernel.org with any protocol, simply remove the "ftp" keyword in the command. The port used at the goober.net end would still have to be one of the high ports (1024 to 65535), but they could talk to any port (ftp, smtp, http, telnet, etc.) at the linux.kernel.org end. The only generalization Mason does right now is the "high port" generalization. The connection that prompted this rule might have been, for example, port 1745 on devel1. As Mason didn't recognize 1745 as some special server, it assumed that the next connection might be from, say, port 1788. By using the entire range of high ports ("1024:65535" in the above rule), Mason uses a pretty standard approach to packet filtering to reduce the number of rules. If you follow the suggestion for sorting your newrules file in the Quick Start section, the file you'll be editing will have similar traffic types listed on consecutive lines. If you see 12 lines all with outgoing smtp rules that differ only in destination address; that's _probably_ a good hint that these could be replaced with a single rule identical to the others but with the destination address replaced with a network address specification appropriate for that destination. For 12 different machines on your lan, these might be replaced with something like "210.134.12.0/24". If these are all machines outside of any local LAN's, "0.0.0.0/0" might be appropriate. In the previous example, you'll probably see 12 other lines for _incoming_ smtp traffic, and maybe 12 more for forwarding these these packets. These, too, can be generalized, leaving just 3 rules instead of 36. To start, I'd suggest only trying to merge rules that differ in source address or differ in destination address. I would not suggest trying to merge almost identical rules like I just mentioned, but where some of the source addresses are on your LAN and some are not. I would also recommend that you think carefully about the ftp data rules (ones where both the source and destination ports are listed as 1024:65535). See "ftp" below for more background on why. Another good candidate for generalization is the IP adress used on a machine that connects via a dynamic PPP or slip address. If your ISP can tell you exactly what range of addresses you might use (say "the class C block '201.12.45.0'"), it would probably make sense to replace each instance of "dial-201.12.45.72.myisp.net" with "201.12.45.0/24" so that the rule still applies no matter what IP address you get when you connect. If they can't or won't tell you, it is _probably_ reasonable (though less safe) to use "0.0.0.0/0" instead of a specific block. You need to decide what's right for your setup. One other approach might be to go over your logs and see what addresses they've given you in the past and try to figure out what pool those addresses come. Router or end node: This program was originally intended for use on a traditional firewall - a packet filtering router (linux box that connects 2 or more networks through one or more interfaces). It works equally well on Linux boxes with only one interface. These could be workstations on a LAN, servers outside of your firewall, or even slip or ppp connected workstations. The number of interfaces and their type and speed are irrelevant to the firewall creation process. This would be great for locking down a web or mail server outside your firewall, for example. Start up Mason and make sure you make one of every kind of connection you want to that machine. Mason will create the corresponding rules. Generalize these and implement them with a default policy of "deny". _Only_ the connection types you specified will be allowed to that machine. The difficulty of setting up the rules has been the major impediment to this kind of hardened end node in the past. Now that Mason is here, there's no reason why every machine on your LAN can't have packet filtering enabled and active. Note that on an end node (Linux box with a single NIC connected to a single IP network) you should never see forwarding rules created - this makes sense if you think about it. You could technically create a firewall on a machine with only the loopback interface, but this would be more for instructional value about internal tcp connections than for any security goal. On the other hand, if you wanted to stop shell account users from getting to an internal Web server, you certainly could; just make sure you put in blocking rules for all interfaces, not just the loopback interface. Slow machines or fast nics: As a shell script, Mason is much less efficient at its work than a C app would be. On my 486sx-33, it can take a couple of seconds from the time the log entry is fed into it until the ipfwadm rule is implemented. If the system is slow, if it has a lot of packets traveling through it, or if it simply has a great deal of log file traffic it can take Mason a long time to catch up. If this is the case, start slow. Try one connection type at a time and give the system a chance to settle before you move on. In the step by step instructions below, I suggest turning on packet logging for input, forward, and output filters at the same time (see the three almost identical ipfwadm lines below with the "-o" at the end). If Mason is having trouble keeping up, you might want to start off with just one of those lines (say "input" or "-I"). Run Mason for a little while to build up the input rules. Then turn on the "forward" rules, etc. If you take this approach, make sure you run the same kinds of traffic through the system at every step. If you _know_ your system will be having a large number of connections from lots of different machines, you might want to run mason for a little while, stop it, generalize the rules, clear the firewall rules and restart with your new rules and restart mason. By going through this process a couple of times you can keep up with even heavily loaded machines or routers. On a mail server, for example, the first rule types you'll want to generalize would be the SMTP (tcp/25), pop-3 (tcp/110) and/or imap (tcp/143) rules. Active hacking while mason running: If at all possible, try to set up these rules in a controlled environment. Hook up your firewall to machines that simulate the routers and networks that will be used in its final location. It is not a good idea to create a firewall in an environment not completely under your control. If you must create the firewall rules in a live environment, be warned: Mason simply creates rules based on what traffic is passing through it. IT CANNOT DISTINGUISH BETWEEN THE TRAFFIC YOU'RE CREATING TO TEACH IT AND SOMEONE ACTIVELY TRYING TO HACK THROUGH YOUR FIREWALL. IF THIS HAPPENS, MASON WILL CREATE RULES THAT _SPECIFICALLY_ _ALLOW_ PEOPLE TO GET BACK IN LATER. _Please_ read and try to understand the rules before you put them to use in a production environment. (I hate all caps too, but the "boldface" button on my keyboard is jammed :-). The "hacker" mentioned above does not need to be a computer criminal in a far-off country looking to crash your machines. This individual could be someone in accounting that is (without malicious intent) connecting to an Internet IRC server, when this doesn't fit in the security policy you're trying to implement. If you don't read and understand the rules Mason spits out, you may very well leave an explicit opening for this user's future IRC use. One more time: Mason _does_ _not_ understand the traffic flowing through your firewall; it just creates the rules that you can later use to specifically allow or disallow this traffic. Masquerading: One of the common uses for Linux firewalling is to act not only as a packet filter but also as a masquerading host, allowing multiple machines to share a single IP address. In this setup, simply create the masquerading forwarding rule on the firewall before you run Mason. Mason will simply accept the forwarding specification you've made and create input and output rules around it. Mason is actually even more useful in this case as the packet rules are even more confusing when packets are being rewritten under you. See the masquerading HOWTO to see how this rule is created. It's actually quite easy to do... Offline and non-root creation: If you are especially cautious, you might not want Mason actively creating rules on your production server. Or maybe you think you've created a good firewall, but keep getting log messages and don't know how to keep your log files from filling your disk. Or perhaps your CPU can't keep up. Or maybe you just don't trust Mason's author (no offense taken :-). In all of the above circumstances, Mason can create the commands without actually being fed the log messages live. For example, if you have packet logging entries in /var/log/messages, try this: cat /var/log/messages | grep 'IP fw-' | mason The output can, of course, be tee'd, redirected to a file, piped to less, etc. "... | sort | uniq" can be useful too when you're not converting it live. Obviously, the source file can be one that has been transferred from another machine. There is one caveat to the offline approach. The specific case is when one has a "deny" or "reject" policy in place for the input logging rule. Let's say I try to telnet through the firewall. My packet arrives at the firewall, is stopped and logged (so Mason can successfully create the correct input rule later). The firewall never has a rule implemented that allows me to get any further than that, however, so there is never a log entry created for any of the remaining 5 packet checks. One way around this might be to use a policy of "accept" on your logging rules while you're creating /var/log/messages for later consumption by Mason. I'm not saying this is appropriate for you, but might be one way to handle this. Be warned; this can create very large log files as every packet passing through the system can create 6 log entries! One final use for this technique is creating the rules when you're not root. Simply edit the script to change DOCOMMAND="YES" to DOCOMMAND="NO" and the script will still output the appropriate ipfwadm commands but won't try to execute them, allowing non-root users to create the firewall rules. Note that you still need to be root long enough to turn on some kind of logging, or /var/log/messages will never contain any entries to convert. Root privileges are also required to implement the rules once you've created them. /etc/services and special ports: Mason converts the protocol number and type (i.e. 53, udp) into the more common name (domain, in this example). It uses the /etc/services file to do make this conversion. Before you start, make sure all the protocols you will work with are listed there. If a particular protocol is not in that file, Mason will usually leave it as a numeric entry. Having this entry is especially important if you are working with services whose ports are >= 1024 (nfs, X, squid, irc, vdolive, etc.). If a service >= 1024 is not found in /etc/services, it will be automatically (and incorrectly) generalized to the port range of 1024-65535. If your favourite service isn't in there, simply edit the file and add it in the same format as the other entries. These services whose ports are >=1024 can occasionally show up in your rules where Mason should have used 1024:65535 instead. Well, you know how to fix this, right? The entries in /etc/services should only be for well-known server ports. Client ports (which are usually just random ports between 1024 and 65535 anyways) should not be listed in here. The specific example of something that should be missing is the ssh client port. See the ssh section for more info. If you plan to do the conversion on one machine and actually run the firewall on another, make sure all of the protocols used are listed in the /etc/services on both machines. The authoritative source for these ports is the Internet Assigned Numbers Authority (IANA). A list of these ports can be found at: ftp://ftp.isi.edu/in-notes/iana/assignments/port-numbers ftp: Ahhh, yes, ftp. The scourge of firewall creators everywhere. Ftp starts off well because the client opens a connection from a high port (1024-65535) to the ftp control port 21. This part of the connection follows the same model as other tcp protocols: client uses a random high port and connects to a fixed low port. The problem arises when it's time to actually transmit data. The client and server exchange directory listings and files over additional tcp connections that are between a random high port at the client end and a random high port at the server end. Remember that packet filtering firewalls depend on being able to identify connections by their (fixed and generally low) server port. Here we have connections that need to be allowed if ftp is going to work, but can't be identified this way. It really comes down to a choice: does the firewall allow ftp traffic (leaving at least one high to high rule which is a generally considered a security risk), or do we block ftp? You'll need to decide. Mason creates these rules as transparently as any others. It opens up the ports for the control channel and the high to high rule (called the data channel). A single ftp connection could therefore open 12 rules. You'll need to decide whether these high to high rules are too much of a security risk. If you do choose to open up ftp rules, you might want to do these last. This allows you to put in more specific rules first. ssh: SSH (server port 22/tcp) has one minor note about its operation. When installed by root (setuid), it does not use a random high port between 1024 and 65535 for the client end. The first client session uses port 1023, the next uses 1022, etc. No real problem for Mason, but you might be surprised at the client ports used. These client ports should NOT be listed in /etc/services, even though it might seem to make identification easier. The reason is that Mason uses this file to identify _server_ ports in the process of deciding whether to use the ACK flag check. Insert vs. append: Ipfwadm has two ways of adding rules: at the beginning of the rule list using insert ("-i"), or at the end of the list using append ("-a"). The usual way of creating the firewall is to flush the existing rules and then add each of the rules using append so they will be scanned in the same order in which they were implemented. For this reason, the rules that Mason spits out to stdout use "append" so they can easily be put in a shell script. Mason needs some way to tell the kernel to not log already logged packets anymore. The way to do this is to put a matching rule before the logging rule. Unfortunately, that means one of two things: deleting the logging rule at the end, implementing the new rule at the end, and reinstating the logging rule, or simply inserting the new rule at the top of the list. The first option is tricky to do well. It's also a bad choice because the user using Mason may not be logging everything, so mason doesn't know what logging rule to reinstate. That leaves using "-i" to insert the rule at the very top of the list. The end effect is that the rules that Mason displays use "-a" to match how that would be put into a rule file, but the rules that are actually implemented while Mason is running use "-i" to avoid relogging those packets again in this Mason run. The major side effect of this approach is that the rule set in memory as Mason is running is almost certainly _not_ in the order you'd want. The final firewall rule set you put in place should flush whatever is in memory before starting so as to clean out these incorrectly ordered rules. It's my understanding that ipchains allows one to insert rules into a specific location in the list. This would get around this quirk of ipfwadm. Allow versus deny and reject: During the course of a Mason run, it's quite reasonable that the firewall creator might want to spend some time working with traffic types that he/she wants to allow, and then switch over to other traffic types that he/she wants to reject or deny (see man ipfwadm for the subtle difference between deny and reject). Mason allows you to change the policy inserted into the ipfwadm command on the fly without having to stop and restart Mason. Included in the Mason package is a program called mason_policy. When run with the desired policy on the command line (such as "mason_policy reject"), any rules created from that point on will use that policy. You also have the option of creating the policy file (by default, /tmp/current_policy) with "accept", "reject", or "deny", w/o quotes, as its contents. The policy can even be changed multiple times during a run. If the /tmp/current_policy file does not exist or holds an invalid value, Mason falls back to a policy of "accept". Input, Output, and Forwarding: To implement packet filtering, the Linux kernel needs to inspect each packet at at least one of the following three times: when the packet enters the system, as it passes through the system on the way to its exit interface, and as it leaves the system. At each of those three times, the kernel can decide to allow or deny/reject the packet. The rules can be different at each stage - it's perfectly legal to, for example, allow it in, allow it to be forwarded, but then block it at the last second before it leaves the system. A simple firewall could be implemented using just, say, input rules(*). It's when you get complex firewalls that having rules at all three stages is useful. You might want to allow hosts from eth0 to get to a pop-3 server on eth1, but not allow hosts from eth2 to get to the same server. This kind of restriction might be impossible to do without forwarding rules, especially if eth2 hosts _should_ be allowed to get to a pop-3 server on eth0. For simpler firewalls, or if you want less than the imposing grandeur of a firewall ruleset that goes on for pages and pages, Mason can accomodate you. If you just want input rules, follow the instructions below, but only run the logging rule for input ("/sbin/ipfwadm -I -a deny -o"). If you just want input and forwarding rules, just log input and forwarded packets. You might even take an approach such as allowing unrestricted access between the hosts on eth0 and eth1 and the firewall itself, but wanting tight control over what passes in and out of eth2. Instead of taking one of the canned logging rules below, make up your own, such as: /sbin/ipfwadm -I -W eth2 -a deny -o /sbin/ipfwadm -O -W eth2 -a deny -o Mason will only create rules corresponding to what you're actively logging, allowing you room to be a firewall artist. (*) The exceptions to this are the special rules for redirecting packets (which must be done as an input rule), and masquerading packets, (which must be done as a forwarding rule). Even in the cases where you wish to use these facilities, it's still legal to implement packet filtering using another rule type. Namecache: One of the ways of reducing the amount of DNS lookups in Mason is to keep a persistent DNS cache for each host that had to be looked up. This is implemented as a text file in /etc/hosts format. Mason does not, by default, use /etc/hosts for this storage as many other programs use /etc/hosts for what should be a small number of local hosts. Using /etc/hosts would defeat the dynamic nature of DNS. If you're ever concerned that the namecache file (/tmp/morehosts by default, change the environment variable in the Mason script if you want something else) holds stale data or is getting too large, just delete it. It will be repopulated as needed. By the way, if /etc/hosts and the namecache both have entries for a certain IP address, the last such entry in /etc/hosts wins. Feel free to add entries to this file if, for example, one of the machines to which you make connections has misconfigured forward or reverse DNS tables. Another good use for this would be entering the IP address/hostname pairs of external nameservers, as these do not get looked up in a mason run. Looking up the names of nameservers can snowball pretty quickly, even if it eventually settles down. Remote firewall creation - Telnet/ssh lockout: If you're creating this firewall rule set and you're telnetting, ssh'ing, or rsh'ing (collectively, "telnetting") in to the firewall, be careful. Some of the first rules to be created will be for the telnet packet flow you're using. If you are so unfortunate as to start this process with a policy of deny, guess what packet flow will be stopped almost immediately? That's right, your telnet session(s). Your machine will be completely locked down with no way to remotely reach it. (Now where were my car keys? ) If you want to put the rules allowing your remote access before starting Mason, great. If not, just make sure that your startup policy is allow or it's remote reboot time! Logging in on any of the console's virtual terminals does not require TCP/IP packets, so you can never lock yourself out completely. You did read the section above on "simulating the working environment under controlled conditions", didn't you? Are you still sure you want to be creating a firewall not directly under your control? Just a thought... Ack flag: Let's look at a standard rule that allows a telnet connection to a server somewhere (this is only one of the 6 possible rules). allow LAN_IPs, ports 1024-65535 -> Outside_world_IP's, port 23 It looks pretty safe, right? Hmmm.... Let's say that one of your LAN machines runs a squid server. This sits waiting for connections on port 3128. Additionally, consider the possibility that the root user on some Outside_world_IP machine writes some program that starts a connection _from_ port 23. This user starts this program and connects to your LANs squid server. All with your firewalls full consent. Ugh. The way to avoid this problem is to be able to identify the _direction_ in which the connection is created. We want to allow connections that start from LAN:1024-65535 to Outside:23, but block connections that start from Outside:23 to LAN:1024-65535. The TCP ACK flag comes to the rescue. The first packet in a connection does not have this flag set. Every packet after the first does have this flag set. If we require all packets coming from the server port have their ACK flag set, we can stop the bogus connection from port 23 back to port 3128. In short, by requiring all packets from a server port have their ACK flag set, we block connections that originate from those server ports. Three notes. Only TCP uses ACK flags, so we can't use this to control the direction in which icmp or udp conversations are initiated. Secondly, DNS may be a problem. I'm not sure if tcp domain transfers are ever from port 53 to port 53. Finally, there may be issues from ssh low ports if /etc/services has entries up near 1023. If anyone can enlighten me on how the ack flag might be indicated in ipfwadm logs, I would sincerely appreciate your help. I specifically avoided the "-b" (bidirectional) flag so that I could use "-k" to control the direction. Limitations, Ideas and future enhancements: - Mason only does ipfwadm rules. At some point I'll add a command line option to do ipchain rules as these will be the default in kernel 2.2. Don't hold your breath for ipfw rules; is there anyone that is actively creating firewalls based on these? - run newrules, then append to it (vaguely described in Quick Start) - group local machines into subnet rule (configurable) - group foreign machines into additional rule? - pad if and proto fields to line up - done - have flag file with current policy and quick scripts to change it so the current policy can be changed on the fly. - done - CL option to use whatever the log entry had. - Configurable name lookup. - CL parameter to not use dynamic IP address on pppx or slx (Need to recalculate IP address on each pass). - Try to automatically implement IP ranges. Quick start: - compile a kernel with firewall and firewall logging enabled, boot into it. See above for more info. - run the following ONLY IF you want to start with an empty set of rules (if you simply want to fill in the gaps of your current rule set, do NOT run the next three commands which erase all existing rules): /sbin/ipfwadm -I -f /sbin/ipfwadm -O -f /sbin/ipfwadm -F -f - Set any custom firewall rules you wish. Here is where you might put in a masquerading forwarding rule if that is one of the uses of this firewall. - If you have not already put in rules for allowing DNS requests through your firewall, put them in now. I offer the following rules as a general way to allow DNS requests through, but as I mentioned above, these are almost certainly way too general for security. Note that these rules would allow someone from the outside world to make requests of a nameserver running on your firewall or on your LAN. A cracker with root access could actually use the following rules to get to arbitrary services on your LAN or the firewall. Please think about what you really want to accomplish before using these in the final production environment. /sbin/ipfwadm -I -i accept -S 0/0 53 -P udp /sbin/ipfwadm -I -i accept -D 0/0 53 -P udp /sbin/ipfwadm -O -i accept -S 0/0 53 -P udp /sbin/ipfwadm -O -i accept -D 0/0 53 -P udp /sbin/ipfwadm -F -i accept -S 0/0 53 -P udp /sbin/ipfwadm -F -i accept -D 0/0 53 -P udp # /sbin/ipfwadm -O -i accept -W ppp0 -P udp -D 0/0 53 # /sbin/ipfwadm -I -i accept -W ppp0 -P udp -S 0/0 53 - in one window, do tail --lines=0 -f /var/log/messages | mason | tee -a newrules At this point, Mason will be ready to start converting packet log entries into ipfwadm rules, but will probably sit idle until you tell the kernel to start logging packets in the next section. - To actually start logging packets, switch to another window and run: /sbin/ipfwadm -I -a deny -o /sbin/ipfwadm -F -a deny -o /sbin/ipfwadm -O -a deny -o (see the section "Input, Output, and Forwarding" for examples of how to get a smaller set of rules or only rules of a certain type). This will start the kernel logging packets into /var/log/messages. Since no other rules (except for masquerading and DNS and any other rules you've already implemented) have been defined, _all_ other packets will be logged. See the above documentation if your machine is too slow to keep up with the initial flood of logged packets; you may wish to execute these one at a time, waiting for the load to settle a bit before implementing the next. When a packet is logged, the corresponding ipfwadm rule will be simultaneously executed, displayed on the terminal, and appended to newrules for later editing. - To watch the fireworks, do: tail -f --lines=0 /var/log/messages newrules in another window. - At this point, start making the connections of the type that you'd like to allow in the production environment. Mason will spit out the appropriate rules for the traffic you're creating. Don't forget to make any appropriate connections to and from the firewall machine itself. Connections _through_ the firewall are not the only ones that open up TCP/IP connections. - When you've gotten all the rules you want, press Ctrl-C in the window running mason. If you're going to be working on these rules for a while and don't want to fill up your logs with additional messages, you might want to either delete the logging rules or flush the firewall entirely(*). These are done, respectively, with the following commands: /sbin/ipfwadm -I -d deny -o /sbin/ipfwadm -F -d deny -o /sbin/ipfwadm -O -d deny -o or(*) /sbin/ipfwadm -I -f /sbin/ipfwadm -O -f /sbin/ipfwadm -F -f * Probably a poor choice if you already have rules on this machine that you want to keep there. - I find the upcoming editing to be easier if similar rules are placed next to each other. Here's how: cat newrules | sort -t '#' +1 | uniq >>edited_rules Strictly speaking, this sorts the rules according to the comments at the end of the line. This has the effect of placing similar rules together as the comments indicate the rule type. Make sure you run this after adding any new rules to "newrules". Edit the edited_rules file to generalize and reorder the rules. If this is the complete set of rules for your environment, you might be able to get away with creating the following wrapper script to create a full firewall: ---- cut here ---- firewall.run ---- cut here ---- #!/bin/bash /sbin/ipfwadm -I -f /sbin/ipfwadm -O -f /sbin/ipfwadm -F -f /sbin/ipfwadm -I -p def_policy* /sbin/ipfwadm -O -p def_policy* /sbin/ipfwadm -F -p def_policy* [place any rules you want to appear before the generated rules here. These might include the masquerading rule and/or DNS rules] . ./edited_rules [place any rules you want to appear after the generated rules here. These might include any logging rules] ---- cut here ---- firewall.run ---- cut here ---- * def_policy is either deny, accept or reject, as appropriate for your firewall. All three of the files should be hidden from public view by executing: chmod 700 firewall.run edited_rules newrules The firewall can be started automatically at boot time by adding the following line to /etc/rc.d/rc.local (or the appropriate boot script for your linux): /path/to/firewall.run Version summary: 0.8.0 -k added to control the direction in which connections are made. Unfortunately, the ftp-data port doesn't honor the simple rule for -k; I suspect this is a consequence of PASV vs. "active?" ftp opening the data connection in one direction of the other. 0.7.0 (6/21/98) 20% speed improvement by changing read command. Local name cache added. On the fly policy changing. Comments. Major documentation updates. Another 20% performance improvement by replacing some sed's with bash internal pattern deletion. 6% more by using ${#..} instead of wc --bytes to size strings. Cut time necessary to process non-firewall lines in third by using && instead of -a. 0.6.0 (6/4/98) Documentation added 0.5.0 (6/2/98) Bare code, almost no documentation, ipfwadm support only. - Bill Stearns Advanced scenarios: Once you've gone through the Quick Start, what now? Now we learn how to use this to match your security policy. The first lesson to learn about packet filtering rules is that they are only useful if you have a mix of accept and deny (equivalent to reject in this discussion) rules. Think about it. If all of your rules are allow rules and your default policy is also allow, this setup is no different from having no rules at all; the system is completely open. At the other end of the spectrum, if all of your rules are deny and the default policy is also deny, well, it's going to be pretty hard to use TCP/IP at all. :-) This means that putting a firewall together involves deciding what should be allowed _and_ what should not be allowed. The first thing for you to decide is what your default policy should be. In the next few minutes we'll be looking at what you specifically want to allow and what you specifically want to disallow. What should the firewall do with the rest of the packets? That depends on how you view your firewall. If you primarily want your firewall to block a relatively small amount of malicious things, but want users on both sides of the firewall to have relatively unencumbered access to the opposite side, you'd probably want to use a default policy of accept. This tends to be a good choice in the case where there are a large number of types of TCP/IP traffic that should be allowed to pass through the firewall. If, on the other hand, you tend more toward the paranoid and want very fine grained control over _exactly_ what passes through your firewall, you'll probably want to use a default policy of deny. This tends to work well when there are a relatively small number of protocols that should be allowed. Choosing a policy becomes difficult when you want fine grained control but there are a large number of protocols used by your users. You'll still choose a default policy of deny, but you'll have to create a large number of rules to accomodate them. Good thing you've got Mason to give you a hand! Now that you've chosen a policy, what goes next? Here's where you can become an artist. With the help of Mason, your job is to decide what should be allowed and what should not be allowed. [More should be added here...] Ordering rules: Here are a couple of guidelines about how to order your rules. I refer to policy below; for this discussion, there are 6 possible policies: accept, deny, reject, accept and log, deny and log, and reject and log. As there is no way that input rules and output rules could ever overlap, the rulesets for those can be considered seperately. The same logic holds true for input and forwarding and output and forwarding. Effectvely, even though you might have them all mixed together in your firewall creation shell script, you can work with the input rules according to the principles below, then come back and work with the forwarding rules, and then come back one last time for the output rules. - If your ruleset contains a block of 2 or more rules with the same policy (accept, deny, or reject) that immediately follow each other, the order of the rules in that block has no functional difference to the operation of the firewall. If you are very concerned about performance, you might want to put the rules that process the largest number of packets at the top of this block and the rules that process the least number of packets near the bottom of this block. - If two consecutive rules do not have any overlapping cases in the patterns they match, they can appear in either order without affecting the operation of the firewall. As long as no two rules in the set overlap, this can be extended to a set with more than two rules. - If two rules overlap in the patterns they match and have different policies, they _cannot_ be reordered without affecting the functional operation of the firewall. Specifically, the packets in the overlapping case will have their policy changed. - If two consecutive rules have the same policy and one is subset of the other, the more specific rule can be discarded and the more general rule can be kept without affecting the functional operation of the firewall. One common case of this is when your default policy is, say, accept, and the last rule just before the default policy rule also has a policy of accept. This more specific rule (not the policy, of course) can be discarded. - Your default policy always comes at the end. I've referred to discarding rules above. One reason why you might _not_ want to discard a particular rule rule is when you're using your firewall to do accounting as well as blocking. You might want to be able to have seperate accounting for the packet traffic in the rule that would have been discarded.