Re: Simplifying pf-rules
On Thu, Jan 4, 2018 at 8:09 AM, Jon Swrote: > This led to my first experieces with pf. After some work I came up with > whats below. It works as I want it to work, but I wonder if there is a way > to create a rule where incomming traffic to the internal NIC (re0) is > passed if it is targeted for em0 (external, internet NIC)? The current > solution would require an update of the "pass in on re0 to > !re0:network"-rule if another NIC is added (lets say a DMZ). > > [ruleset omitted] For years I used a vaguely similar ruleset on my own router; similar in the sense that it used "pass out all" and relied only on filtering inbound traffic. But over time I've decided that it's better to block both inbound and outbound by default, then explicitly allow traffic in 3 categories: 1. traffic to this router as the final destination (for services running on the router) 2. traffic to be forwarded (with NAT if needed) 3. traffic that originates from this router #3 is especially important if the router is also running other services which may make announcements on the network. If you are running Samba for example you probably don't want to send announcements to the Internet. Yes, this means you need to know explicitly what your services are doing so you know what to enable. On the plus side it means nothing gets sent to the Internet simply because you didn't know you needed to turn it off. To differentiate between #1 and #2 I use tags to mark packets as ACCEPT or FORWARD. Only the packets tagged FORWARD are allowed to pass out. Inbound packets start with a TBD tag that basically means "not yet tagged" and ensures that once a rule sets an ACCEPT or FORWARD tag, other rules don't then try to re-tag it. Also, I try to avoid using ! anywhere. It is too easy to make mistakes with it, and configuration mistakes are the #1 reason unwanted traffic will get through your firewall. A very stripped down subset of my ruleset follows, showing the essentials. em0 is my internal interface, em1 is my 'guest' interface (that friends can use for their WiFi when they visit) and em2 connects to my Internet cable modem (I don't use variable name substitutions for unrelated reasons, but you may want to do so anyway). I have included em1 because it's very similar to a DMZ network. I am running several services on my router so I've also included the DNS and ftp-proxy rules because they are good examples. Note that I make extensive use of "quick" to give "first matching rule wins" behavior. I think this is easier to understand. # pf.conf - PF configuration file # tables table const { 10/8, 172.16/12, 192.168/16 } # by default, block all traffic not explicitly allowed block in log all tag TBD block out log all # ACCEPT - traffic that should be accepted by this router (not forwarded) # accept ping requests pass in log quick on em0 inet proto icmp from em0:network to (self) icmp-type echoreq tagged TBD tag ACCEPT pass in log quick on em1 inet proto icmp from em1:network to em1 icmp-type echoreq tagged TBD tag ACCEPT # accept DNS requests pass in log quick on em0 inet proto { udp tcp } to (self) port domain tagged TBD tag ACCEPT pass in log quick on em1 inet proto { udp tcp } from em1:network to em1 port domain tagged TBD tag ACCEPT # accept SSH connections pass in log quick on em0 inet proto tcp from em0:network to (self) port ssh tagged TBD tag ACCEPT pass in log quick on em1 inet proto tcp from em1:network to em1 port ssh tagged TBD tag ACCEPT # FORWARD / Inbound - traffic that should be forwarded by this router # block non-Internet traffic from public (guest) network block in log quick on em1 to tagged TBD # pass internal FTP traffic pass in log quick on em0 inet proto tcp from em0:network to 192.168/18 port ftp tagged TBD tag FORWARD # proxy external FTP traffic pass in log quick on em0 inet proto tcp from em0:network to port ftp divert-to 127.0.0.1 port 8021 tagged TBD tag ACCEPT pass in log quick on em1 inet proto tcp from em1:network to port ftp divert-to 127.0.0.1 port 8021 tagged TBD tag ACCEPT anchor "ftp-proxy/*" # default forwarding rules for traffic from private network pass in log quick on em0 from em0:network to 192.168/18 tagged TBD tag FORWARD pass in log quick on em0 from em0:network modulate state tagged TBD tag FORWARD # default forwarding rules for traffic from public (guest) network pass in log quick on em1 from em1:network to em1:network tagged TBD tag FORWARD pass in log quick on em1 from em1:network modulate state tagged TBD tag FORWARD # game server pass in log quick on em2 inet proto udp to (em2) port 27016 rdr-to 192.168.24.50 tagged TBD tag FORWARD # FORWARD / Outbound # forward internal traffic pass out log quick on em0 tagged FORWARD pass out log quick on em1 tagged FORWARD # block unroutable external traffic block out log quick on em2 to tagged FORWARD # forward external traffic pass out log quick on em2 nat-to (em2) tagged FORWARD # Outbound - traffic that
Re: Simplifying pf-rules
Marko: Thanks for your input. Your proposals got me thinking a few steps further. I now came up with the following solution which have all propertiers i want: pass in on re0 inet to !all:network pass in on re0 inet to em0:network # Just in case we would need to interact # with some other service on the same segment... block in quick log on re0 inet to em0 # ... but not our own IP The above lines replaces my initial rule "pass in on re0 to !re0:network" 2018-01-04 16:29 GMT+01:00 Marko Cupać: > On Thu, 4 Jan 2018 14:09:50 +0100 > Jon S wrote: > > > Hello misc! > > > > My OpenBSD file server just became a router too (after getting a new > > internet connection where the provider does not include a router in > > the subscription). > > If possible, I'd avoid combining file server and firewall services on > single box > > > This led to my first experieces with pf. After some work I came up > > with whats below. It works as I want it to work, but I wonder if > > there is a way to create a rule where incomming traffic to the > > internal NIC (re0) is passed if it is targeted for em0 (external, > > internet NIC)? The current solution would require an update of the > > "pass in on re0 to !re0:network"-rule if another NIC is added (lets > > say a DMZ). > > All my pf rulesets start with defining interface macros so they are > more readable, and also more flexible (this way changing NIC with > different driver needs one line changed, instead of all lines in the > ruleset referencing that interface): > > # INTERFACE MACROS > if_int = "re0" > if_ext = "em0" > > > set skip on lo0 > > > > # Block everything everywhere by default > > block log all > > I prefer to put "match" section above default "block log all" rule. > It's more logical to me, as something being "matched" has no impact if > it's not "passed" or "blocked" later on in the ruleset. > > > # NAT local network to external > > match out on em0 inet from re0:network nat-to (em0) > > > > # Allow all outgoing traffic > > pass out on {em0, re0} > > > > # Allow only specific services on this machine to be accessed from > > # local network > > pass in on re0 inet proto tcp to port ssh # ssh > > pass in on re0 inet proto icmp# icmp > > pass in on re0 inet proto tcp to port 445 # samba > > Your description line does not describe accurately what next three > lines do - as destination IP is not present, "to any" is assumed, so > more accurate description would be "Allow specific services on any > machine be accessed from local network". > > If you wanted your ruleset to match description line, and your > services listen on internal NIC, you would do something like: > > pass in on $if_int inet proto tcp from re0:network to re0 port ssh > pass in on $if_int inet proto icmp from re0:network to re0 > pass in on $if_int inet proto tcp from re0:network to re0 port 445 > > > > > #pass in on re0 inet to em0:network # This does not work, since the > > #mask for this IF will only let traffic through to the limitied set of > > #IPs on the same C-segment as em0. That would probably be a set of > > #other customers at the nework operator... > > > > # This works, but will require an update if any furter NIC is involved > > # later > > pass in on re0 to !re0:network > > There are multiple ways to achieve this. One of them would be passing > everything on $if_int, and blocking what you don't want later (if > "quick" keyword is not used, last matching rule wins): > > pass in on $if_int > block in on $if_int inet proto tcp from $if_int:network to \ > $if_int port { !=ssh !=445 } > > The other one would be blocking unwanted stuff quickly early in the > ruleset, and passing what you want later on: > > block in quick on $if_int inet proto tcp from $if_int:network to \ > $if_int port { !=ssh !=445 } > pass in on $if_int > > Both examples block only TCP to internal NIC, so blocking other > protocols if there are any on the firewall also needs to be done. > > > > # I would like something like this to work, so that future added NICs > > # wont open new unwanted paths > > #pass in on re0 to em0 > > > > # Allow only incomming SSH to external NIC > > pass in on em0 inet proto tcp to port ssh > > In the end, your ruleset seems quite minimal. I suggest you start > worrying about new NIC once you add it. For now it would be better to > play around with pfctl -vvsr, systat states/rules, tcpdumping pflog etc. > > Hope this helps, > > -- > Before enlightenment - chop wood, draw water. > After enlightenment - chop wood, draw water. > > Marko Cupać > https://www.mimar.rs/ > -- <> Jon Sjöstedt Gamla Björboholmsvägen 2 443 72 GRÅBO Mobil 0735 - 029 557 jonsjost...@gmail.com jonsjost...@hotmail.com
Re: Simplifying pf-rules
On Thu, 4 Jan 2018 14:09:50 +0100 Jon Swrote: > Hello misc! > > My OpenBSD file server just became a router too (after getting a new > internet connection where the provider does not include a router in > the subscription). If possible, I'd avoid combining file server and firewall services on single box. > This led to my first experieces with pf. After some work I came up > with whats below. It works as I want it to work, but I wonder if > there is a way to create a rule where incomming traffic to the > internal NIC (re0) is passed if it is targeted for em0 (external, > internet NIC)? The current solution would require an update of the > "pass in on re0 to !re0:network"-rule if another NIC is added (lets > say a DMZ). All my pf rulesets start with defining interface macros so they are more readable, and also more flexible (this way changing NIC with different driver needs one line changed, instead of all lines in the ruleset referencing that interface): # INTERFACE MACROS if_int = "re0" if_ext = "em0" > set skip on lo0 > > # Block everything everywhere by default > block log all I prefer to put "match" section above default "block log all" rule. It's more logical to me, as something being "matched" has no impact if it's not "passed" or "blocked" later on in the ruleset. > # NAT local network to external > match out on em0 inet from re0:network nat-to (em0) > > # Allow all outgoing traffic > pass out on {em0, re0} > > # Allow only specific services on this machine to be accessed from > # local network > pass in on re0 inet proto tcp to port ssh # ssh > pass in on re0 inet proto icmp# icmp > pass in on re0 inet proto tcp to port 445 # samba Your description line does not describe accurately what next three lines do - as destination IP is not present, "to any" is assumed, so more accurate description would be "Allow specific services on any machine be accessed from local network". If you wanted your ruleset to match description line, and your services listen on internal NIC, you would do something like: pass in on $if_int inet proto tcp from re0:network to re0 port ssh pass in on $if_int inet proto icmp from re0:network to re0 pass in on $if_int inet proto tcp from re0:network to re0 port 445 > > #pass in on re0 inet to em0:network # This does not work, since the > #mask for this IF will only let traffic through to the limitied set of > #IPs on the same C-segment as em0. That would probably be a set of > #other customers at the nework operator... > > # This works, but will require an update if any furter NIC is involved > # later > pass in on re0 to !re0:network There are multiple ways to achieve this. One of them would be passing everything on $if_int, and blocking what you don't want later (if "quick" keyword is not used, last matching rule wins): pass in on $if_int block in on $if_int inet proto tcp from $if_int:network to \ $if_int port { !=ssh !=445 } The other one would be blocking unwanted stuff quickly early in the ruleset, and passing what you want later on: block in quick on $if_int inet proto tcp from $if_int:network to \ $if_int port { !=ssh !=445 } pass in on $if_int Both examples block only TCP to internal NIC, so blocking other protocols if there are any on the firewall also needs to be done. > > # I would like something like this to work, so that future added NICs > # wont open new unwanted paths > #pass in on re0 to em0 > > # Allow only incomming SSH to external NIC > pass in on em0 inet proto tcp to port ssh In the end, your ruleset seems quite minimal. I suggest you start worrying about new NIC once you add it. For now it would be better to play around with pfctl -vvsr, systat states/rules, tcpdumping pflog etc. Hope this helps, -- Before enlightenment - chop wood, draw water. After enlightenment - chop wood, draw water. Marko Cupać https://www.mimar.rs/
Simplifying pf-rules
Hello misc! My OpenBSD file server just became a router too (after getting a new internet connection where the provider does not include a router in the subscription). This led to my first experieces with pf. After some work I came up with whats below. It works as I want it to work, but I wonder if there is a way to create a rule where incomming traffic to the internal NIC (re0) is passed if it is targeted for em0 (external, internet NIC)? The current solution would require an update of the "pass in on re0 to !re0:network"-rule if another NIC is added (lets say a DMZ). set skip on lo0 # Block everything everywhere by default block log all # NAT local network to external match out on em0 inet from re0:network nat-to (em0) # Allow all outgoing traffic pass out on {em0, re0} # Allow only specific services on this machine to be accessed from # local network pass in on re0 inet proto tcp to port ssh # ssh pass in on re0 inet proto icmp# icmp pass in on re0 inet proto tcp to port 445 # samba #pass in on re0 inet to em0:network # This does not work, since the #mask for this IF will only let traffic through to the limitied set of #IPs on the same C-segment as em0. That would probably be a set of #other customers at the nework operator... # This works, but will require an update if any furter NIC is involved # later pass in on re0 to !re0:network # I would like something like this to work, so that future added NICs # wont open new unwanted paths #pass in on re0 to em0 # Allow only incomming SSH to external NIC pass in on em0 inet proto tcp to port ssh -- <> Jon Sjöstedt jonsjost...@gmail.com