### Macros
ext_if="tun0" # External interface
int_if="fxp0" # Internal interface
pri_addr="10.10.2.3" # My address
### Tables
# Non-public/weird addresses, doesn't include our 10.10.x.x subnet, anything in here shouldn't be going anywhere
table <banned> { 192.168.0.0/16, 192.0.2.0/24, 172.16.0.0/12, 127.0.0.0/8, 0.0.0.0/8, 169.254.0.0/16, 224.0.0.0/3,
204.152.64.0/23 }
### Options
# We want to sent ICMP RST or unreachable when a packet is blocked, if we don't people have to wait for a timeout
set block-policy return
### Filtering
# Let all loopback traffic through
pass quick on lo0
# no traffic is trying to get into the loopback interface from outside.
block quick from any to lo0:network
#--- Making sure all traffic is coming to/going from the right interface
# Make sure no banned addresses are around
block quick from <banned> to any
block quick from any to <banned>
# all traffic to/from the internal network is addressed to/from the internal network
block in quick on $int_if from ! $int_if:network to any
block out quick on $int_if from any to ! $int_if:network
# all traffic to/from the external network is addressed to/from our external address specifically
# $ext_if is in brackets because the IP is dynamic, in brackets pf knows the IP may change
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
block log all
[...]
### Filtering
# Let all loopback traffic through
pass quick on lo0
# no traffic is trying to get into the loopback interface from outside.
block quick from any to lo0:network
#--- Making sure all traffic is coming to/going from the right interface
# Make sure no banned addresses are around
block quick from <banned> to any
block quick from any to <banned>
# all traffic to/from the internal network is addressed to/from the internal network
block in quick on $int_if from ! $int_if:network to any
block out quick on $int_if from any to ! $int_if:network
# all traffic to/from the external network is addressed to/from our external address specifically
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
#>>> From this box
#--- Don't let restricted users initiate their own connections
# icmp doesn't seem to be associated with user accounts, so we have to
# specify tcp and udp
block log quick proto { tcp, udp } from any to any user \
{ www, mysql, pgsql, conrad, algis, nobody, games, news, man, smmsp, mailnull, pop, uucp, bind }
#--- Allow outbound connections from this server
pass out quick on $int_if proto { tcp, udp, icmp } from $int_if to $int_if:network keep state
pass out quick on $ext_if proto { tcp, udp, icmp } from ($ext_if) to any keep state
# We can check what gets caught here to see if we've missed anything
block log all
[...]
### Translation: specify how addresses are to be mapped or redirected.
# nat: packets going out through $ext_if with source address in the network will
# get translated as coming from the address of $ext_if, a state is created for
# such packets, and incoming packets will be redirected to the internal address.
nat on $ext_if proto { tcp, udp, icmp } from $int_if:network to ! $int_if -> ($ext_if)
### Filtering
# Let all loopback traffic through
[...]
[...]
# all traffic to/from the external network is addressed to/from our external address specifically
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
#<<< Through this box >>>
#--- Allow NAT traffic out, create a state so traffic can get back in
pass in quick on $int_if proto { tcp, udp, icmp } from $int_if:network to ! $int_if keep state
#>>> From this box
#--- Don't let restricted users initiate their own connections
block out log quick from any to any user \
{ www, pgsql, conrad, algis, nobody, toor, games, news, man, smmsp, mailnull, pop, uucp, bind }
#--- Allow outbound connections from this server
pass out quick on $int_if proto { tcp, udp, icmp } from $int_if to $int_if:network keep state
pass out quick on $ext_if proto { tcp, udp, icmp } from ($ext_if) to any keep state
# We can check what gets caught here to see if we've missed anything
block log all
[...]
# all traffic to/from the external network is addressed to/from our external address specifically
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
#<<< To this box
#--- Internal services, there aren't many people internally but each'll be using lots of connections
# httpd, samba, and the proxy servers
# 2000 max states, 20 max users, 100 max states per user
pass in quick on $int_if proto tcp from any to $int_if port { www, 445, 139, 3001, 3128 } flags S/SA \
keep state (max 2000, source-track rule, max-src-nodes 20, max-src-states 100)
# Treat sshd differently so that even if all other services are maxed out sshd will be available
pass in quick on $int_if proto tcp from any to $int_if port ssh flags S/SA \
keep state (max 20, source-track rule, max-src-nodes 2, max-src-states 10)
# If it's still inbound, coming specifically to this box, it's not using our services, then don't let it in.
# This rule is probably redundant as any traffic still coming in will fall into the 'block log all' at the end
# but it's reassuring that you don't have to worry about traffic coming in from here on out.
block in log quick from any to { $int_if, ($ext_if) }
#<<< Through this box >>>
#--- Allow NAT traffic out, create a state so traffic can get back in
pass in quick on $int_if proto { tcp, udp, icmp } from $int_if:network to ! $int_if keep state
#>>> From this box
#--- Don't let restricted users initiate their own connections
block out log quick from any to any user \
{ www, pgsql, conrad, algis, nobody, toor, games, news, man, smmsp, mailnull, pop, uucp, bind }
#--- Allow outbound connections from this server
pass out quick on $int_if proto { tcp, udp, icmp } from $int_if to $int_if:network keep state
pass out quick on $ext_if proto { tcp, udp, icmp } from ($ext_if) to any keep state
# We can check what gets caught here to see if we've missed anything
block log all
[...]
# all traffic to/from the external network is addressed to/from our external address specifically
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
#<<< To this box
#--- Globally accessible services
# sshd from external; this gets attacked every couple of days so we have to carefully limit this:
# 10 max states, 5 different users at once, 2 connections per user, 2 connections per minute
# and when an IP surpasses any of these restrictions add them to the banned list
pass in log quick on $ext_if proto tcp from any to ($ext_if) port ssh flags S/SA \
synproxy state (max 30, source-track rule, max-src-nodes 10, max-src-states 2, \
max-src-conn 2, max-src-conn-rate 2/60, overload <banned>)
# httpd, more relaxed settings as users will grab lots of things like images on a page all at once
# 1000 max states, 50 different users at once, 30 connections per user, etc
pass in log quick on $ext_if proto tcp from any to ($ext_if) port www flags S/SA \
synproxy state (max 1000, source-track rule, max-src-nodes 50, max-src-states 30, \
max-src-conn 30, overload <banned>)
#--- Internal services, there aren't many people internally but each'll be using lots of connections
# httpd, samba, and the proxy servers
# 2000 max states, 20 max users, 100 max states per user
pass in quick on $int_if proto tcp from any to $int_if port { www, 445, 139, 3001, 3128 } flags S/SA \
keep state (max 2000, source-track rule, max-src-nodes 20, max-src-states 100)
# Treat sshd differently so that even if all other services are maxed out sshd will be available
pass in quick on $int_if proto tcp from any to $int_if port ssh flags S/SA \
keep state (max 20, source-track rule, max-src-nodes 2, max-src-states 10)
# If it's still inbound, coming specifically to this box, it's not using our services, then don't let it in.
# This rule is probably redundant as any traffic still coming in will fall into the 'block log all' at the end
# but it's reassuring that you don't have to worry about traffic coming in from here on out.
block in log quick from any to { $int_if, ($ext_if) }
[...]
---------------------
---->tocomp1 (50 packets)
---------------------
---->tocomp2 (50 packets)
--------------------- -----------------
---->tocomp3 (50 packets) parent 512Kb ---->
--------------------- -----------------
---->tocomp4 (50 packets)
---------------------
---->tocomp5 (50 packets)
---------------------
[...]
### Options
# We want to sent ICMP RST or unreachable when a packet is blocked, if we don't people have to wait for a timeout
set block-policy return
# Bind states to interfaces so we can have a queue for each interface
set state-policy if-bound
[...]
[...]
# If it's still inbound, coming specifically to this box, it's not using our services, then don't let it in.
# This rule is probably redundant as any traffic still coming in will fall into the 'block log all' at the end
# but it's reassuring that you don't have to worry about traffic coming in from here on out.
block in log quick from any to { $int_if, ($ext_if) }
#<<< Through this box >>>
#--- Let out NAT traffic from the internal network to the internet
# Tag it so that when it gets run through the filter again on the external interface we'll know
# that it came from a priority (pri) or default (def) address.
# If we were going to restrict outbound traffic (eg restricting access to http services or banning
# certain websites) we would do it here
pass in quick on $int_if from $pri_addr to ! $int_if keep state tag fromint_pri
pass in quick on $int_if from ! $pri_addr to ! $int_if keep state tag fromint_def
# We have to create a state on the external interface for traffic that has been passed, so that we can
# create an upload queue.
pass out quick on $ext_if tagged fromint_pri keep state
pass out quick on $ext_if tagged fromint_def keep state
#>>> From this box
#--- Don't let restricted users initiate their own connections
block out log quick from any to any user \
{ www, pgsql, conrad, algis, nobody, toor, games, news, man, smmsp, mailnull, pop, uucp, bind }
#--- Allow outbound connections from this server
pass out quick on $int_if proto { tcp, udp, icmp } from $int_if to $int_if:network keep state
pass out quick on $ext_if proto { tcp, udp, icmp } from ($ext_if) to any keep state
[...]
[...]
### Tables
# Non-public/weird addresses, doesn't include our 10.10.x.x subnet, anything in here shouldn't be going anywhere
table <banned> { 192.168.0.0/16, 192.0.2.0/24, 172.16.0.0/12, 127.0.0.0/8, 0.0.0.0/8, 169.254.0.0/16, 224.0.0.0/3,
204.152.64.0/23 }
### Queueing: rule-based bandwidth control.
# Internal interface; download queue
altq on $int_if bandwidth 100Mb hfsc queue { ether, nattraffic }
queue ether hfsc ( default, upperlimit 70% ) bandwidth 10% priority 0
# Ethernet traffic
queue nattraffic hfsc ( upperlimit 400Kb ) bandwidth 420Kb { toint_pri, toint_def }
queue toint_pri qlimit 10 hfsc ( red, realtime 35%, linkshare 50% ) priority 4 bandwidth 70%
queue toint_def qlimit 10 hfsc ( red, realtime 15%, linkshare 30% ) priority 3 bandwidth 20%
# External interface; upload queue
altq on $ext_if hfsc ( upperlimit 90Kb ) bandwidth 100Kb queue { fromint_pri, fromint_def, server, fromint_ack }
# External interface, stuff which goes out on this interface has 128Kb bandwidth
queue fromint_pri hfsc ( realtime 20Kb ) bandwidth 10%
queue fromint_def hfsc ( realtime 40Kb ) bandwidth 10%
# From others
queue server hfsc ( default ) bandwidth 10%
# To the server from external
queue fromint_ack hfsc ( realtime 5Kb ) bandwidth 10% priority 7
# TCP ACK packets, saying we've got a packet, we have to get these off asap
### Translation: specify how addresses are to be mapped or redirected.
[...]
[...]
### Options, most of these default are fine
# We want to sent ICMP RST or unreachable
set block-policy return
# Bind states to interfaces so we can have a queue for each interface
set state-policy if-bound
### Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
scrub on $ext_if all random-id reassemble tcp fragment reassemble
scrub on $int_if all random-id reassemble tcp fragment reassemble
# random-id: Randomize IP ID fields to protect againt packet injections by ID prediction
# reassemble tcp: Protect against some DoS and info gathering attacks
# fragment reassemble: Packet fragments are reassembled before processing, it's forced when using NAT anyway
# Don't normalize traffic on the loopback
### Queueing: rule-based bandwidth control.
[...]
### Macros
ext_if="tun0" # External interface
int_if="fxp0" # Internal interface
pri_addr="10.10.2.3" # My address
### Tables
# Non-public/weird addresses, doesn't include our 10.10.x.x subnet, anything in here shouldn't be going anywhere
table <banned> { 192.168.0.0/16, 192.0.2.0/24, 172.16.0.0/12, 127.0.0.0/8, 0.0.0.0/8, 169.254.0.0/16, 224.0.0.0/3,
204.152.64.0/23 }
### Options, most of these default are fine
# We want to sent ICMP RST or unreachable
set block-policy return
# Bind states to interfaces so we can have a queue for each interface
set state-policy if-bound
### Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
scrub on $ext_if all random-id reassemble tcp fragment reassemble
scrub on $int_if all random-id reassemble tcp fragment reassemble
# random-id: Randomize IP ID fields to protect againt packet injections by ID prediction
# reassemble tcp: Protect against some DoS and info gathering attacks
# fragment reassemble: Packet fragments are reassembled before processing, it's forced when using NAT anyway
# Don't normalize traffic on the loopback
### Queueing: rule-based bandwidth control.
# Internal interface; download queue
altq on $int_if bandwidth 100Mb hfsc queue { ether, nattraffic }
queue ether hfsc ( default, upperlimit 70% ) bandwidth 10% priority 0
# Ethernet traffic
queue nattraffic hfsc ( upperlimit 400Kb ) bandwidth 420Kb { toint_pri, toint_def }
queue toint_pri qlimit 10 hfsc ( red, realtime 35%, linkshare 50% ) priority 4 bandwidth 70%
queue toint_def qlimit 10 hfsc ( red, realtime 15%, linkshare 30% ) priority 3 bandwidth 20%
# External interface; upload queue
altq on $ext_if hfsc ( upperlimit 90Kb ) bandwidth 100Kb queue { fromint_pri, fromint_def, server, fromint_ack }
# External interface, stuff which goes out on this interface has 128Kb bandwidth
queue fromint_pri hfsc ( realtime 20Kb ) bandwidth 10%
queue fromint_def hfsc ( realtime 40Kb ) bandwidth 10%
# From others
queue server hfsc ( default ) bandwidth 10%
# To the server from external
queue fromint_ack hfsc ( realtime 5Kb ) bandwidth 10% priority 7
# TCP ACK packets, saying we've got a packet, we have to get these off asap
### Translation: specify how addresses are to be mapped or redirected.
# nat: packets going out through $ext_if with source address $internal_net will
# get translated as coming from the address of $ext_if, a state is created for
# such packets, and incoming packets will be redirected to the internal address.
nat on $ext_if proto { tcp, udp, icmp } from $int_if:network to ! $int_if -> ($ext_if)
# rdr local mail to remote mail, for those who don't like using NAT
rdr on $int_if proto tcp from $int_if:network to $int_if port 2525 -> mail.kuliukas.com port 2525
rdr on $int_if proto tcp from $int_if:network to $int_if port 1100 -> mail.kuliukas.com port 110
### Filtering
# Let all loopback traffic through
pass quick on lo0
# no traffic is trying to get into the loopback interface from outside.
block quick from any to lo0:network
#--- Making sure all traffic is coming to/going from the right interface
# Make sure no banned addresses are around
block quick from <banned> to any
block quick from any to <banned>
# all traffic to/from the internal network is addressed to/from the internal network
block in quick on $int_if from ! $int_if:network to any
block out quick on $int_if from any to ! $int_if:network
# all traffic to/from the external network is addressed to/from our external address specifically
block in quick on $ext_if from any to ! ($ext_if)
block out quick on $ext_if from ! ($ext_if) to any
#<<< To this box
#--- Globally accessible services
# sshd from external; this gets attacked every couple of days so we have to carefully limit this:
# 10 max states, 5 different users at once, 2 connections per user, 2 connections per minute
# and when an IP surpasses any of these restrictions add them to the banned list
pass in log quick on $ext_if proto tcp from any to ($ext_if) port ssh flags S/SA \
keep state (max 30, source-track rule, max-src-nodes 10, max-src-states 2, \
max-src-conn 2, max-src-conn-rate 2/60, overload <banned>) queue ( server, fromint_ack )
# httpd, more relaxed settings as users will grab lots of things like images on a page all at once
# 1000 max states, 50 different users at once, 30 connections per user, etc
pass in log quick on $ext_if proto tcp from any to ($ext_if) port www flags S/SA \
keep state (max 1000, source-track rule, max-src-nodes 50, max-src-states 30, \
max-src-conn 30, overload <banned>) queue ( server, fromint_ack )
#--- Internal services, there aren't many people internally but each'll be using lots of connections
# httpd, samba, and the proxy servers
# 2000 max states, 20 max users, 100 max states per user
pass in quick on $int_if proto tcp from any to $int_if port { www, 445, 139, 3001, 3128 } flags S/SA \
keep state (max 2000, source-track rule, max-src-nodes 20, max-src-states 100) queue ether
# Treat sshd differently so that even if all other services are maxed out sshd will be available
pass in quick on $int_if proto tcp from any to $int_if port ssh flags S/SA \
keep state (max 20, source-track rule, max-src-nodes 2, max-src-states 10) queue ether
# If it's still inbound, coming specifically to this box, it's not using our services, then don't let it in.
# This rule is probably redundant as any traffic still coming in will fall into the 'block log all' at the end
# but it's reassuring that you don't have to worry about traffic coming in from here on out.
block in log quick from any to { $int_if, ($ext_if) }
#<<< Through this box >>>
#--- Let out NAT traffic from the internal network to the internet
# Tag it so that when it gets run through the filter again on the external interface we'll know
# that it came from a priority (pri) or default (def) address.
# If we were going to restrict outbound traffic (eg restricting access to http services or banning
# certain websites) we would do it here
pass in quick on $int_if from $pri_addr to ! $int_if keep state tag fromint_pri queue ( toint_pri )
pass in quick on $int_if from ! $pri_addr to ! $int_if keep state tag fromint_def queue ( toint_def )
# We have to create a state on the external interface for traffic that has been passed, so that we can
# create an upload queue.
pass out quick on $ext_if tagged fromint_pri keep state queue ( fromint_pri, fromint_ack )
pass out quick on $ext_if tagged fromint_def keep state queue ( fromint_def, fromint_ack )
#>>> From this box
#--- Don't let restricted users initiate their own connections
block out log quick from any to any user \
{ www, pgsql, conrad, algis, nobody, toor, games, news, man, smmsp, mailnull, pop, uucp, bind }
#--- Allow outbound connections from this server
pass out quick on $int_if proto { tcp, udp, icmp } from $int_if to $int_if:network keep state queue ether
pass out quick on $ext_if proto { tcp, udp, icmp } from ($ext_if) to any keep state queue ( server, fromint_ack )
# We can check what gets caught here to see if we've missed anything
block log all