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 eth0, which is external, and direction inbound.

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 tbl.r0.s can be used in other rules wherever we need to operate with all addresses of the firewall.

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 "eth0" is configured as "dynamic". The anti-spoofing rule looks exactly like the rule in the previous example and matches the same external interface "eth0", direction "inbound":

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 "getaddr" at the beginning. This function uses "ip addr show" command to determine actual address of the interface at the time when script is running and assigns the address to the shell variable i_eth0. Iptables commands then use this variable to build rules matching address of this interface. Otherwise generated rules are the same as in the previous example.

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 "Address", "Host", "Network" and "Firewall" objects in an object group, but you cannot put service objects in a such group. Similarly, a service group can contain "IP Service", "TCP Service", "UDP Service" and "ICMP Service" objects, but cannot contain hosts or networks. Groups can contain other groups of the same type as well. Screenshot below represents object group used in this example.

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 INPUT chain because it controls access to the firewall and not to any addresses across it. The first iptables command matches chain, tcp port and state. If this rule does not match the packet, there is no need to waste CPU cycles checking source ip addresses. However if the first rule matches, it passes control to the special user-defined chain "Cid17843X27745.0" where it checks source address of the packet. If compiler were to generate iptables script not using this temporary chain, it would end up comparing tcp port and state three times, together with each possible source address. This can be rather wasteful if the rule should match a lot of addresses. Separation of the matches using temporary chain can improve performance a lot.

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 object-group PIX clause. Compiler always checks the number of objects it needs to compare the packet against and uses object-groups statements to optimize generated code as appropriate.

 

Using Address Range instead of a group

In the example above, three hosts used for the group "management hosts" have consecutive addresses 192.168.1.110, 192.168.1.111, 192.168.1.112. Although this example may be artificial, it allows us to illustrate how a different type of object could be used to achieve the same goal - to permit access to the firewall from these three addresses. The difference may be negligible when we deal with just three addresses, but when the list gets into hundreds it may become significant.

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:

Share this page:

0 Comment(s)