With the host locked down, the firewall rules must be configured and tested. In our example, there is an external interface, a DMZ interface, and an interface that faces the wireless network. The following firewall rules are very aggressive at limiting communication. The gateway must protect the DMZ from attacks coming from both the Internet and the wireless network. It must also protect the wireless network from attacks originating on the Internet. These requirements lead to a restrictive ruleset that errs on the side of caution.
The firewall rules on an OpenBSD host are normally stored in
/etc/pf.conf
. We will examine our firewall
script in sections to help explain the thought process that led to
this ruleset.
These four variables correspond to your outside interface, network, number of bits in the netmask, and IP address, respectively. Change these to the correct values.
# set these to your outside interface network and netmask and ip o_if = "dc0
" o_net = "192.0.2.0
" o_mask = "24
" o_ip = "192.0.2.230
"
These variables do the same thing for the wireless network (variables starting with “w”) and for the internal wired network (variables starting with “i”). Change these if you are going to use different IP ranges on these networks.
# set these to your inside interface networks, netmasks, and IPs w_if = "dc1
" w_net = "192.168.0.0
" w_mask = "24
" w_ip = "192.168.0.1
" i_if = "dc2
" i_net = "192.168.1.0
" i_mask = "24
" i_ip = "192.168.1.1
"
The parsing of OpenBSD’s pf
rules differs dramatically from the ipfw
rules
used in FreeBSD. In FreeBSD, the first rule that is matched by the
firewall is used to process the packet. In OpenBSD, it is the last
rule matched that matters. You can force the packet to exit the
ruleset by using the keyword quick
. When a packet
is matched by a quick rule, the parsing stops and the packet is acted
upon by the matched rule.
To have a deny-all ruleset, place the default-blocking rule at the top of the ruleset.
# Default deny block in log all block out log all
These rules allow traffic to and from the loopback interface to pass
through the firewall. This allows any connections that are made to
localhost
by internal processes to be
successful.
# Let loopback traffic through pass out quick on lo0 all pass in quick on lo0 all
These rules prevent spoofed packets from being passed through the firewall. A spoofed packet is a packet that appears to be from one of our three networks but actually originates on the wrong network. For example, a packet with the source IP of a wireless client should not come into the gateway from the wired network or the external network.
# Stop Spoofing block in quick on $o_if inet from { $i_net/$i_mask, $w_net/$w_mask } to any block in quick on $i_if inet from { $o_net/$o_mask, $w_net/$w_mask } to any block in quick on $w_if inet from { $i_net/$i_mask, $o_net/$o_mask } to any
This rule blocks incoming packets from the Internet destined to improper network IP ranges such as non-routable, multicast, and broadcast IP addresses.
# Stop RFC 1918 et al. block in quick on $o_if inet from { 127.0.0.0/8, 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 0.0.0.0/8, 169.254.0.0/16, 224.0.0.0/4, 240.0.0.0/4 } to any
The rule allows clients on the DMZ and wireless networks to query the caching nameserver running on the gateway. The caching nameserver is configured in Section 13.5 later in this chapter.
# allow DNS queries to our gateway pass in quick proto udp from any to { $i_ip, $o_ip, $w_ip } port 53 keep state
Allow connections to the SSH daemon from anywhere. This will allow secure administration of the gateway from anyplace the operator may be.
# Allow SSH connection pass in quick proto tcp from any to { $i_ip, $o_ip, $w_ip } port 22 flags S/SA keep state
This rule will log and block all attempted TCP setup attempts against the external interface.
# Reject and log all setup of incoming connections from the outside block in log quick proto tcp on $o_if from any to any flags S/SA
These rules prevent communication between the wireless network and the DMZ. The wireless network may contain attackers attempting to subvert your firewall in an effort to get to the DMZ. The DMZ must protect itself from the wireless network as if it were the Internet.
# Reject connections between the wireless network and DMZ network block in quick on $w_if inet from any to $i_net/$i_mask block in quick on $i_if inet from any to $w_net/$w_mask
These rules allow outbound connections from the DMZ and wireless networks to the rest of the network. We are allowing the outbound connections that are sourced from the external IP address of the gateway with the assumption that the NAT rules will be configured to use that IP address. Note that since the connections are outbound on the outside interface, the connections to the gateway itself are still dropped. Also, any other connections not explicitly allowed in this ruleset are now dropped by the block-all rule at the top.
# Allow all outbound connections from the DMZ and wireless networks pass in quick on $w_if proto tcp from $w_net/$w_mask to any flags S/SA keep state pass in quick on $w_if proto { udp, icmp } from $w_net/$w_mask to any keep state pass in quick on $i_if proto tcp from $i_net/$i_mask to any flags S/SA keep state pass in quick on $i_if proto { udp, icmp } from $i_net/$i_mask to any keep state pass out quick on $o_if proto tcp from $o_ip to any flags S/SA keep state pass out quick on $o_if proto { udp, icmp } from $o_ip to any keep state
Rules stored in /etc/pf.conf
will be loaded at
boot time. If you make a change to the firewall rules and want to
update them at runtime, use the pfctl
utility.
These commands will flush the firewall rules and then reload
them:
# pfctl -F rules # pfctl -R /etc/pf.conf
The reality of deploying a network in this day and age is that you will end up needing to translate your internal networks to a limited number of public IP addresses. The process, called Network Address Translation (NAT) can be a very complicated process on some operating systems. Thankfully, on OpenBSD it is straightforward procedure with a very robust feature set. Rather than run NAT as a userland process, NAT support is provided directly by the kernel through the packet filter that also provides firewalling capabilities.
The NAT configuration is controlled by directives stored in
/etc/nat.con
f. Here is the example file that
corresponds with the previous firewall
ruleset:
# /etc/natd.conf nat on dc0 from 192.168.0.0/24 to any -> dc0 nat on dc0 from 192.168.1.0/24 to any -> dc0
This configuration causes NAT to act on packets that cross the
dc0
interface. Any packet from either internal
network will be translated to the IP address of the outside
interface. This is a very simple configuration. OpenBSD can perform
bidirectional NAT’ing where one internal IP address
maps to one external IP address. There is also a redirection
capability within the NAT implementation to allow for source and
destination port manipulation. For a complete listing and explanation
of NAT, see the nat.conf
manual page.
If you make a change to nat.conf
, you can force
the packet filter to reload the rules using the
pfctl
utility. The following command will flush
the old NAT rules and load the new ones from
/etc/nat.conf
:
# pfctl -F nat # pfctl -N /etc/nat.conf
3.142.96.146