Firewall Access Policy Rulesets, Part 2 - Page 2
Anti-spoofing rules
Generally speaking, IP spoofing is a technique of generating IP packets with source address that belongs to someone else. Spoofing creates a danger when hosts on the LAN permit access to their resources and services to trusted hosts by checking the source IP of the packets. Using spoofing, an intruder can fake the source address of his packets and make them look like they originated on the trusted hosts. The basic idea of anti-spoofing protection is to create a firewall rule assigned to the external interface of the firewall that examines source address of all packets crossing that interface coming from outside. If the address belongs to the internal network or the firewall itself, the packet is dropped.
Simple anti-spoofing rule looks like shown on the next screenshot. Unlike the rule in the previous example, anti-spoofing rule requires matching of the interface and direction. The idea is that packets that come from outside must not have source addresses that match internal network or the firewall itself. The only way to distinguish packets coming from outside from those coming from inside is to check which interface of the firewall they cross and in which direction. Here the rule matches interface
Article Using Firewall Object In Firewall Builder explains how a firewall object and its interfaces can be created. Article Firewall Access Policy Rulesets, Part 1 explains the concept of direction.
Here are the iptables commands generated for this rule:
# Rule 0 (eth0) # # anti spoofing rule # $IPTABLES -N In_RULE_0 $IPTABLES -A INPUT -i eth0 -s 192.0.2.1 -j In_RULE_0 $IPTABLES -A INPUT -i eth0 -s 192.168.1.1 -j In_RULE_0 $IPTABLES -A INPUT -i eth0 -s 192.168.1.0/24 -j In_RULE_0 $IPTABLES -A FORWARD -i eth0 -s 192.0.2.1 -j In_RULE_0 $IPTABLES -A FORWARD -i eth0 -s 192.168.1.1 -j In_RULE_0 $IPTABLES -A FORWARD -i eth0 -s 192.168.1.0/24 -j In_RULE_0 $IPTABLES -A In_RULE_0 -j LOG --log-level info --log-prefix "RULE 0 -- DENY " $IPTABLES -A In_RULE_0 -j DROP
Iptables commands were placed in INPUT and FORWARD chains to match both packets that are headed for the firewall and through the firewall to hosts behind it. Rules match source address of the packets and then log and drop them. Fwbuilder generated iptables commands to match all addresses of the firewall (192.168.1.1, 192.0.2.1) and network behind it (192.168.1.0/24).
Lets see what gets generated for the same rule for PF:
# Tables: (1) table <tbl.r0.s> { 192.0.2.1 , 192.168.1.1 } # Rule 0 (en0) # anti spoofing rule # block in log quick on en0 inet from <tbl.r0.s> to any block in log quick on en0 inet from 192.168.1.0/24 to any #
Here compiler uses tables to make generated PF code more compact. Table
Here is the same rule, compiled for PIX:
! Rule 0 (Ethernet1/0) ! anti-spoofing rule ! access-list outside_acl_in remark 0 (Ethernet1/0) access-list outside_acl_in remark anti-spoofing rule access-list outside_acl_in deny ip host 192.0.2.1 any access-list outside_acl_in deny ip host 192.168.2.1 any access-list outside_acl_in deny ip host 192.168.1.1 any access-list outside_acl_in deny ip 192.168.1.0 255.255.255.0 any access-group outside_acl_in in interface outside
Anti-spoofing rules for the firewall with dynamic address
Anti-spoofing rule must match all addresses of the firewall to leave no holes. However it is difficult to do if one interface of the firewall gets its ip address dynamically via DHCP or PPP protocol. This address is unknown at the compile time and proper configuration can not be generated by just including it. Some firewall platforms have syntax in their configuration language that provides a way to match an address of an interface at run time, but other platforms do not have anything like this. Lets see how fwbuilder works around this problem.
In this test I use variation of the same firewall object where external interface
Generated iptables script looks like this:
getaddr eth0 i_eth0 # Rule 0 (eth0) # # anti spoofing rule # $IPTABLES -N In_RULE_0 test -n "$i_eth0" && $IPTABLES -A INPUT -i eth0 -s $i_eth0 -j In_RULE_0 $IPTABLES -A INPUT -i eth0 -s 192.168.1.1 -j In_RULE_0 $IPTABLES -A INPUT -i eth0 -s 192.168.1.0/24 -j In_RULE_0 test -n "$i_eth0" && $IPTABLES -A FORWARD -i eth0 -s $i_eth0 -j In_RULE_0 $IPTABLES -A FORWARD -i eth0 -s 192.168.1.1 -j In_RULE_0 $IPTABLES -A FORWARD -i eth0 -s 192.168.1.0/24 -j In_RULE_0 $IPTABLES -A In_RULE_0 -j LOG --log-level info --log-prefix "RULE 0 -- DENY " $IPTABLES -A In_RULE_0 -j DROP
The script defines shell function
Here is what is generated for PF:
table <tbl.r0.d> { en0 , 192.168.1.1 } # Rule 0 (en0) # anti spoofing rule # block in log quick on en0 inet from <tbl.r0.d> to any block in log quick on en0 inet from 192.168.1.0/24 to any
In PF, one can place interface name ("en0") in the table and PF will use its address at the execution time.
Unfortunately there is no workaround for this problem for PIX.
Using groups
Sometimes we need to define a lot of very similar rules for multiple hosts or networks. For example, there may be a need to permit the same service to 10 different hosts on the network, while still blocking it to all others. The simplest way to accomplish this is to add 10 rules with the same source and service fields and just different destinations. Another method is to add 10 objects to the Source or Destination rule element of the same rule. Both methods can make firewall policy quite cluttered and hardly readable. To avoid this we can use groups. Group is just a container which includes references to multiple objects of the same or similar type. Firewall Builder supports groups of objects and groups of services. You can put
Groups not only make policy rules more readable, another great advantage of object groups is that they are reusable. You can now have many different rules using this same group object. If you ever need to add another host or address to the group, you only need to do it once and all rules will automatically pick the change after recompile.
To add objects to a group simply drag them from the tree on the left into group view on the right, or use Copy/Paste functions available via menus.
Once appropriate group has been created, it can be used for the policy and NAT rules just like any other object.
Here is iptables commands generated for this example:
# Rule 0 (global) # $IPTABLES -N Cid17843X27745.0 $IPTABLES -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j Cid17843X27745.0 $IPTABLES -A Cid17843X27745.0 -s 192.168.1.110 -j ACCEPT $IPTABLES -A Cid17843X27745.0 -s 192.168.1.111 -j ACCEPT $IPTABLES -A Cid17843X27745.0 -s 192.168.1.112 -j ACCEPT
Generated iptables command is placed only in the
Compiler decides whether to use temporary chain not because administrator used object group in source in the original rule in the GUI, but because it determined that in the end it needs to compare source address of the packet against several addresses defined in the policy. If the group contained just one address, the generated iptables script would have consisted of just one iptables command without temporary chain. If there was no group in "Source" of the rule but instead all these host objects were placed in "source" of the rule directly, generated iptables script would look exactly like shown above, using temporary chain for optimization.
Here is the code generated for PF for the same rule:
table <tbl.r0.d> { 192.0.2.1 , 192.168.1.1 } table <tbl.r0.s> { 192.168.1.110 , 192.168.1.111 , 192.168.1.112 } # Rule 0 (global) # pass quick inet proto tcp from <tbl.r0.s> to <tbl.r0.d> port 22 keep state
Policy compiler for PF extensively uses tables to produce compact code. PF tables are reused when needed.
Here is the config generated for PIX:
object-group network inside.id20599X27745.src.net.0 network-object host 192.168.1.110 network-object host 192.168.1.111 network-object host 192.168.1.112 exit ! Rule 0 (global) ! access-list inside_acl_in remark 0 (global) access-list inside_acl_in permit tcp object-group inside.id20599X27745.src.net.0 host 192.0.2.1 eq 22 access-list inside_acl_in permit tcp object-group inside.id20599X27745.src.net.0 host 192.168.1.1 eq 22 !
Just like in case of iptables, it is not that a group object was used in the original rule what triggered using
Using Address Range instead of a group
In the example above, three hosts used for the group
Since addresses of the management hosts are consecutive, we can use Address Range object to describe them:
We use this object in the rule just like any other object. Here is how the rule looks like:
The main difference in generated code for the rule using Address Range compared to the rule using collection of individual addresses is that compiler is allowed to optimize it. It tries to squeeze the address range to the minimal set of address and network objects. Here is how it looks like for iptables:
# Rule 0 (global) # $IPTABLES -A INPUT -s 192.168.1.110/31 -m state --state NEW -j ACCEPT $IPTABLES -A INPUT -s 192.168.1.112 -m state --state NEW -j ACCEPT
Again, the difference may not be very great when we have only three ip addresses, but in case of a range that spans hundred addresses the performance gain and reduction in the size of generated script are significant.
Generated PF and PIX configurations look similar.
We will contniune with even more complex examples of policy access rules in the next article.
References:
- Project web site: http://www.fwbuilder.org/
- Source code, Linux .deb and .rpm package repositories, Windows and Mac OS X binary packages
- Firewall Builder Users Guide (PDF)
- Firewall Builder Users Guide (HTML)
- Examples of iptables, pf and other rules: Firewall Builder Cookbook
- Project announcements and status: Firewall Builder Project Blog