Re: Simplifying pf-rules

2018-01-07 Thread Kenneth Gober
On Thu, Jan 4, 2018 at 8:09 AM, Jon S  wrote:
> 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

2018-01-05 Thread Jon S
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

2018-01-04 Thread 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/



Simplifying pf-rules

2018-01-04 Thread Jon S
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