Skip to content

Instantly share code, notes, and snippets.

@nathwill
Last active August 23, 2025 23:31
Show Gist options
  • Select an option

  • Save nathwill/9703175 to your computer and use it in GitHub Desktop.

Select an option

Save nathwill/9703175 to your computer and use it in GitHub Desktop.

Revisions

  1. nathwill revised this gist Mar 23, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -107,9 +107,9 @@ match out on $ext_if from $int_inet_net to any \

    # Permit rate-limited ICMP
    pass inet proto icmp all icmp-type $icmp_types \
    (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    pass inet6 proto icmp6 all icmp6-type $icmp_types \
    (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)

    # Allow *very* trusted hosts
    anchor "whitelist" {
  2. nathwill revised this gist Mar 23, 2014. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -84,6 +84,7 @@ anchor "blacklist" {
    block quick log on { $int_if $ext_if } \
    proto {tcp, udp} \
    from any to any port { 111 67 }

    }

    # scrub incoming packets
    @@ -106,9 +107,9 @@ match out on $ext_if from $int_inet_net to any \

    # Permit rate-limited ICMP
    pass inet proto icmp all icmp-type $icmp_types \
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    pass inet6 proto icmp6 all icmp6-type $icmp_types \
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    (max-src-conn-rate 6/4, overload <abusivehosts> flush global)

    # Allow *very* trusted hosts
    anchor "whitelist" {
  3. nathwill revised this gist Mar 23, 2014. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -70,6 +70,10 @@ antispoof quick for { lo0 $int_if $ext_if }
    # don't filter loopback
    set skip on lo0


    # default block policy
    block log

    # block undesired traffic up-front
    anchor "blacklist" {

    @@ -82,9 +86,6 @@ anchor "blacklist" {
    from any to any port { 111 67 }
    }

    # default block policy
    block log

    # scrub incoming packets
    # no-df is so scrubbing plays nice with NFS,
    # which is known to generate fragmented packets
  4. nathwill revised this gist Mar 23, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion pf.conf
    Original file line number Diff line number Diff line change
    @@ -156,4 +156,4 @@ anchor "nats" {
    # default gateway configuration. None of this is gospel best-practice,
    # and adaptation to best suit the environment in which it is deployed
    # is highly encouraged.
    #
    #
  5. nathwill revised this gist Mar 23, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,7 @@ set optimization normal
    set block-policy drop

    # provide some protection against address spoofing
    antispoof quick for { lo $int_if $ext_if }
    antispoof quick for { lo0 $int_if $ext_if }

    # don't filter loopback
    set skip on lo0
    @@ -77,7 +77,7 @@ anchor "blacklist" {
    block quick log from { <bruteforce> <abusivehosts> }

    # block unwanted services
    block quick log on { $int_if, $ext_if } \
    block quick log on { $int_if $ext_if } \
    proto {tcp, udp} \
    from any to any port { 111 67 }
    }
    @@ -156,4 +156,4 @@ anchor "nats" {
    # default gateway configuration. None of this is gospel best-practice,
    # and adaptation to best suit the environment in which it is deployed
    # is highly encouraged.
    #
    #
  6. nathwill revised this gist Mar 23, 2014. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -112,6 +112,7 @@ pass inet6 proto icmp6 all icmp6-type $icmp_types \
    # Allow *very* trusted hosts
    anchor "whitelist" {

    pass out quick log on $ext_if from { $ext_if_inet, $ext_if_inet6 }
    pass in quick log on $ext_if inet from <trusted_hosts_inet>
    pass in quick log on $ext_if inet6 from <trusted_hosts_inet6>

  7. nathwill revised this gist Mar 23, 2014. 1 changed file with 24 additions and 20 deletions.
    44 changes: 24 additions & 20 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -10,24 +10,24 @@
    # system

    ext_if = "em0"
    ext_if_inet = "123.45.67.89"
    ext_if_inet6 = "2600:feed:1234:2::15"
    ext_if_inet = "10.0.2.15"
    ext_if_inet6 = "2607:f700:1234:2::15"

    int_if = "em1"
    int_if_inet = "10.0.3.1"
    int_if_inet6 = "2600:beef:1234:3::1"
    int_if_inet = "10.0.3.15"
    int_if_inet6 = "2607:f700:abcd:3::1"

    # networks

    int_inet_net = "10.0.3.0/24"
    int_inet6_net = "2600:beef:1234:3::/64"
    int_inet6_net = "2607:f700:abcd:3::/64"

    # hosts

    bastion_int_inet = "10.0.3.11"

    app_ext_inet = "208.87.29.16"
    app_int_inet = "10.0.3.21"
    app_ext_inet = "208.87.29.16"

    # other

    @@ -45,13 +45,15 @@ table <trusted_hosts_inet6> persist file "/etc/pf/trusted_hosts_inet6"

    ### Policies

    ## sane default options (http://www.openbsd.org/faq/pf/options.html)
    ## sane default options
    # http://www.openbsd.org/faq/pf/options.html

    # only generate debug messages for serious errors
    set debug urgent

    # gather statistics for interface (may be expensive in processing power)
    # set loginterface em0
    # gather statistics for interface
    # can only do one, may be expensive
    set loginterface em0

    # built-in optimizations for network environment
    set optimization normal
    @@ -72,11 +74,12 @@ set skip on lo0
    anchor "blacklist" {

    # block rate-limited bad actors
    block in quick from { <bruteforce> <abusivehosts> }
    block quick log from { <bruteforce> <abusivehosts> }

    # block unwanted services ( 111,67 below are often used for profiling )
    block in quick on {$int_if, $ext_if} \
    proto {tcp, udp} port {111 67}
    # block unwanted services
    block quick log on { $int_if, $ext_if } \
    proto {tcp, udp} \
    from any to any port { 111 67 }
    }

    # default block policy
    @@ -95,8 +98,8 @@ match in all scrub (no-df random-id)

    # provide outbound nat for permitted traffic
    # but hold off on nat-ing until explicitly passed
    match out on $ext_if from $int_inet_net nat-to $ext_if_inet

    match out on $ext_if from $int_inet_net to any \
    nat-to $ext_if_inet

    ## start poking holes

    @@ -117,8 +120,8 @@ anchor "whitelist" {
    anchor "proxies" {

    # Port forward for bastion and prevent brute-forcing of SSHD
    pass in log on $ext_if inet proto tcp to $ext_if_inet \
    port 2222 flags S/SA synproxy state \
    pass in log on $ext_if proto tcp from any \
    to $ext_if_inet port 2222 flags S/SA synproxy state \
    (max-src-conn 40, max-src-conn-rate 5/10, \
    overload <bruteforce> flush global) \
    rdr-to $bastion_int_inet port 22
    @@ -128,11 +131,11 @@ anchor "proxies" {
    anchor "nats" {
    anchor "inbound" {
    # 1:1 NAT
    pass quick on $ext_if from $app_int_inet to any binat-to $app_ext_inet
    pass quick log on $ext_if from $app_int_inet binat-to $app_ext_inet
    }
    anchor "outbound" {
    # Outbound SNAT
    pass out log on $ext_if from $int_inet_net to any
    pass out log on $ext_if from $int_inet_net nat-to $ext_if_inet
    }
    }

    @@ -151,4 +154,5 @@ anchor "nats" {
    # pf (macros, tables, anchors and syntax) while providing a reasonable
    # default gateway configuration. None of this is gospel best-practice,
    # and adaptation to best suit the environment in which it is deployed
    # is highly encouraged.
    # is highly encouraged.
    #
  8. nathwill created this gist Mar 22, 2014.
    154 changes: 154 additions & 0 deletions pf.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,154 @@
    # $OpenBSD: pf.conf,v 1.52 2013/02/13 23:11:14 halex Exp $
    #
    # See pf.conf(5) for syntax and examples.
    #
    # Remember to set net.inet.ip.forwarding=1 and/or net.inet6.ip6.forwarding=1
    # in /etc/sysctl.conf if packets are to be forwarded between interfaces.

    ### Macros

    # system

    ext_if = "em0"
    ext_if_inet = "123.45.67.89"
    ext_if_inet6 = "2600:feed:1234:2::15"

    int_if = "em1"
    int_if_inet = "10.0.3.1"
    int_if_inet6 = "2600:beef:1234:3::1"

    # networks

    int_inet_net = "10.0.3.0/24"
    int_inet6_net = "2600:beef:1234:3::/64"

    # hosts

    bastion_int_inet = "10.0.3.11"

    app_ext_inet = "208.87.29.16"
    app_int_inet = "10.0.3.21"

    # other

    icmp_types="echoreq"

    ### Tables

    # black holes
    table <bruteforce> persist
    table <abusivehosts> persist

    # extremely trusted hosts
    table <trusted_hosts_inet> persist file "/etc/pf/trusted_hosts_inet"
    table <trusted_hosts_inet6> persist file "/etc/pf/trusted_hosts_inet6"

    ### Policies

    ## sane default options (http://www.openbsd.org/faq/pf/options.html)

    # only generate debug messages for serious errors
    set debug urgent

    # gather statistics for interface (may be expensive in processing power)
    # set loginterface em0

    # built-in optimizations for network environment
    set optimization normal

    # increase the default state limit from 10,000 on busy systems
    # set limit states 100000

    # dropping is less expensive than rejecting
    set block-policy drop

    # provide some protection against address spoofing
    antispoof quick for { lo $int_if $ext_if }

    # don't filter loopback
    set skip on lo0

    # block undesired traffic up-front
    anchor "blacklist" {

    # block rate-limited bad actors
    block in quick from { <bruteforce> <abusivehosts> }

    # block unwanted services ( 111,67 below are often used for profiling )
    block in quick on {$int_if, $ext_if} \
    proto {tcp, udp} port {111 67}
    }

    # default block policy
    block log

    # scrub incoming packets
    # no-df is so scrubbing plays nice with NFS,
    # which is known to generate fragmented packets
    # with the don't-fragment bit set... ;
    # random-id is used due to some OS's rather
    # pathetically predictable (zero) id headers
    # this is only for improved security, though,
    # so if it seems like it may be causing issues,
    # feel free to pull it
    match in all scrub (no-df random-id)

    # provide outbound nat for permitted traffic
    # but hold off on nat-ing until explicitly passed
    match out on $ext_if from $int_inet_net nat-to $ext_if_inet


    ## start poking holes

    # Permit rate-limited ICMP
    pass inet proto icmp all icmp-type $icmp_types \
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)
    pass inet6 proto icmp6 all icmp6-type $icmp_types \
    keep state (max-src-conn-rate 6/4, overload <abusivehosts> flush global)

    # Allow *very* trusted hosts
    anchor "whitelist" {

    pass in quick log on $ext_if inet from <trusted_hosts_inet>
    pass in quick log on $ext_if inet6 from <trusted_hosts_inet6>

    }

    anchor "proxies" {

    # Port forward for bastion and prevent brute-forcing of SSHD
    pass in log on $ext_if inet proto tcp to $ext_if_inet \
    port 2222 flags S/SA synproxy state \
    (max-src-conn 40, max-src-conn-rate 5/10, \
    overload <bruteforce> flush global) \
    rdr-to $bastion_int_inet port 22

    }

    anchor "nats" {
    anchor "inbound" {
    # 1:1 NAT
    pass quick on $ext_if from $app_int_inet to any binat-to $app_ext_inet
    }
    anchor "outbound" {
    # Outbound SNAT
    pass out log on $ext_if from $int_inet_net to any
    }
    }

    ### End Rules
    #
    # Comments
    #
    # One of the confusing things about pf is that the rules are
    # applied as "last matching rule wins", which is counter-intuitive
    # for any who learned packet filtering on Linux.
    #
    # The exception to this rule is the use of the "quick" keyword,
    # which has the effect of cancelling any further rule-processing.
    #
    # This ruleset is designed to exercise a lot of the core concepts of
    # pf (macros, tables, anchors and syntax) while providing a reasonable
    # default gateway configuration. None of this is gospel best-practice,
    # and adaptation to best suit the environment in which it is deployed
    # is highly encouraged.