Synopsis
This quickie howto describes the steps necessary to configure a system acting as a firewall/router using OpenBSD’s Packet Filter (PF) software to provide proactive defense against simple Denial of Service (DoS) attacks and brute force attacks. This post assumes that the firewall/router has already been configured and is running PF with two NIC’s; one facing the Internet and one facing the local area network (LAN).
Sample NAT Ruleset
Below is an example of a very basic PF ruleset used on a system providing firewall and Network Address Translation (NAT). The ruleset defines the external NIC (ext_if), the internal NIC (int_if), the local network (localnet), and a list of TCP services that are allowed to connect to the system from the outside (tcp_services).
ext_if = "ath0"
int_if = "dc0"
localnet = $int_if:network
tcp_services = "{ ssh, http }"
nat on $ext_if from $localnet to any -> ($ext_if)
block all
scrub in all
antispoof for $ext_if
antispoof for $int_if
pass from { lo0, $localnet } to any keep state
pass in inet proto tcp from any to $ext_if port $tcp_services
Adding Simple Proactive Protection
The new ruleset will need a persistent table to store IP addresses that have attempted to DoS or brute force the TCP services that have been allowed in. Create a table called bruteforce and add a block statement early in the ruleset to block the hosts in the bruteforce table. The sample ruleset would now look like the following:
ext_if = "ath0"
int_if = "dc0"
localnet = $int_if:network
tcp_services = "{ ssh, http }"
table <bruteforce> persist
nat on $ext_if from $localnet to any -> ($ext_if)
block all
block quick from <bruteforce>
scrub in all
antispoof for $ext_if
antispoof for $int_if
pass from { lo0, $localnet } to any keep state
pass in inet proto tcp from any to $ext_if port $tcp_services
Now modify the last rule that allows traffic on the specified TCP services in. The max-src-conn option specifies how many concurrent connections from a single IP address are allowed and the max-src-rate option specifies how many connection attempts per second are allowed (5 attempts every 5 seconds in the example below). The finished sample ruleset would now look like the following:
ext_if = "ath0"
int_if = "dc0"
localnet = $int_if:network
tcp_services = "{ ssh, http }"
table <bruteforce> persist
nat on $ext_if from $localnet to any -> ($ext_if)
block all
block quick from <bruteforce>
scrub in all
antispoof for $ext_if
antispoof for $int_if
pass from { lo0, $localnet } to any keep state
pass in inet proto tcp from any to $ext_if port $tcp_services \
keep state (max-src-conn 10, max-src-rate 5/5, \
overload <bruteforce> flush global)
Restart the system for the new PF ruleset to take effect.
References
[EoF]