IPFILTER (IPF) Firewall
Contributed by Joseph J. Barbish
The author of IPFILTER is Darren Reed. IPFILTER is not FBSD operating system dependant. IPFILTER is an open source application and has been ported to FreeBSD, NetBSD, OpenBSD, Sun, HP, and Solaris operating systems. IPFILTER is actively being supported and maintained, with updated versions being released regularly.
The IPFILTER program runs in the kernel and consists of the firewall and separate NAT facilities. IPFILTER also has user-land front-end interactive interfaces for controlling the firewall rules, NAT, packet accounting, and the logging facility. Program IPF is used to load the firewall rules. Program IPNAT is used to load the firewall NAT rules. Program IPFSTAT reports on packet filter statistics and lists active rules sets. Program IPMON monitors IPFILTER for logged packets.
From this point on IPFILTER will be written as IPF and is intended to mean the same thing as IPFILTER.
IPF was originally written using an rules processing logic of ‘the last matching rule wins’ and used only stateless types of rules. Over time IPF has been enhanced to include an ‘quick’ option and a stateful ‘keep state’ option which drastically modernized the rules processing logic. IPF’s official documentation covers the legacy rule coding parameters and the legacy rule file processing logic, the modernized functions are only included as additional options, completely understating their benefits in producing an far superior secure firewall.
The instructions contained in this guide is based on using rules that contain the ‘quick option’ and the stateful ‘keep state’ option. This is the basic framework for coding an inclusive firewall rule set.
An inclusive firewall only allows services matching the rules through. This way you can control what services can originate behind the firewall destine for the public internet and also control the services which can originate from the public internet accessing your private network. Every thing else is blocked and logged by default design. Inclusive firewalls are much, much securer than exclusive firewall rule sets and is the only rule set type covered here in.
For detailed explanation of the legacy rules processing method see, http://www.obfuscation.org/ipf/ipf-howto.html#TOC_1
http://coombs.anu.edu.au/~avalon/ip-filter.html
To see the FAQ http://www.phildev.net/ipf/index.html
Installers Note: IPFILTER users who need an traffic shaper facility for managing bandwidth usage can use the standalone ALTQ port application. ALTQ is now in beta test on FBSD 5.2. See the following links for details.
http://www.rofug.ro/projects/freebsd-altq/
http://www.csl.sony.co.jp/person/kjc/kjc/software.html#ALTQ
Since all firewalls are based on interrogating the values of selected packet control fields, the creator of the firewall rules must have an understanding of how TCP/IP works, what the different values in the packet control fields are and how these values are used in a normal session conversation. For a good explanation go to http://www.ipprimer.com/overview.cfm
Enabling IPF
IPF is included in the basic FBSD install as a separate run time loadable module. IPF will dynamically load it’s kernel loadable module when the rc.conf statement ipfilter_enable="YES" is used. The loadable module was created with logging enabled and the ‘default pass all’ options. You do not need to compile IPF into the FBSD kernel just to change the default to ‘black all’, you can do that by just coding an block all rule at the end of your rule set.
Using the IPF run time loadable module is recommended.
Kernel options
It is not an mandatory requirement that you enable IPF by compiling the following options into the FBSD kernel. It’s only presented here as an background information. Compiling IPF into the kernel causes the loadable module to never be used.
Sample kernel source IPF options statements are in the /usr/src/sys/i386/conf/LINT kernel source and are reproduced here.
options IPFILTER
options IPFILTER_LOG
options IPFILTER_DEFAULT_BLOCK
IPFILTER This tells the compile to include IPFILTER as part of it’s core kernel.
IPFILTER_LOG enables the option to have IPF log traffic by writing to the ipl packet logging psuedo-device for every rule that has the "log" keyword.
IPFILTER_DEFAULT_BLOCK This option changes the default behavior so any packet not matching an firewall ‘pass’ rule gets blocked.
To build a custom kernel see the appropriate FBSD handbook section.
RC.CONF Options
You need the follow statements in /etc/rc.conf to activate IPF at boot time.
ipfilter_enable="YES" # Start ipf firewall
ipfilter_rules="/etc/ipf.rules" # loads rules definition text file
# IE: not script file with rules in it
ipmon_enable="YES" # Start IP monitor log
ipmon_flags="-Ds" # D = start as daemon
# s = log to syslog
# v = log tcp window, ack, seq
# n = map IP & port to names
If you have an LAN behind this firewall that uses the reserved private IP address ranges, then you need to add the following to enable NAT function.
gateway_enable="YES" # Enable as Lan gateway
ipnat_enable="YES" # Start ipnat function
ipnat_rules="/etc/ipnat.rules" # rules definition file for ipnat
IPF COMMAND
The ipf command is used to load your rules file. Normally you create a file containing your custom rules and use this command to replace in mass the currently running firewall internal rules.
ipf –Fa –f /etc/ipf.rules
-Fa means flush all internal rules tables
-f means this is the file to read for the rules to load
This gives the user the ability to make changes to their custom rules file, run the above IPF command thus updating the running firewall with a fresh copy of all the rules with out having to reboot the system. This method is very convenient to testing new rules as the procedure can be executed as many times as needed.
See man IPF(8) for details on the other flag options available with this command.
The ipf command expects the rules file to be an standard text file. It will not accept an rules file written as an script with symbolic substitution.
There is an way to build IPF rules that utilities the power of script symbolic substitution. See the Building Rule Script section below.
IPFSTAT Command
The default behavior of ipfstat is to retrieve and display the totals of the accumulated statistics gathered as a result of applying the user coded rules against packets going in and out of the firewall since it was last started or since the last time the accumulators were reset to zero by ipf –Z command.
See ‘man ipfstat’ for details.
This is what the ipfstat command displays with out any flags
input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
input packets logged: blocked 99286 passed 0
output packets logged: blocked 0 passed 0
packets logged: input 0 output 0
log failures: input 3898 output 0
fragment state(in): kept 0 lost 0
fragment state(out): kept 0 lost 0
packet state(in): kept 169364 lost 0
packet state(out): kept 431395 lost 0
ICMP replies: 0 TCP RSTs sent: 0
Result cache hits(in): 1215208 (out): 1098963
IN Pullups succeeded: 2 failed: 0
OUT Pullups succeeded: 0 failed: 0
Fastroute successes: 0 failures: 0
TCP cksum fails(in): 0 (out): 0
Packet log flags set: (0)
When supplied with either -i for inbound or –o for outbound, it will retrieve and display the appropriate list of filter rules currently installed and in use by the kernel.
Ipfstat –in displays the inbound internal rules table with rule number
Ipfstat –on displays the outbound internal rules table with rule number
Rules will be displayed like this
@1 pass out on xl0 from any to any
@2 block out on dc0 from any to any
@3 pass out quick on dc0 proto tcp/udp from any to any keep state
Ipfstat –ih displays the inbound internal rules table prefixed each rule with count of times the rule was matched
Ipfstat –oh displays the outbound internal rules table prefixed each rule with count of times the rule was matched
Rules will be displayed like this
2451423 pass out on xl0 from any to any
354727 block out on dc0 from any to any
430918 pass out quick on dc0 proto tcp/udp from any to any keep state
Ipfstat –t [ -C | -D | -P | -S | -T ]
The most important function of the ipfstat command is the –T flag which activates the display state table in a way similar to the way the ‘top’ command shows the FBSD running process table. When your firewall is under attack this function gives you the ability to identify and drill down to, and see the attacking packets. The optional sub-flags give the ability to select destination or source IP, port, protocol, you want to monitor in real time. See man ipfstat for details.
IPMON Command
In order for ipmon to properly work, the kernel option IPFILTER_LOG must be turned on. This command has 2 different modes it can be used in. Native mode is the default mode when you type the command on the FBSD console command line with out the –D flag.
Daemon mode is for when you want to have a continuous system log file available so you can review logging of past events. This is how FBSD and IPFILTER are configured to work together. FBSD has an built in facility to automatically rotate syslogs. That is why outputting the log information to syslogd is better than the default of an regular file. In rc.conf file you see the ipmon_flags statement uses the "-Ds" flags
ipmon_flags="-Ds" # D = start as daemon
# s = log to syslog
# v = log tcp window, ack, seq
# n = map IP & port to names
The benefits of logging are obvious, provides the ability to review after the fact, information like, what packets had been dropped, what addresses they came from, where they were going, giving you a significant edge in tracking down attackers.
Even with the logging facility enabled, IPF will not generate any rule logging on it’s own. The firewall administrator decides what rules in the rule set he wants to log and adds the log keyword to those rules. Normally only deny rules are logged.
It’s very customary to include an default deny every thing rule with the log keyword included as your last rule in the rule set. This way you get to see all the packets that did not match any of the rules in the rule set.
IPMON Logging
Syslogd uses it’s own special method for segregation of log data. It uses special grouping called ‘facility’ and ‘level’. IPMON in –Ds mode uses Local0 as the ‘facility’ name. All IPMON logged data goes to Local0. The following levels can be used to further segregate the logged data if desired.
LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block.
LOG_NOTICE - packets logged which are also passed
LOG_WARNING - packets logged which are also blocked
LOG_ERR - packets which have been logged and which can be considered short
FBSD keeps all of it’s syslog files in location /var/log/
You have to create an log file for the IPFILTER logged data.
touch /var/log/ipfilter.log # will allocate the file
The syslog function is controlled by definition statements in the /etc/syslog.conf file. The syslog.conf file offers considerable flexibility in how syslog will deal with system messages issued by software applications like IPF.
You will have to edit the /etc/syslog.conf file.
Add the following statement to syslog.conf
Local0.* /var/log/ipfilter.log
The local0.* means to write all the logged messages to the coded file location.
To activate the changes to /etc/syslog.conf you can reboot or bump the syslog task into re-reading /etc/syslog.conf by kill –HUP pid. You get the pid (IE: process number) by listing the tasks with ps ax command. Find syslog in the display and the pid number is the number in the left column.
Don’t forget to change /etc/newsyslog.conf to rotate the new log you just created above.
Format of Logged Messages
Messages generated by ipmon consist of data fields separated by white space.
Fields common to all messages are:
1. The date of packet receipt.
2. The time of packet receipt. This is in the form HH:MM:SS.F, for hours, minutes seconds, and fractions of a second (which can be several digits long).
3. The name of the interface the packet was processed on, e.g., dc0.
4. The group and rule number of the rule, e.g., @0:17.
These can be viewed with ipfstat -in.
5. The action: p for passed, b for blocked, S for a short packet, n did not match any rules, L for a log rule. The order of precedence in showing flags is:
S, p, b, n, L. A capital P or B means that the packet has been logged due to a global logging setting, not a particular rule.
6. The addresses. This is actually three fields: the source address and port (separated by a comma), the -> symbol, and the destination address and port. 209.53.17.22,80 -> 198.73.220.17,1722.
7. PR followed by the protocol name or number, e.g., PR tcp.
8. len followed by the header length and total length of the packet,
e.g., len 20 40.
If the packet is a TCP packet, there will be an additional field starting with a hyphen followed by letters corresponding to any flags that were set. See the ipf.conf manual page for a list of letters and their flags.
If the packet is an ICMP packet, there will be two fields at the end, the first always being `ICMP', and the next being the ICMP message and sub-message type, separated by a slash, e.g., ICMP 3/3 for a port unreachable message.
Building Rule Script
Some experienced IPF users create a file containing the rules and code them in a manner compatible with running them as a script with symbolic substitution. The major benefit of doing this is you only have to change the value associated with the symbolic name and when the script is run all the rules containing the symbolic name will have the value substituted in the rules. Being a script, you can use symbolic substitution to code frequent used values and substitute them in multiple rules. You will see this in the following example.
The script syntax used here is compatible with the ‘sh’, ‘csh’, ‘tcsh’ shells.
Symbolic substitution fields are prefixed with a dollar sign $.
Symbolic fields do not have the $ prefix
The value to populate the Symbolic field must be enclosed with "double quotes".
Start your rules file with this.
############# Start of IPF rules script ########################
oif="dc0" # name of the outbound interface
odns="192.0.2.11" # ISP's dns server IP address Symbolic>
myip="192.0.2.7" # My Static IP address from ISP
ks="keep state"
fks="flags S keep state"
# You can use this same to build the /etc/ipf.rules file
#cat >> /etc/ipf.rules << EOF
# exec ipf command and read inline data, stop reading
# when word EOF is found. There has to be one line
# after the EOF line to work correctly.
/sbin/ipf -Fa -f - << EOF
# Allow out access to my ISP's Domain name server.
pass out quick on $oif proto tcp from any to $odns port = 53 $fks
pass out quick on $oif proto udp from any to $odns port = 53 $ks
# Allow out non-secure standard www function
pass out quick on $oif proto tcp from $myip to any port = 80 $fks
# Allow out secure www function https over TLS SSL
pass out quick on $oif proto tcp from $myip to any port = 443 $fks
EOF
################## End of IPF rules script ########################
That’s all there is to it. The rules are not important in this example, how the Symbolic substitution field are populated and used are. If the above example was in /etc/ipf.rules.script file, I could reload these rules by entering on the FBSD command line
sh /etc/ipf.rules.script
There is one problem with using an rules file with embedded symbolics. IPF has no problem with it, but the rc.conf
ipfilter_rules="/etc/ipf.rules"
statement will not load the rules if the file this statement is pointing at contains symbolics. This is an FBSD rc.conf launch problem.
The solution is to delete the following statement in the rc.conf
ipfilter_rules=
and put the following script in this directory.
/usr/local/etc/rc.d/
FBSD looks in this directory for scripts that have names ending in ‘.sh’ to automatically launch during the boot process. Apache and DHCP place their launch scripts there.
Your launch script should look like this.
ee /usr/local/etc/rc.d/ipf.loadrules.sh
#!/bin/sh
sh /etc/ipf.rules.script
The permission on this script file must be read, write, exec for owner root.
chmod 700 /usr/local/etc/rc.d/ipf.loadrules.sh
Now when you system boots your IPF rules will be loaded using the script.
IPF Rule Sets
A rule set is a group of ipf rules coded to pass or block packets based on the values contained in the packet. The bi-directional exchange of packets between hosts comprises an session conversation. The firewall rule set processes the packet 2 times, once on its arrival from the public internet host and again as it leaves for it’s return trip back to the public internet host. Each tcp/ip service (IE: telnet, www, mail, etc;) is predefined by its protocol, source and destination IP address, or the source and destination port number. This is the basic selection criteria used to create rules which will pass or block services.
IPF was originally written using an rules processing logic of ‘the last matching rule wins’ and used only stateless types of rules. Over time IPF has been enhanced to include an ‘quick’ option and a stateful ‘keep state’ option which drastically modernized the rules processing logic.
The instructions contained in this section is based on using rules that contain the ‘quick option’ and the stateful ‘keep state’ option. This is the basic framework for coding an inclusive firewall rule set.
An inclusive firewall only allows services matching the rules through. This way you can control what services can originate behind the firewall destine for the public internet and also control the services which can originate from the public internet accessing your private network. Every thing else is blocked and logged by default design. Inclusive firewalls are much, much securer than exclusive firewall rule sets and is the only rule set type covered here in.
Installers Note: Warning, when working with the firewall rules, always, always do it from the root console of the system running the firewall or you can end up locking your self out.
Rule Syntax
The rule syntax presented here has been simplified to only address the modern stateful rule context and ‘first matching rule wins’ logic. For the complete legacy rule syntax description see the online ‘man ipf’ page at http://www.freebsd.org/cgi/man.cgi?query=ipf&apropos=0&sektion=0&manpath=FreeBSD+5.2-RELEASE+and+Ports&format=html
# is used to mark the start of a comment and may appear at the end of a rule line or on its own lines. Blank lines are ignored.
Rules contain keywords, These keywords have to be coded in an specific order from left to right on the line. Keywords are identified in bold type. Some keywords have sub-options which may be keywords them selves and also include more sub-options. Each of the headings in the below syntax has an bold section header which expands on the content.
Syntax = ACTION IN-OUT OPTIONS SELECTION STATEFUL
ACTION = block | pass
IN-OUT = in | out
OPTIONS = log | quick | on interface-name
SELECTION = proto value| source/destination IP | port = number | flags flag-value
Where value = tcp/udp | udp | tcp | icmp
Where source/destination IP = all | from object to object
Where object = IP address | any
Where number = port number
Where flag-value = S
STATEFUL = keep state
The | symbol used in the above syntax means ‘or’.
ACTION
The action indicates what to do with the packet if it matches the rest of the filter rule. Each rule MUST have an action. The following actions are recognized:
block indicates that the packet should be dropped if the selection parameters match the packet.
pass indicates that the packet should exit the firewall if the selection parameters match the packet.
IN-OUT This is a mandatory requirement that each filter rule explicitly state which side of the I/O it is to be used on. The next keyword must be either in or out and one or the other has to be coded or the rule will not pass syntax check.
in means this rule is being applied against an inbound packet which has just been received on the interface facing the public internet.
out means this rule is being applied against an outbound packet destine for the interface facing the public internet.
OPTIONS Must be used in the order shown here.
log indicates that the packet header will be written to the ipl log (as described in the LOGGING section below) if the selection parameters match the packet
quick indicates that if the selection parameters match the packet, this rule will be the last rule checked, allowing a "short-circuit" path to avoid processing any following rules for this packet. This option is an mandatory requirement for the modernized rules processing logic.
on indicates the interface name to be incorporated into the selection parameters. Interface names are as displayed by ifconfig. Using this option, the rule will only match if the packet is going through that interface in the specified direction (in/out). This option is an mandatory requirement for the modernized rules processing logic.
When a packet is logged, the headers of the packet are written to the IPL packet logging psuedo-device. Immediately following the log keyword, the following qualifiers may be used (in this order):
body indicates that the first 128 bytes of the packet contents will be logged after the headers.
first If the ‘log’ keyword is being used in conjunction with a "keep state" option, it is recommended that this option is also applied so that only the triggering packet is logged and not every packet which there after matches the ‘keep state’ information.
SELECTION
The keywords described in this section are used to describe attributes of the packet to be interrogated when determining whether rules match or don't match. There is an keyword subject, and it has sub-option keywords, one of which has to be selected. The following general-purpose attributes are provided for matching, and must be used in this order:
proto value Proto is the subject keyword, it must be coded along with one of it’s corresponding keyword sub-option values. The value allows a specific protocol to be matched against. This option is an mandatory requirement for the modernized rules processing logic.
Valid sub-option value keywords are
tcp/udp | udp | tcp | icmp or any protocol names found in /etc/protocols are recognized and may be used. The special protocol keyword tcp/udp may be used to match either a TCP or a UDP packet, and has been added as a convenience to save duplication of otherwise identical rules.
source/destination IP =
all keyword is essentially a synonym for "from any to any" with no other match parameters.
from src to dst The from and to keywords are used to match against IP addresses. Rules must specify BOTH source and destination parameters. ‘any’ is an special keyword that matches any IP address. As in "from any to any" or
"from 0.0.0.0/0 to any" or "from any to 0.0.0.0/0 " or
"from 0.0.0.0 to any" or "from any to 0.0.0.0 "
IP addresses may be specified as a dotted IP address numeric form/mask-length, or as single dotted IP address numeric form.
There isn't a way to match ranges of IP addresses which do not express themselves easily as mask-length. See this link for help on writing mask-length. http://jodies.de/ipcalc
port If a port match is included, for either or both of source and destination, then it is only applied to TCP and UDP packets. When composing port comparisons, either the service name from /etc/services or an integer port number may be used. When the port appears as part of the from object, it matches the source port number, when it appears as part of the to object, it matches the destination port number. The use of the port option with the ‘to’ object is an mandatory requirement for the modernized rules processing logic.
As in ‘from any to any port = 80’
Port comparisons may be done in a number of forms, with a number of comparison operators, or port ranges may be specified.
port "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" |
"gt" | "le" | "ge".
To specify port ranges, port "<>" | "><" .
Following the source and destination matching parameters, the following two parameters are mandatory requirements for the modernized rules processing logic.
flags is only effective for TCP filtering. The letters represents one of the possible flags that can be interrogated in the TCP packet header.
The modernized rules processing logic uses the ‘flags S’ parameter to identify the tcp session start request.
STATEFUL
keep state indicates that on an pass rule, any packets that match the rules selection parameters is to activate the stateful filtering facility.
This option is an mandatory requirement for the modernized rules processing logic.
Stateful Filtering
Stateful filtering treats traffic as a bi-directional exchange of packets comprising an session conversation. When activated keep-state dynamically generates internal rules for each anticipated packet being exchanged during the bi-directional session conversation. It has the interrogation abilities to determine if the session conversation between the originating sender and the destination are following the valid procedure of bi-directional packet exchange. Any packets that do not properly fit the session conversation template are automatically rejected as impostors.
Keep state will also allow ICMP packets related to a TCP or UDP session through. So if you get ICMP type 3 code 4 in response to some web surfing allowed out by a keep state rule, they will be automatically allowed in. Any packet that IPF can be certain is part of a active session, even if it's a different protocol, will be let in.
What happens is:
Packets destine to go out the Nic interface connected to the public internet are first checked against the dynamic state table, if the packet matches the next expected packet comprising in an active session conversation, then it's exits the firewall and the state of the session conversation flow is updated in the dynamic state table, the remaining packets get checked against the outbound rule set.
Packets coming in to the Nic interface connected to the public internet are first checked against the dynamic state table, if the packet matches the next expected packet comprising an active session conversation, then it's exits the firewall and the state of the session conversation flow is updated in the dynamic state table, the remaining packets get checked against the inbound rule set.
When the conversation completes it's removed from the dynamic state table.
Stateful filtering allows you to focus on blocking/passing new sessions. If the new session is passed, all its subsequent packets will be allowed through automatically and any impostors automatically rejected. If a new session is blocked, none of its subsequent packets will be allowed through. Stateful filtering has technically advanced interrogation abilities capable of defending against the flood of different attack methods currently employed by attackers.
Inclusive Rule set Example
The following rule set is an example of how to code an very secure inclusive type of firewall. An inclusive firewall only allows services matching pass rules through and blocks all other by default. All firewalls have at the minimum two interfaces which have to have rules to allow the firewall to function.
All Unix flavored systems including FBSD are designed to use interface L0 and IP address 127.0.0.1 for internal communication with in the FBSD operating system. The firewall rules must contain rules to allow free unmolested movement of these special internally used packets.
The interface which faces the public internet, is the one which you code your rules to authorize and control access out to the public internet and access requests arriving from the public internet. This can be your ‘user ppp’ tun0 interface or your Nic card that is cabled to your DSL or cable modem.
In cases where one or more than one Nic cards are cabled to Private LANs (local area networks) behind the firewall, those interfaces must have a rule coded to allow free unmolested movement of packets originating from those LAN interfaces.
The rules should be first organized into three major sections, all the free unmolested interfaces, public interface outbound, and the public interface inbound.
The order of the rules in each of the public interface sections should be in order of the most used rules being placed before less often used rules with the last rule in the section being an block log all packets on that interface and direction.
The Outbound section in the following rule set only contains ‘pass’ rules which contain selection values that uniquely identify the service that is authorized for public internet access. All the rules have the ‘quick’, ‘on’, proto, port, and keep state option coded. The ‘proto tcp’ rules have the ‘flag’ option included to identify the session start request as the triggering packet to activate the stateful facility.
The Inbound section has all the blocking of undesirable packets first for 2 different reasons. First is these things being blocked may be part of an otherwise valid packet which may be allowed in by the later authorized service rules. Second reason is that by having a rule that explicitly blocks selected packets that I receive on an infrequent bases and don’t want to see in the log, this keeps them from being caught by the last rule in the section which blocks and logs all packets which have fallen through the rules. The last rule in the section which blocks and logs all packets is how you create the legal evidence needed to prosecute the people who are attacking your system.
Another thing you should take note of, if there is no response returned for any of the undesirable stuff, their packets just get dropped and vanish. This way the attackers has no knowledge if his packets have reached your system. The less the attackers can learn about your system the more secure it is. The inbound 'nmap OS fingerprint' attempts rule I log the first occurrence because this is something an attacker would do.
Any time you see log messages on a rule with ‘log first’ you should do an ipstst –h command to see the number of times the rule has been matched so you know if your are being flooded, IE: under attack.
When you log packets with port numbers you do not recognize, go to http://www.securitystats.com/tools/portsearch.php and do an port number lookup to find what the purpose of that port number is.
Check out this link for port numbers used by Trojans: http://www.simovits.com/trojans/trojans.html
The following rule set is an complete very secure ‘inclusive’ type of firewall rule set that I have used on my system. You can not go wrong using this rule set for your own. Just comment out any pass rules for services to don’t want to authorize.
If you see messages in your log that you want to stop seeing just add an block rule in the inbound section.
You have to change the ‘dc0’ interface name in every rule to the interface name of the Nic card that connects your system to the public internet. For ‘user ppp’ it would be ‘tun0’.
Add the following statements to /etc/ipf.rules
#################################################################
# No restrictions on Inside Lan Interface for private network
# Not needed unless you have Lan
#################################################################
#pass out quick on xl0 all
#pass in quick on xl0 all
#################################################################
# No restrictions on Loopback Interface
#################################################################
pass in quick on lo0 all
pass out quick on lo0 all
#################################################################
# Interface facing Public internet (Outbound Section)
# Interrogate session start requests originating from behind the
# firewall on the private network
# or from this gateway server destine for the public internet.
#################################################################
# Allow out access to my ISP's Domain name server.
# xxx must be the IP address of your ISP’s DNS.
# Dup these lines if your ISP has more than one DNS server
# Get the IP addresses from /etc/resolv.conf file
pass out quick on dc0 proto tcp from any to xxx port = 53 flags S keep state
pass out quick on dc0 proto udp from any to xxx port = 53 keep state
# Allow out access to my ISP's DHCP server for cable or DSL networks.
# This rule is not needed for ‘user ppp’ type connection to the
# public internet, so you can delete this whole group.
# Use the following rule and check log for IP address.
# Then put IP address in commented out rule & delete first rule
pass out log quick on dc0 proto udp from any to any port = 67 keep state
#pass out quick on dc0 proto udp from any to z.z.z.z port = 67 keep state
# Allow out non-secure standard www function
pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state
# Allow out secure www function https over TLS SSL
pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state
# Allow out send & get email function
pass out quick on dc0 proto tcp from any to any port = 110 flags S keep state
pass out quick on dc0 proto tcp from any to any port = 25 flags S keep state
# Allow out Time
pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state
# Allow out nntp news
pass out quick on dc0 proto tcp from any to any port = 119 flags S keep state
# Allow out gateway & LAN users non-secure FTP ( both passive & active modes)
# This function uses the IPNAT built in FTP proxy function coded in
# the nat rules file to make this single rule function correctly.
# If you want to use the pkg_add command to install application packages
# on your gateway system you need this rule.
pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state
# Allow out secure FTP, Telnet, and SCP
# This function is using SSH (secure shell)
pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state
# Allow out non-secure Telnet
pass out quick on dc0 proto tcp from any to any port = 23 flags S keep state
# Allow out FBSD CVSUP function
pass out quick on dc0 proto tcp from any to any port = 5999 flags S keep state
# Allow out ping to public Internet
pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state
# Allow out whois for LAN PC to public Internet
pass out quick on dc0 proto tcp from any to any port = 43 flags S keep state
# Block and log only the first occurrence of everything
# else that’s trying to get out.
# This rule enforces the block all by default logic.
block out log first quick on dc0 all
#################################################################
# Interface facing Public internet (Inbound Section)
# Interrogate packets originating from the public internet
# destine for this gateway server or the private network.
#################################################################
# Block all inbound traffic from non-routable or reserved address spaces
block in quick on dc0 from 192.168.0.0/16 to any #RFC 1918 private IP
block in quick on dc0 from 172.16.0.0/12 to any #RFC 1918 private IP
block in quick on dc0 from 10.0.0.0/8 to any #RFC 1918 private IP
block in quick on dc0 from 127.0.0.0/8 to any #loopback
block in quick on dc0 from 0.0.0.0/8 to any #loopback
block in quick on dc0 from 169.254.0.0/16 to any #DHCP auto-config
block in quick on dc0 from 192.0.2.0/24 to any #reserved for doc's
block in quick on dc0 from 204.152.64.0/23 to any #Sun cluster interconnect
block in quick on dc0 from 224.0.0.0/3 to any #Class D & E multicast
##### Block a bunch of different nasty things. ############
# That I don’t want to see in the log
# Block frags
block in quick on dc0 all with frags
# Block short tcp packets
block in quick on dc0 proto tcp all with short
# block source routed packets
block in quick on dc0 all with opt lsrr
block in quick on dc0 all with opt ssrr
# Block nmap OS fingerprint attempts
# Log first occurrence of these so I can get their IP address
block in log first quick on dc0 proto tcp from any to any flags FUP
# Block anything with special options
block in quick on dc0 all with ipopts
# Block public pings
block in quick on dc0 proto icmp all icmp-type 8
# Block ident
block in quick on dc0 proto tcp from any to any port = 113
# Block all Netbios service. 137=name, 138=datagram, 139=session
# Netbios is MS/Windows sharing services.
# Block MS/Windows hosts2 name server requests 81
block in log first quick on dc0 proto tcp/udp from any to any port = 137
block in log first quick on dc0 proto tcp/udp from any to any port = 138
block in log first quick on dc0 proto tcp/udp from any to any port = 139
block in log first quick on dc0 proto tcp/udp from any to any port = 81
# Allow traffic in from ISP's DHCP server. This rule must contain
# the IP address of your ISP’s DHCP server as it’s the only
# authorized source to send this packet type. Only necessary for
# cable or DSL configurations. This rule is not needed for
# ‘user ppp’ type connection to the public internet.
# This is the same IP address you captured and
# used in the outbound section.
pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state
# Allow in standard www function because I have apache server
pass in quick on dc0 proto tcp from any to any port = 80 flags S keep state
# Allow in non-secure Telnet session from public Internet
# labeled non-secure because ID/PW passed over public internet as clear text.
# Delete this sample group if you do not have telnet server enabled.
#pass in quick on dc0 proto tcp from any to any port = 23 flags S keep state
# Allow in secure FTP, Telnet, and SCP from public Internet
# This function is using SSH (secure shell)
pass in quick on dc0 proto tcp from any to any port = 22 flags S keep state
# Block and log only first occurrence of all remaining traffic
# coming into the firewall. The logging of only the first
# occurrence stops an ‘denial of service’ attack targeted
# at filling up your log file space.
# This rule enforces the block all by default logic.
block in log first quick on dc0 all
################### End of rules file #####################################
NAT Explanation
NAT stands for Network Address Translation. To those familiar with Linux, this concept is called IP Masquerading, NAT and IP Masquerading are the same thing. One of the many things the IPF NAT function enables, is the ability to have an private Local area network (LAN) behind the firewall sharing an single ISP assigned IP address to the public internet.
You ask why would someone want to do this. ISP’s normally assign an dynamic IP address to their non-commercial users. Dynamic means the IP address can be different each time you dial in and logon to your ISP, or for cable and DSL modem users when you power off and then power on your modems you can get assigned an different IP address. This IP address is how you are known to the public internet.
Now lets say you have 5 PC’s at home and each one needs internet access. You would have to pay your ISP for an individual internet account for each PC and have 5 phone lines.
With NAT you only need a single account with your ISP, then cable your other 4 PC’s to an switch and the switch to the Nic card in your FBSD system which is going to service your LAN as an gateway. Nat will automatically translate the private LAN IP address for each separate PC on the LAN to the single public IP address as it exits the firewall bound for the public internet. It also does the reverse translation for returning packets.
Nat is most often accomplished without the approval, or knowledge, of your ISP and in most cases is grounds for your ISP terminating your account if found out. Commercial users pay a lot more for their internet connection and usually get assigned a block of static IP address which never change. The ISP also expects and consents to their Commercial customers using NAT for their internal private LANs.
There is an special range of IP addresses reserved for NATed private LAN IP address.
According to RFC 1918, you can use the following IP ranges for private nets which will never be routed directly to the public Internet.
Start IP 10.0.0.0 - Ending IP 10.255.255.255
Start IP 172.16.0.0 - Ending IP 172.31.255.255
Start IP 192.168.0.0 - Ending IP 192.168.255.255
IPNAT Command
NAT rules are loaded by using the ipnat command. Typically the NAT rules are stored in /etc/ipnat.rules. See man ipnat(1) for details.
When changing the Nat rules after Nat has been started, Make your changes to the file containing the nat rules, then run ipnat command with the –CF flags to delete the internal in use Nat rules and flush the contents of the translation table of all active entries.
ipnat –CF –f /etc/ipnat.rules # reload the nat rules
ipnat -s # Retrieve and display NAT statistics
ipnat -l # List the internal NAT table entry mappings.
ipnat -v
Turn verbose mode on, to display information relating to rule
processing and active rules/table entries.
NAT Rules
Nat rules are very flexible and can accomplish many different things to fit the needs of commercial users who have blocks of static IP address ranges assigned to them. This document is targeted at the non-commercial user who have an single dynamic IP address assigned to them by their ISP. If you are an commercial user see man ipnat(5) for details, and for sure read this, http://www.obfuscation.org/ipf/ipf-howto.html#TOC_1
The rule syntax presented here has been simplified to what is most commonly used in an non-commercial environment. For an complete rule syntax description see the man ipf page at ipnat(5) or ipnat(8).
# is used to mark the start of a comment and may appear at the end of a rule line or on its own lines. Blank lines are ignored.
Rules contain keywords, These keywords have to be coded in an specific order from left to right on the line.
For standard NAT functionality, you only need an single Nat rule.
ee /etc/ipnat.rules # add the following rule.
map dc0 10.0.10.1/29 -> 0.32
MAP = The keyword MAP starts the rule
dc0 = The interface name of the interface facing the public internet
10.0.10.1/29 = The IP address range of the private LAN
-> = Mandatory arrow symbol
0.32 = The IP address/netmask of your ISP assign IP address.
The special keyword 0.32 tells ipnat to get the public
IP address of the interface specified on this statement and
substitute it for the 0.32 keyword.
How NAT works
A packet arrives at the firewall from the LAN with an public destination. It passes through the outbound filter rules, NAT gets his turn at the packet and applies it’s rules top down, first matching rule wins. NAT tests each of it’s rules against the packets interface name and source IP address. When an packets interface name matches an NAT rule then the [source IP address, IE: private Lan IP address] of the packet is checked to see if it falls within the IP address range specified to the left of the arrow symbol on the NAT rule. On a match the packet has it’s source IP address rewritten with the public IP address obtained by the 0.32 keyword. Nat posts an entry in it’s internal NAT table so when the packet returns from the public internet it can be mapped back to it’s original private IP address and then passed to the filter rules for processing.
Enabling Nat
To enable the IPNAT function add these statements to /etc/rc.conf
gateway_enable="YES" # Enable as Lan gateway
ipnat_enable="YES" # Start ipnat function
ipnat_rules="/etc/ipnat.rules" # ipnat rules definition file
Nat for very large Lan
For networks that have large numbers of PC's on the Lan or networks with more that an single LAN the process of funneling all those private IP address into an single public IP address becomes an resource problem that may cause problems with same port numbers being used many times across many Natd Lan PC's causing collisions. There are 2 ways to relieve this resource problem.
1. Mapping Many Lan Address into Single public Address
map dc0 10.0.10.1/29 -> 0.32
In the above rule the packet's source port is unchanged from the original source port. IPNAT has the special keyword "portmap" that changes the above rule into
map dc0 10.0.10.1/29 -> 0.32 portmap tcp/udp 20000:6000
This rule now shoehorns all the translated connections (which can be tcp, udp, or tcp/udp) into the port range of 20000 to 60000.
Additionally, we can make things even easier by using the "auto" keyword to tell ipnat to determine for itself which ports are available for use, and allocate a proportional amount of them per address in your pool versus addresses being NATed:
map dc0 10.0.10.1/29 -> 0.32 portmap tcp/udp auto
2. Mapping Many Lan addresses into an Pool of static Public address.
In large Lan networks there comes an point where there are just to many Lan address to fit into an single public IP address. Change the map rule to specify an range of public IP address as follows
map dc0 10.0.10.1/29 -> 20.20.20.0/24 portmap tcp/udp 20000:60000 or
map dc0 10.0.10.1/29 -> 20.20.20.0/24 portmap tcp/udp auto or
map dc0 10.0.10.1/29 -> 20.20.20.5-20.20.20.7 portmap tcp/udp auto or even
map dc0 10.0.10.1/29 -> 20.20.20.5-20.20.20.7
Here 20.20.20.0/24 is the pool of static public IP address assigned to you by your ISP. For ranges of IP address that do not lend there self to that format you can specify it as 20.20.20.5-20.20.20.7 for an 3 address pool.
Directing traffic to Lan servers
An very common practice is to have an web server, email server, database server and Domain name server each segregated to an different PC on the Lan. In this case the traffic from these servers still have to be NATed, but there has to be some way to direct the inbound traffic to the correct Lan PC's. IPNAT has the redirection facilities of NAT to solve this problem. Lets say you have your web server on Lan address 10.0.10.25 and your single public Ip address is 20.20.20.5 you would code the rule like this
map dc0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80 or
map dc0 0/32 port 80 -> 10.0.10.25 port 80
or for an Lan Domain server on Lan address 10.0.10.33 that needs to receive public DNS info
map dc0 20.20.20.5/32 port 53 -> 10.0.10.33 port 53 udp
FTP Special Nat Handling
FTP is an dinosaur left over from the time before the internet, when research universities were leased lined together and FTP was used to share files among research Scientists. This was a time when data security was not even an idea yet. Over the years the FTP protocol became buried into the backbone of the emerging internet and it’s login ID & PW being sent in clear text was never changed to address new security concerns. FTP has 2 flavors, it can run in active mode or passive mode. The difference is in how the data channel is acquired. Passive mode is more secure as the data channel is acquired be the ordinal ftp session requester. For a real good explanation of FTP and it’s different modes read this http://www.slacksite.com/other/ftp.html
NAT has an special built in FTP proxy option which can be specified on the NAT map rule. It can monitor all outbound packet traffic for FTP active or passive start session requests and dynamically create temporary filter rules containing only the port number really in use for the data channel. This eliminates the security risk FTP normally exposes the firewall to from having large ranges of high order port numbers open. You specify the map rule like this
map dc0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp
map dc0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp
map dc0 10.0.10.0/29 -> 0/32
The first rule handles all FTP traffic for the private LAN.
The second rule handles all FTP traffic from the gateway.
The third rule handles all non-FTP traffic for the private LAN.
All the non-FTP gateway traffic is using the public IP address by default so
there is no ipnat rule needed.
The FTP map rule goes before our regular map rule. All packets are tested against the first rule from the top. Matches on interface name, then private LAN source IP address, and then is it an FTP packet. If all that matches then the special FTP proxy creates temp filter rules to let the FTP session packets pass in and out, in addition to also Nating the FTP packets. ALL LAN packets that are not FTP do not match the first rule and fall through to the third rule and are tested, matching on interface and source IP, then get NATed.
FTP Filter rules
Only one filter rule is needed for FTP if NAT FTP proxy is used
# Allow out LAN PC client FTP to public Internet
# Active and passive modes.
pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state
Three Filter rules are needed for FTP if no NAT FTP proxy used
# Allow out LAN PC client FTP to public Internet
# Active and passive modes.
pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state
# Allow out passive mode data channel high order port numbers
pass out quick on rl0 proto tcp from any to any port > 1024 flags S keep state
# Active mode let data channel in from FTP server
pass in quick on rl0 proto tcp from any to any port = 20 flags S keep state
FTP NAT proxy bug
As of FBSD 4.9 which includes IPFILTER version 3.4.31 the FTP proxy works as documented during the FTP session until the session is told to close. When the close happens packets returning from the remote FTP server are blocked and logged coming in on port 21. The NAT FTP/proxy appears to remove it’s temp rules prematurely, before receiving the response from the remote FTP server acknowledging the close. Posted problem report to ipf mailing list.
Solution is to add filter rule like this one to get rid of these unwanted log messages or do nothing and ignore FTP inbound error messages in your log. Not like you do FTP session to the public internet all the time, so this is not a big deal.
Block in quick on rl0 proto tcp from any to any port = 21