PF How do I Lock down pf

How to at a minimum, allow https (port 443/TCP), ssh (port 22/TCP), auth (port 113/TCP), and ICMP lock-down. I want to only allow specific traffic such as the FreeBSD 443 and the w3school port 80 examples as below. Out of all the threads about pf only one used these words but the site no longer exist and there is absolutely nothing that I could find for pf, even on openbsd. Linux way is all over the place :(
.

I don't know exactly what I am doing here. Could someone please show me by fixing this pf.conf as far as you can? If I can’t have specific traffic in port 80 forget 80. I have only a few that I like to run in this special VM.


Code:
ext_if="em0"

dns1 = "199.85.126.10"
dhcp = "192.168.1.254"
icmp_types_A = "{ 8 }"    # Set allowed ICMP types - { 0, 3, 4, 8, 11, 12 }
icmp_types_B = "{ 8 }"

ob_state = "flags S/SA modulate state"
ib_state = "flags S/SA synproxy state"

table <sshguard> persist

set optimization aggressive
set block-policy drop
set state-policy if-bound
set loginterface $ext_if
scrub out on $ext_if all random-id
scrub reassemble tcp
# ...............................
# ................................
# nat on $ext_if from !($ext_if) -> ($ext_if:0)    # vBox bridge mode for FreeBSD guest

pass quick on lo0 all
block in all
block out all

pass in quick from 8.8.178.110 to any #  https
pass out quick from 8.8.178.110 to any

pass in quick from 72.21.91.8 to any #  http
pass out quick from 72.21.91.8 to any

# ............................................................................
# ............................................................................
pass out quick on $ext_if proto tcp from any to $dns1 port 53 $ob_state
pass out quick on $ext_if proto udp from any to $dns1 port 53 keep state

pass out quick on $ext_if proto tcp from any to $dns1 port 113 $ob_state
pass out quick on $ext_if proto tcp from any to any port 443 $ob_state
pass out quick on $ext_if proto tcp from any to any port 22 $ob_state
##    pass out quick on $ext_if proto tcp from any to any port 80 $ob_state
pass out quick on $ext_if inet proto icmp from any to any icmp-type $icmp_types_B keep state
# ##################################################################
block out log quick on $ext_if all
block in quick on $ext_if from <sshguard> label "ssh bruteforce"
block in quick on $ext_if inet proto icmp all icmp-type $icmp_types_B    #   public pings

###  pass out quick on $ext_if proto udp from any to $dhcp port 67 keep state # O dhcp
 
Code:
pass quick on lo0 all
Don't use this. Use this instead:
Code:
set skip on lo0

Code:
pass in quick from 8.8.178.110 to any #  https
This allows everything, UDP/TCP/ICMP on all ports, not just HTTPS.
Code:
pass in proto tcp from 8.8.178.110 to any port 443
This allows TCP connections to port 443 (HTTPS) from 8.8.178.110.

Code:
pass out quick from 8.8.178.110 to any
This allows outgoing traffic from 8.8.178.110 to anywhere. Unless you are 8.8.178.110 this doesn't do anything.

Same here:
Code:
pass in quick from 72.21.91.8 to any #  http
pass out quick from 72.21.91.8 to any
Not really sure what you're trying to block/prevent here.

Code:
pass out quick on $ext_if proto tcp from any to $dns1 port 53 $ob_state
pass out quick on $ext_if proto udp from any to $dns1 port 53 keep state
No need to explicitly add "keep state". And you probably don't want to use "modulate state". Can be done on one line:
Code:
pass out on $ext_if proto {tcp,udp} from any to $dns1 port 53

Code:
pass out quick on $ext_if proto tcp from any to $dns1 port 113 $ob_state
Nobody uses ident any more as it's a horrible security risk. Do you really need it?

Code:
block in quick on $ext_if from <sshguard> label "ssh bruteforce"
Doesn't do anything. You'll want to move this to the top, at least before the rule that allows all access to port 22.
Code:
pass out quick on $ext_if proto tcp from any to any port 22 $ob_state
Because of the quick keyword the sshguard block rule will never be reached.

Code:
block out log quick on $ext_if all
Pretty much already done in
Code:
block out all
 
Code:
pass quick on lo0 all
Don't use this. Use this instead:
Code:
set skip on lo0

Code:
pass in quick from 8.8.178.110 to any #  https
This allows everything, UDP/TCP/ICMP on all ports, not just HTTPS.
Code:
pass in proto tcp from 8.8.178.110 to any port 443
This allows TCP connections to port 443 (HTTPS) from 8.8.178.110.

Code:
pass out quick from 8.8.178.110 to any
This allows outgoing traffic from 8.8.178.110 to anywhere. Unless you are 8.8.178.110 this doesn't do anything.

Same here:
Code:
pass in quick from 72.21.91.8 to any #  http
pass out quick from 72.21.91.8 to any
Not really sure what you're trying to block/prevent here.

Code:
pass out quick on $ext_if proto tcp from any to $dns1 port 53 $ob_state
pass out quick on $ext_if proto udp from any to $dns1 port 53 keep state
No need to explicitly add "keep state". And you probably don't want to use "modulate state". Can be done on one line:
Code:
pass out on $ext_if proto {tcp,udp} from any to $dns1 port 53

Code:
pass out quick on $ext_if proto tcp from any to $dns1 port 113 $ob_state
Nobody uses ident any more as it's a horrible security risk. Do you really need it?

Code:
block in quick on $ext_if from <sshguard> label "ssh bruteforce"
Doesn't do anything. You'll want to move this to the top, at least before the rule that allows all access to port 22.
Code:
pass out quick on $ext_if proto tcp from any to any port 22 $ob_state
Because of the quick keyword the sshguard block rule will never be reached.

Code:
block out log quick on $ext_if all
Pretty much already done in
Code:
block out all
 
The consequences of greedy searches, and then I had the nerve to include or change stuff with what I thought sounded so good if it was not in the tutorial or how-to already. Thanks SirDice, I can feel it! I’ll certainly will post my attempt of correction in a few days for the ultimate inspection (Please). Right now I got to take a crash course with the ancient serial ports. I might to force to build an addition vBox for that. dag!
 
Code:
pass quick on lo0 all
Don't use this. Use this instead:
Code:
set skip on lo0
.......
........


This is working well SirDice. What has been most interesting is following your instructions to the point that I even clean out my full version(s) of PF for my standard web-surfing VM. Above all this one will be used for connection to my first remote server along with my favorite sites and nothing more. I never knew it could be this simple because there was nothing I found about it even in PF handbook. If I got it right, I can finally move on to the next dilemma.

Code:
##################################################
#     FreeBSD-k9   Most Trusted Sites in vBox-0    June 3, 2016
##################################################

ext_if="em0"

dns1 = "999.99.99.99"        # your dns
dhcp = "10.0.2.2"        # vBox dhcp
 
icmp_types_A = "{ 8 }"    # Set allowed ICMP types - { 0, 3, 4, 8, 11, 12 }

ob_state = "flags S/SA modulate state"        #  outbound
# ib_state = "flags S/SA synproxy state"    #  inbound

table <sshguard> persist

set optimization aggressive
set block-policy drop
set state-policy if-bound
set loginterface $ext_if

scrub out on $ext_if all random-id 
scrub reassemble tcp
set skip on lo0
# ..................................
# ..................................
block drop in quick inet6
block in all
block out all

# 1 Your Server - 2 FreeBSD.org - 3 FreeBSD Forum - 4 Bing  (workstation browser must use ob_state)

# DO needs two IP's to work properly
pass out on $ext_if inet proto tcp from any to 104.16.24.4 port 443 $ob_state # d-Ocean
pass out on $ext_if inet proto tcp from any to 23.235.44.249 port 443 $ob_state # d-static

pass out on $ext_if inet proto tcp from any to 8.8.178.110 port 443 $ob_state # FBSD-main
pass out on $ext_if inet proto tcp from any to 204.109.59.195 port 443 $ob_state # forum
pass out on $ext_if inet proto tcp from any to 204.79.197.200 port 443 $ob_state # bing


# Google needs more PF features available or more than 2 google IP's or I did not find the right one!
#pass out on $ext_if inet proto tcp from any to 74.125.21.99 port 443 $ob_state # google  # don't work
#pass out on $ext_if inet proto tcp from any to 74.125.21.103 port 443 $ob_state # google   # don't work

###################################################################

# Most needed sites need nothing more this this so far!
pass out quick on $ext_if proto tcp from any to $dns1 port 53  # must have
pass out quick on $ext_if proto udp from any to $dns1 port 53  # or must have

block in on $ext_if from <sshguard> label "ssh bruteforce"  # never use quick here

####  block in log quick on $ext_if all

#########################################
#     End of FreeBSD-k9 rules
#########################################
 
Code:
block in on $ext_if from <sshguard> label "ssh bruteforce" # never use quick here
Actually, this is one rule were you DO want to use quick. And you'll want to move it to the very top of your rule set. The reason is that you absolutely want to block it and you want to block it as soon as possible. There's no sense in having this traffic traverse the entire rule set just to be blocked at the end.

The problem with the initial rules was more or less this:
Code:
1: pass in quick on $ext_if from any to any port 22
2: block in quick on $ext_if from <sshguard>
A connection to port 22 would always be allowed, even if the source IP address was in the sshguard table. This was because of the quick keyword on rule #1. When traffic 'hits' this rule the quick keyword will make it stop evaluating the later rules, so rule #2 was never evaluated. Changing the order or removing the quick keyword on rule #1 would have made it work.

The quick keyword should be used sparsely and really only on very specific rules when there's no reason to evaluate the rest of the rule set.
 
I have a different view on the use of quick. In rules where you know that no other rule after them are going to affect the outcome you should use quick because it saves CPU cycles in rule processing. Without the quick keyword the rule evaluation will proceed as long as it takes to reach the end of the rules or another matching rule with quick keyword is encountered. Let's say you want to allow all outgoing traffic on any interface, you certainly want to do it this way:

Code:
...
# Rules for outgoing traffic
pass out quick all

# Rules for incoming traffic
...
# Lots and lots of 'pass in' rules
...

Without the quick the above rule would be functionally equivalent assuming there are no other rules that match outgoing traffic but the rule evaluation would be slower because PF would try to match all the other rules after it on outgoing traffic even though they only match incoming traffic.
 
. . . . . The quick keyword should be used sparsely and really only on very specific rules when there's no reason to evaluate the rest of the rule set.

In my case the very few lines I’m using seems to be very specific, but I am not going to take any chances in what I believe… is there anything here where quick could be of no help?


I moved this to the top.
Code:
block in quick on $ext_if from <sshguard> label "ssh bruteforce"


Do I really need this line if I am the only one using this workstation and it is not on a LAN or WAN other than Virtualbox and it is using Bridge Mode?
Code:
pass out quick on $ext_if proto tcp from any to any port 22

I think I should use QUICK for direct hard-coded address's. Is this correct? Also, am I’m using inet correctly. Is there another way to write this line to enhance security and speed, or is that what inet do already?

Code:
pass out on $ext_if inet proto tcp from any to 204.109.59.195 port 443 $ob_state
…. 
….

Should both of these use QUICK?
Code:
pass out quick on $ext_if proto {tcp udp} from any to $dns1 port 53

pass out quick on $ext_if inet proto icmp from any to any icmp-type $icmp_A

Bing is out because it will not search anyway. Searching FreeBSD for solutions and the provider of the server is all this VM will ever do.

Have I missed anything needed in my rules?





In my case, I don't need any of this kind of rules because I'm blocking in and out anyway and going directly to hard-coded addresses, correct? This is from my old Hermelito rules that many I mess up over the years.
Code:
# block in quick on $ext_if from 192.168.0.0/16 to any  # RFC 1918 private IP
# block in quick on $ext_if from 172.16.0.0/12 to any   # RFC 1918 private IP
# block in quick on $ext_if from 10.0.0.0/8 to any      # RFC 1918 private IP
# block in quick on $ext_if from 127.0.0.0/8 to any     # loopback
# block in quick on $ext_if from 0.0.0.0/8 to any       # loopback
# block in quick on $ext_if from 169.254.0.0/16 to any  # DHCP auto-config
# block in quick on $ext_if from 192.0.2.0/24 to any    # reserved for doc's
# block in quick on $ext_if from 204.152.64.0/23 to any # Sun cluster connect
# block in quick on $ext_if from 224.0.0.0/3 to any     # Class D $ E multicast
 
When God was passing out the brains I think he forget about me ...
.... .... .... A connection to port 22 would always be allowed, even if the source IP address was in the sshguard table.


I'll just hard-code it just like the rest. It probably the most common thing that FreeBSD people do. After this I'll understand better when I read FreeBSD Networking sections. Deskkop FreeBSD was fun but it's time to move on.

Code:
pass out quick on $ext_if proto udp from any to xxx.xxx.xxx.xxxx port 22

That should do it?
 
Yes, that would allow outgoing SSH from any local IP address to IP address xxx.xxx.xxx.xxxx but you need to change the protocol to TCP, SSH uses only TCP destination port 22. You also might want to tighten the source address to let's say this:

Code:
pass out quick on $ext_if proto tcp from $ext_if to xxx.xxx.xxx.xxxx port 22

When asking for help on PF or any other firewalling matters you should always qualify for the sake of clarity what is the direction of the traffic in question. All network traffic has a direction and you can't write proper firewall rules without understanding how the direction should be taken into account. For example, in the above rules you have the rule for the sshguard:

Code:
block in quick on $ext_if from <sshguard> label "ssh bruteforce"

This matches only incoming connections and has no effect on the other rule above for outgoing SSH. This is because TCP is stateful and PF is a stateful packet filter. The so called return packets of an outgoing connection will never match the sshguard rule even though the this return traffic is incoming on the ext_if interface.
 
What resonates with me is that you and SirDice say essentially the same thing, and most of that has been included to the best of my ability.
kpa said:
...
# Rules for outgoing traffic
pass out quick all

# Rules for incoming traffic
...
# Lots and lots of 'pass in' rules
...



Yes, that would allow outgoing SSH from any local IP address to IP address xxx.xxx.xxx.xxxx but you need to change the protocol to TCP, SSH uses only TCP destination port 22. You also might want to tighten the source address to let's say this:

Code:
pass out quick on $ext_if proto tcp from $ext_if to xxx.xxx.xxx.xxxx port 22

When asking for help on PF or any other firewalling matters you should always qualify for the sake of clarity what is the direction of the traffic in question. All network traffic has a direction and you can't write proper firewall rules without understanding how the direction should be taken into account. For example, in the above rules you have the rule for the sshguard:

Code:
block in quick on $ext_if from <sshguard> label "ssh bruteforce"

This matches only incoming connections and has no effect on the other rule above for outgoing SSH. This is because TCP is stateful and PF is a stateful packet filter. The so called return packets of an outgoing connection will never match the sshguard rule even though the this return traffic is incoming on the ext_if interface.

Mostly I fear in not including any inbound protection rules but I thought these rules are suppose to take care of that:
Code:
block drop in quick inet6 
block in all 
block out all

… I know most of those rules and will use them if written in my sample below, but I feel they will never be reach so that could mean they are useless when using a direct-connect PF style.
This is my tiniest rule set, and PF builds it without error, but maybe something is missing and I know it can’t possibly be that much beyond a line or two. I learn by example, especially when I provide the example. Show me a better way in my example, in full, if possible.

Code:
block drop in quick inet6 
block in all 
block out all

# ############################################################
# it now back to using tcp … could you show the correct way because I am lost in explanation.
# it will only be for secure connection to a remote server and the hope of non-system high-jack.

# pass out on … no?  yes?  No  no?  yes?  Yes?  I can't figure ...

block in quick on $ext_if from <sshguard> label "ssh bruteforce" # maybe no good at all .. please repair
pass out quick on $ext_if proto tcp from $ext_if to xxx.xxx.xxx.xxx port 22 # maybe not needed please repair
# ############################################################

pass out quick on $ext_if inet proto tcp from any to 104.16.24.4 port 443 $ob_state # direct-IP
pass out quick on $ext_if inet proto tcp from any to 8.8.178.110 port 443 $ob_state # direct-IP

 ############################################################
pass out quick on $ext_if proto {tcp udp} from any to $dns1 port 53
block in log quick on $ext_if all
######################################### 
#     k9 ends useless it needs more or less.
#########################################

Other than that, thanks a bunch, I will dwell in all suggests here as long as FreeBSD exist, and that is not small talk, that is how I learn, eventually, unless I nail it already.
 
Only once did not pay attention to what was in the sshguard table. I thought they were FreeBSD update related IP’s. Now I know why this line is not needed: Thank you
Code:
pass out quick on $ext_if proto tcp from $ext_if to xxx.xxx.xxx.xxxx port 22

So MINUMUM would be:
Code:
block drop in quick inet6 # The future: if you know why and how to use it.
block in all # if this was quick you will never connect.. This completes the story about quick.
block out all # I tested both and em0 brought down the entire house, wifi too.

# #######################################################

# Good to go!
block in quick on $ext_if proto tcp from <sshguard> to any port ssh label "ssh bruteforce"

#######################################################

pass out quick on $ext_if inet proto tcp from any to 104.16.24.4 port 443 $ob_state # quick direct
pass out quick on $ext_if inet proto tcp from any to 8.8.178.110 port 443 $ob_state # quick direct

 #######################################################

pass out quick on $ext_if proto {tcp udp} from any to $dns1 port 53

#  be quick or not from this point.  I choose nothing more for this VM.  Good luck!

######################################### 
#     Now I seen the light ... k9 ends.
#########################################
 
Code:
# Good to go!
block in quick on $ext_if proto tcp from <sshguard> to any port ssh label "ssh bruteforce"
I usually just block everything, not just port 22. I don't want them brute-forcing any other port.
Code:
block in quick on $ext_if proto tcp from <sshguard> to any label "ssh bruteforce"
 
Back
Top