A firewall is a a method of intercepting packets that pass through an interface, such as a modem, or network card, and match that packet with a rule that in turn will deny, allow or
log that packet.
This document will cover the setting up of a firewall on a PPP dialup machine. As it is not on an internal network, it wont cover packet forwarding, gateways, etc.
Why would I want a firewall? There are several reasons you may want a firewall. One reason is that when a UNIX box is running
a few programs, such as X, a font service, printer service, etc, they all listen on ports on which external connections can abuse, and generally run amok. If you don't believe me, try scanning your machine with a
scanner such as nmap. Generally you don't want users to be trying to use these ports, and therefore it would be a good idea to deny external access by using a firewall.
Other reasons may be for blocking
certain types of DoS's or `nukes`, and although FreeBSD can usually handle this, having a firewall to log the attack would be useful for when reporting that attacker to their ISP.
Preparing your system for a firewall As networking is a major part of UNIX and FreeBSD, the ability to use a firewall has to be first compiled into the kernel. For information on compiling your kernel see the kernel part of the Handbook.
In FreeBSD 4.0 I wanted a normal IP firewall for ipv4. Therefore, I added the following options. If you use another version of FreeBSD, it may be a good idea to check LINT for
the correct usage.
# Firewall
1 options IPFIREWALL 2 options IPFIREWALL_VERBOSE 3 options IPFIREWALL_VERBOSE_LIMIT=10
4 options IPFIREWALL_DEFAULT_TO_ACCEPT
Don't add the line numbers - they are just for discussion. The # line is a comment, and is exempt from kernel compilation.
Line 1 tells the kernel to enable the firewall option for ipv4.
Line 2
gives the ability to log packets - without this option logging firewall packets and responses from ipfw is impossible.
Line 3
will limit logging to 10 packets from the same rule & IP, to prevent an attack which will cause a file system to be filled. It is my understanding that the logging is only stopped temporarily (for how long, I'm not sure) and the firewall will still log other rules that have not already passed the verbose limit.
Line 4
is used because I have used the firewall to deny only certain packets, ports and protocols, and therefore, any packet that passes through the rule sets I want to let through. This option is fine for most systems, although you may wish to omit this rule - however I will not cover the omission in this document, and you LOCK yourself out of the system, as omitting this rule will mean any packet on any interface will be denied by the system.
With these options added, the kernel can be recompiled for firewall support.
Enabling IPFW
When the system is booted, the firewall rules are added by /etc/rc.firewall, which adds its own basic rule sets, and then adds user specified ones.
To enable this, /etc/rc.conf - the main startup file must be edited. The contents of my rc.conf are as follows:
# firewall stuff
1 firewall_enable="YES" 2 firewall_script="/etc/rc.firewall" 3 firewall_type="/etc/ipfw.rules" 4 firewall_quiet="NO"
5 firewall_flags=""
Again, don't use the line numbers, they are here for discussion only.
Line 1 turns the firewall on at bootup. Without this, the firewall won't operate.
Line 2 uses the rc.firewall script to set up the initial firewall rule basics, and then defers setup to other files.
Line 3 tells us what script or section of the rc.firewall should be excuted to set up your
main firewall rulesets. You can use some predefined settings in rc.firewall, or use an external file. In this example, we'll be using an external file in /etc called ipfw.rules.
Line 4 will show the rules you have defined at bootup unless it is set to YES.
Line 5 settings are left blank for this example.
Save the changes, and on the next reboot, the firewall will
be enabled. However, at this point the firewall will have only one rule, 65535, which allows all packets, because we set the option in the kernel configuration. Before rebooting and starting the firewall, add
some rules.
Adding rules to your firewall
If you haven't already done so, create the file
/etc/ipfw.rules, by doing 'touch /etc/ipfw.rules'. At this point, you need to know what interface(s) you wish to set up ipfw to operate on - tun0 is the interface ppp runs on my system. Your ISPs dns server IP's
would also be useful.
Another thing before setting up your rules, it would be a good idea to know how these rules are interpreted by ipfw. Ipfw works at the beginning of the rules, in the number they
are ordered, and works through the ruleset to the end looking for a packet that matches the list of rules. When it finds a match, it processes the packet in accordance with the rule. It will only process the packet
against the first matching rule. If no matching rule is found, it will pass through the firewall (a match with rule 65535). (Or it will be denied if the firewall is not accepting as default).
The basic rule format is as follows;
add <rule number> <action[deny,allow,log,etc]> <protocol[tcp,icmp,udp,etc]> from <ip [port]> to <ip [port]> <in/out> <interface>
for more information on each of the parts, see ipfw(8)
I intend to block TCP, UDP services, and also log some interesting ports.
The first two rules have been added by rc.firewall and allow packets to pass internally, and really shouldnt be removed. These are rules 00100 and 00200. I will start at 00300
by blocking the ports i mentioned earlier that are open by X, lpd, etc.
If you run X, you'll want to block port 6000, and possibly others, depending on how many displays you have. Typing this into ipfw.rules
will block external X connections.
add 00300 deny log tcp from any to any 6000 in recv tun0
To deny lpd access from outside:
add 00301 deny log tcp from any to any 515 in recv tun0
And to prevent my font server being connected to, i need to block 7101 (read your font server documentation to find which port it uses):
add 00302 deny tcp from any to any 7101 in recv tun0
Next, I will want allow port 53 through from my ISP dns server (as I will block all ports on TCP below 1000 later on.)
add 00310 allow tcp from 212.49.224.1 53 to any in recv tun0 add 00311 allow tcp from 212.49.224.2 53 to any in recv tun0 add 00312 allow tcp from 212.49.224.3 53 to any in recv tun0
The 212.49.224.x is where you should insert your ISP's dns.
If you wish to allow any other ports access below 1024, such as identd, add them now:
add 00322 allow log tcp from any to any 113 in recv tun0 setup
This rule is slightly different, because the port is accessible by anyone, I want to log machines that try using this port. The log + setup flags will therefore only log the initial IP set up packet, and not the whole communication, as that will create an excessive log. 'setup' only works on TCP sockets.
You may also want to enable FTP (port 21), or telnet (port 23) connections.
By this point, we have now denied all ports that were open, apart from the ones where external connections are needed. Therefore, we can now block the rest of the TCP ports below 1000, by adding this next rule:
add 00399 deny log tcp from any to any 0-1000 in recv tun0 setup
This logs any attempts to connect on other ports below 1000. You can remove the log option if you want.
Next, is the udp protocol, which other daemons, such as syslogd use - and which you'll probably want to block too.
Although, we need to allow DNS again:
add 00400 allow udp from 212.49.224.1 53 to any in recv tun0 add 00401 allow udp from 212.49.224.2 53 to any in recv tun0 add 00402 allow udp from 212.49.224.3 53 to any in recv tun0
and replace 212.49.224.x with your ISP's dns servers.
I also use ntpdate which keeps my clock in sync with a timeserver, and uses the udp 123 port. As I know my timeserver address, I can give it exclusive access to port 123, thus denying connections from other servers by adding:
add 00403 allow udp from 192.5.41.40 123 to any 123 in recv tun0
where 192.5.41.40 is your timeserver. If you don't use a time server, you can omit the rule.
I will now block the rest of the udp connections, however I think Real player streaming uses udp, but I think it will allow other transport protocols
too. If this bothers you, you can find the Real player port, and let it through, otherwise leave real player to find another transport protocol to you.
# block the rest of udp. add 00499 deny log udp from any to any in recv tun0
The next section is optional, but it allows you to log connections such as netbus - although netbus is harmless on FreeBSD, its still interesting to find out who is trying to use it on you.
add 00500 deny log tcp from any to any 12345 in recv tun0 add 00501 deny log tcp from any to any 20034 in recv tun0
The final part is to add logging for ICMP, a protocl along which (usually) small data parts such as pings flow. These in a flood attack can be a DoS attack, and are useful to
log. You might also wish to limit ICMP bandwidth by adding `options ICMP_BANDLIM` to your kernel for extra safety.
Let your ISP ping you:
add 00600 allow icmp from 212.49.224.1 to any in recv tun0 add 00601 allow icmp from 212.49.224.2 to any in recv tun0
add 00602 allow icmp from 212.49.224.3 to any in recv tun0
again, where 212.49.224.x are your ISPs dns servers.
These two rules log imcp echos and dest. unreach, a popular choice of script kiddies. You can add other types by changing the number after icmptype. ipfw(8) lists the choices.
add 00610 allow log icmp from any to any in recv tun0 icmptype 3 add 00611 allow log icmp from any to any in recv tun0 icmptype 8
After this point any packet that doesnt match the rules will be let through as default. Save these changes to ipfw.rules, reboot and your firewall should be activated with these
rules in place.
Checking it works
As root, typing 'ipfw show' will display your rules, (remember you must reboot before they appear)
`ipfw -at l` shows the last time a rule was matched
`ipfw flush` will flush your rules, something you shouldn't really need to do.
Once your firewall is running, you can add rules on the fly by typing
ipfw add <rule number> <action[deny,allow,log,etc]> <protocol[tcp,icmp,udp,etc]> from <ip [port]> to <ip [port]> <in/out> <interface>
and you can remove one by typing;
ipfw delete [rulenumber]
Remember, in order for these changes to be permanent, you must edit ipfw.rules.
Reading the logs
ipfw should log to /var/log/security, and also to /var/log/ipfw.*, as long as you enabled verbosity in the kernel, and that the following line is in /etc/syslog.conf:
security.* /var/log/security
NOTE: The gaps must be tabs. I didn't have to change this in FreeBSD 4.0.
Caveats:
I assumed tun0 is the interface that ppp routes through. Change this to suit.
I used 'any' for my machine, as the IP is dynamic.
Signing Off
I hope this document has given you a simple insight into ipfw, and you should now be able to customize and add rules for your own system, and for your own needs.
Remember, a firewall doesn't make you "unhackable", and you should still use other techniques to secure your system.
[ Andy Smith ]
[ aa_smith@iname.com ]
I have included a copy of my /etc/ipfw.rules for reference below -- although dont load this and expect it to work straight away; some of it is customized, which you learn about by
reading the information above.
#--- begin ipfw.rules ---#
# 00100 & 00200 are specified in /etc/rc.firewall # 00300 tcp service blocking # 00400 udp blocking
# 00500 kiddie logging (netbus etc) # 00600 icmp logging # # 003xx rules - TCP # # block X server external connections on tun0 (ppp tunnel)
add 00300 deny log tcp from any to any 6000 in recv tun0 # block lpd access add 00301 deny log tcp from any to any 515 in recv tun0 # block external font server connections.
add 00302 deny tcp from any to any 7101 in recv tun0 # allow DNS from my ISP # put these after deny rules. add 00310 allow tcp from 212.49.224.1 53 to any in recv tun0
add 00311 allow tcp from 212.49.224.2 53 to any in recv tun0 add 00312 allow tcp from 212.49.224.3 53 to any in recv tun0 # allow general ftp, telnet & ident access.
# log the inital setup packet to establish who is trying to login. add 00320 allow log tcp from any to any 21 in recv tun0 setup add 00321 allow log tcp from any to any 23 in recv tun0 setup
add 00322 allow log tcp from any to any 113 in recv tun0 setup # block all other tcp stuff below port 1000, and log it. add 00399 deny log tcp from any to any 0-1000 in recv tun0 setup #
# 004xx rules - UDP # #allow dns again. add 00400 allow udp from 212.49.224.1 53 to any in recv tun0 add 00401 allow udp from 212.49.224.2 53 to any in recv tun0
add 00402 allow udp from 212.49.224.3 53 to any in recv tun0 # allow timeserver through. add 00403 allow udp from 192.5.41.40 123 to any 123 in recv tun0 # block the rest of udp.
add 00499 deny log udp from any to any in recv tun0 # # 005xx rules - logging other access # # Log all requests to port 12345 & 20034. add 00500 deny log tcp from any to any 12345 in recv tun0
add 00501 deny log tcp from any to any 20034 in recv tun0 # # 006xx rules - logging icmp # add 00600 allow icmp from 212.49.224.1 to any in recv tun0
add 00601 allow icmp from 212.49.224.2 to any in recv tun0 add 00602 allow icmp from 212.49.224.3 to any in recv tun0 add 00610 allow log icmp from any to any in recv tun0 icmptype 3
add 00611 allow log icmp from any to any in recv tun0 icmptype 8 # anything else that has not been blocked is now allowed to pass through, # as defined in the kernel as rule 65535. #--- end ipfw.rules ---#
|