Re: Weird pf NAT failure on apu2

2023-06-26 Thread Ashlen
On Sat, 24 Jun 2023 07:33 -0600, Zack Newman wrote:
> On 6/2l/23 9:01, Stephan Neuhaus wrote:
> > I'm not sure about the Configuring NAT section being
> > correct. I still maintain that the documentation and
> > observed behaviour are different.
> 
> I was lazy when I said that. I meant the example I quoted from that
> section in the original reply is correct. Everything else that says
> otherwise (including the two people that said that part was wrong) is
> incorrect. Explicitly the following rule _is_ correct:
> 
> match out on interface [af] \
> from src_addr to dst_addr \
> nat-to ext_addr [pool_type] [static-port]
> [...]
> pass out [log] on interface [af] [proto protocol] \
> from ext_addr [port src_port] \
> to dst_addr [port dst_port]
> 
> There is only so many ways that this can be shown. If the pass out rule
> had "src_addr" instead of "ext_addr", it would be wrong. The diff that
> "fixes" that example needs to be rejected. It is the _other_ example
> that is wrong.
> 
> If you tried using the above example to get NAT to work, you will find
> that it will work. The last e-mail I sent clearly follows the above
> example except I chose to use stateless rules to help show more
> thoroughly all the rules that are necessary. Additionally, I prefer
> "quick" rules; but the conclusion is very clear: the match out rule
> applies and "sticks" which in turn means "src_addr" is replaced with
> "ext_addr" which in turn means the pass out rule must have "ext_addr".
> 

I forgot about that diff until I read your mail today. You're right,
I just tested that and your logic is sound. This is a good reminder
to me to test before sending diffs. I'm glad it wasn't committed.
Thank you for investigating that.



Re: Weird pf NAT failure on apu2

2023-06-25 Thread Stephan Neuhaus

On 6/24/23 13:14, Stuart Henderson wrote:

On 2023-06-24, Stephan Neuhaus  wrote:

I now think that either the documentation is wrong, or
pf is wrong.  At any rate, there seems to be a rather
serious disconnect between the two. The FAQ clearly
says:

When a packet is selected by a match rule, parameters (e.g. nat-to) in
that rule are remembered and are applied to the packet when a pass rule
matching the packet is reached.


Yes that's wrong. Address changes take effect at the time the match rule
is processed when traversing the ruleset; rules processed later "see"
the rewritten address. As pf.conf(5) says,


Translation
  Translation options modify either the source or destination address
  and port of the packets associated with a stateful connection.  pf(4)
  modifies the specified address and/or port in the packet and
  recalculates IP, TCP, and UDP checksums as necessary.

  If specified on a match rule, subsequent rules will see packets as
  they look after any addresses and ports have been translated.  These
  rules will therefore have to filter based on the translated address
  and port number.


OK, that's clear and unambiguous, thanks! So it's a bug in the FAQ, not 
in pf itself.


Cheers

Stephan



Re: Weird pf NAT failure on apu2

2023-06-24 Thread Zack Newman

On 6/2l/23 9:01, Stephan Neuhaus wrote:

I'm not sure about the Configuring NAT section being
correct. I still maintain that the documentation and
observed behaviour are different.


I was lazy when I said that. I meant the example I quoted from that
section in the original reply is correct. Everything else that says
otherwise (including the two people that said that part was wrong) is
incorrect. Explicitly the following rule _is_ correct:

match out on interface [af] \
from src_addr to dst_addr \
nat-to ext_addr [pool_type] [static-port]
[...]
pass out [log] on interface [af] [proto protocol] \
from ext_addr [port src_port] \
to dst_addr [port dst_port]

There is only so many ways that this can be shown. If the pass out rule
had "src_addr" instead of "ext_addr", it would be wrong. The diff that
"fixes" that example needs to be rejected. It is the _other_ example
that is wrong.

If you tried using the above example to get NAT to work, you will find
that it will work. The last e-mail I sent clearly follows the above
example except I chose to use stateless rules to help show more
thoroughly all the rules that are necessary. Additionally, I prefer
"quick" rules; but the conclusion is very clear: the match out rule
applies and "sticks" which in turn means "src_addr" is replaced with
"ext_addr" which in turn means the pass out rule must have "ext_addr".



Re: Weird pf NAT failure on apu2

2023-06-24 Thread Stuart Henderson
On 2023-06-24, Stephan Neuhaus  wrote:
> Hi Zack
>
> On 6/24/23 03:39, Zack Newman wrote:
>> There do appear to be contradictions in documentation as well as the pf
>> book. The Configuring NAT section is correct as you have seen with your
>> own rules.
>
> I'm not sure about the Configuring NAT section being
> correct. I still maintain that the documentation and
> observed behaviour are different.

The pf.conf(5) manual page is the best documentation for PF and that
is expected to be correct.

The pf faq could well be wrong, it's not really had a full
review/update/rewrite since before nat-to was introduced - a relatively
light conversion to the "new" syntax and mostly smaller changes -
no integration of new features in the existing text e.g. the very
useful tag/tagged is relegated to an added on "advanced features"
section).

> I now have the following small ruleset. The rules for
> ports 22 and 53 are just so that I can do my
> experiments over ssh. (Port 53 may not be necessary
> but the blocked packets mess up my logs.) The em0

You can always follow a general "block log" with a "block on port XX"
if you want to log most blocked psckets except for certain ones.

> interface has the IPv4 address 192.168.0.2.
>
> set skip on lo
>
> block log all
>
> pass in on em0 proto tcp to any port 22
> pass out on em0 proto tcp from any port 22
> pass on em0 proto udp from any port 53
> pass on em0 proto udp to any port 53

This allows someone on the internet to bypass your filter rules and
send UDP traffic to any port by simply setting the source port to 53.

Just have "to port 53", reply ("from port 53") packets will match
the state created by the packet that was passed by the "to port 53"
rule.

(You would have the same with TCP except for the direction on the
rule; still "pass out proto tcp from port 22" is probably not quite
what you want).

> I now think that either the documentation is wrong, or
> pf is wrong.  At any rate, there seems to be a rather
> serious disconnect between the two. The FAQ clearly
> says:
>
> When a packet is selected by a match rule, parameters (e.g. nat-to) in 
> that rule are remembered and are applied to the packet when a pass rule 
> matching the packet is reached.

Yes that's wrong. Address changes take effect at the time the match rule
is processed when traversing the ruleset; rules processed later "see"
the rewritten address. As pf.conf(5) says,


   Translation
 Translation options modify either the source or destination address
 and port of the packets associated with a stateful connection.  pf(4)
 modifies the specified address and/or port in the packet and
 recalculates IP, TCP, and UDP checksums as necessary.

 If specified on a match rule, subsequent rules will see packets as
 they look after any addresses and ports have been translated.  These
 rules will therefore have to filter based on the translated address
 and port number.


> I know that the documentation (at this time) ALSO
> says:
>
> match out on interface [af] \
> from src_addr to dst_addr \
> nat-to ext_addr [pool_type] [static-port]
> [...]
> pass out [log] on interface [af] [proto protocol] \
> from ext_addr [port src_port] \
> to dst_addr [port dst_port]
>
> where the pass rule has ext_addr instead of src_addr,
> but at least two people on t...@openbsd.org have
> confirmed that this is a bug and have already
> submitted a diff that replaces ext_addr with src_addr
> in the pass rule, see 
> https://marc.info/?l=openbsd-tech=168714686620055=2

I think that this bit _is_ correct as written, although it's not
particularly useful as it doesn't allow passing just the specific
translated packets.

I think it's the example rules which are wrong, i.e.

match out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1
pass on tl0 from 192.168.1.0/24 to any

directly fixing this would be

match out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1
pass on tl0 from 198.51.100.1 to any

however this would be a good place to instead show how to use
match...nat-to...tag and pass...tagged, maybe also received-on. Then a)
it's clear what traffic is passed and b) that fits better with the very
common use-case where the external (nat-rewritten) address is dynamic so
you need to use an interface name with parentheses in the nat-to rule.

But when you pull at that thread, the current structure of the pf faq
section starts to unravel, i.e. it doesn't make sense to separate tags
into "advanced", there's a fair bit of information which really isn't
useful at the faq level (flag matching? the bit about using "block
return" instead of a set of 6 different block rules that nobody learning
from the faq would have thought of writing? syn proxy, esoteric scrub
rules, being originally written from a point-of-view of "keep state"
being a special thing and tweaked from that to the current state, ...)
and it becomes a fairly big authoring job.

> Should I be taking this to another mailing 

Re: Weird pf NAT failure on apu2

2023-06-24 Thread Stephan Neuhaus

Hi Zack

On 6/24/23 03:39, Zack Newman wrote:

There do appear to be contradictions in documentation as well as the pf
book. The Configuring NAT section is correct as you have seen with your
own rules.


I'm not sure about the Configuring NAT section being
correct. I still maintain that the documentation and
observed behaviour are different.

I now have the following small ruleset. The rules for
ports 22 and 53 are just so that I can do my
experiments over ssh. (Port 53 may not be necessary
but the blocked packets mess up my logs.) The em0
interface has the IPv4 address 192.168.0.2.

set skip on lo

block log all

pass in on em0 proto tcp to any port 22
pass out on em0 proto tcp from any port 22
pass on em0 proto udp from any port 53
pass on em0 proto udp to any port 53

pass in on athn0

match out log on em0 from athn0:network to any nat-to (em0)

#pass out log on em0 from athn0:network to any
pass out log on em0 from 192.168.0.2 to any

This causes packets from athn0 to pass and to be
correctly NATed. If I uncomment the penultimate line
and comment out the last line, the packets get matched
(as before), but then blocked by the catch-all rule 0.
This is consistent with the nat-to being applied
immediately after the match rule matches, EXCEPT that
the blocked packet is logged with a source address
inside athn0:network (192.168.3.0/24 in this case) and
not the NATed-to 192.168.0.2. For example:

Jun 24 10:24:46.498327 rule 0/(match) block out on em0: 
192.168.3.32.54459 > 172.217.168.68.443: S 2479117865:2479117865(0) win 
65535  (DF)


I now think that either the documentation is wrong, or
pf is wrong.  At any rate, there seems to be a rather
serious disconnect between the two. The FAQ clearly
says:

When a packet is selected by a match rule, parameters (e.g. nat-to) in 
that rule are remembered and are applied to the packet when a pass rule 
matching the packet is reached.


This seems to me to imply that the nat-to in my match
rule should not be applied BEFORE the pass rule is
attempted, but only AFTER. This seems also to be the
point of these lines in the documentation:

match
When a packet traverses the ruleset and matches a match rule, any 
optional parameters specified in that rule are remembered for future use 
(made "sticky").


pass
This rule allows the packet to be transmitted. If the packet was 
previously matched by a match rule where parameters were specified, they 
will be applied to this packet. [...]


I know that the documentation (at this time) ALSO
says:

match out on interface [af] \
   from src_addr to dst_addr \
   nat-to ext_addr [pool_type] [static-port]
[...]
pass out [log] on interface [af] [proto protocol] \
   from ext_addr [port src_port] \
   to dst_addr [port dst_port]

where the pass rule has ext_addr instead of src_addr,
but at least two people on t...@openbsd.org have
confirmed that this is a bug and have already
submitted a diff that replaces ext_addr with src_addr
in the pass rule, see 
https://marc.info/?l=openbsd-tech=168714686620055=2


Should I be taking this to another mailing list?
Should I be submitting a bug report? Or am I just
really really dense and am just too stupid to read the
documentation correctly?

Cheers

Stephan



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Zack Newman

There do appear to be contradictions in documentation as well as the pf
book. The Configuring NAT section is correct as you have seen with your
own rules.

Here is the minimum set of stateless rules that allows ICMP traffic
between my laptop and Cloudflare.

# Options.
set block-policy drop

# Macros.
wan = em0
wifi = vlan4
external = 76.154.165.21
laptop = 192.168.6.2
cflare = 1.1.1.1

# NAT.
match out on $wan inet proto icmp from $laptop nat-to $external static-port

# Filtering rules.
pass in quick on $wifi inet proto icmp from $laptop to $cflare no state
pass out quick on $wan inet proto icmp from $external to $cflare keep state 
(if-bound)
pass out quick on $wifi inet proto icmp from $cflare to $laptop no state
block quick

The second filter rule _must_ be stateful in order for the router to
map the ICMP Query ID back to the original source IP (i.e., my laptop).

When relying on only stateful rules, we can remove the last pass rule-
since the first filter rule when hit will allow the returning Echo
Response.

If instead of using match rules for NAT, you use pass out; then pf will
fail to load pf.conf(5) if the second rule is stateless:

/etc/pf.conf:13: nat-to and rdr-to require keep state
/etc/pf.conf:13: skipping rule due to errors
/etc/pf.conf:13: rule expands to no valid combination
pfctl: Syntax error in config file: pf rules not loaded

If you want to easily distinguish traffic sourced from your router
leaving em0 from traffic sourced from your (V)LAN devices, then
you will need to have a separate rule. For example:

pass out quick log on em0 inet from (em0)
match out log on em0 inet from athn0:network nat-to (em0)
pass out log quick on em0 inet



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Zack Newman

Just wanted to reply that that was an excellent rebuttal. Looks like I
should have put my foot in my mouth. I am now keenly interested-and
disappointed in my (lack) of knowledge. I will practice with pf on my
machine to better understand what is happening. If/when I have something
meaningful to say, I will send another e-mail.

Thanks for the information.



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Stephan Neuhaus




On 6/23/23 18:29, Zack Newman wrote:

On 6/23/23 11:19, Stephan Neuhaus wrote:

# Rule 5
match out log on em0 from athn0:network to any nat-to (em0)

# Rule 6
pass out log on em0 from athn0:network to any


Rule 5 replaces the source IP address with the IP address assigned to
em0-as well as replaces the source port (for TCP and UDP) with an
ephemeral port. Rule 6 does _not_ pass traffic out of em0 from the IP
address assigned to em0 but instead passes traffic where the IP address
is from athn0:network, so of course it won't work.


Thanks for replying!

What you say may well be true, but if it is, it is in
conflict with the documentation and IMO the match/pass
combo is much less useful.

To make my first point, the pf FAQ says the following
about match/pass:

match
When a packet traverses the ruleset and matches a match rule, any 
optional parameters specified in that rule are remembered for future use 
(made "sticky").


pass
This rule allows the packet to be transmitted. If the packet was 
previously matched by a match rule where parameters were specified, they 
will be applied to this packet. [...]


This makes it very clear (to me at least) that the
nat-to in the match rule is "remembered for
future use" in the match, and is applied to the packet
only when it is finally subject to a pass rule.

The FAQ also has the following example:

match out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1
pass on tl0 from 192.168.1.0/24 to any

This is what I meant when I said that I took my code
"almost verbatim" from the FAQ.

Also, "The Book of pf", 3rd ed., has a similar match/pass combo on p.53:

match out on $ext_if inet from $localnet nat-to ($ext_if)
pass quick inet proto { tcp, udp } from $localnet to port $udp_services

(See how the "from" address in the pass rule is
$localnet, which would match the packet's original
source address, and not $(ext_if)?)

To make my second point, If the packet would
immediately change its effective source address to
that of the outgoing interface, it would for example
become very hard in later rules to distinguish between
NATed packets and packets originating on the firewall, at least in pass 
out rules.



It would be a lot easier to just have a pass out rule and only filter
ingress traffic.


Agreed, but at this stage, I'm only trying to understand what's going on.




Is there anything you see in these rules, especially
in rules 5 and 6, that is not correct? I don't think
so, I've taken this almost verbatim from the pf FAQ
https://www.openbsd.org/faq/pf/nat.html.


You did not read that FAQ carefully enough, so I wouldn't say you
have followed it "almost verbatim". Under Configuring NAT, the example
shows

match out on interface [af] \
    from src_addr to dst_addr \
    nat-to ext_addr [pool_type] [static-port]
[...]
pass out [log] on interface [af] [proto protocol] \
    from ext_addr [port src_port] \
    to dst_addr [port dst_port]

Notice the pass out rule which states "from *ext_addr*" _not_ "from
src_addr".



Agreed! These very lines were the subject of a previous post of mine, 
and two people from t...@openbsd.org said that it was a typo and that 
the ext_addr in the pass rule should be changed to src_addr. See 
https://marc.info/?l=openbsd-tech=168714686620055=2 Note also that 
these lines are in conflict with the example that comes later in the 
FAQ, and which I have quoted above.



You are also not specifying the IP version which you likely should since
you probably don't want to rely on NAT for IPv6. For example

match out log on em0 inet from athn0:network nat-to (em0)
pass out


Fair point, thanks.

Cheers

Stephan



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Zack Newman

On 6/23/23 11:19, Stephan Neuhaus wrote:

# Rule 5
match out log on em0 from athn0:network to any nat-to (em0)

# Rule 6
pass out log on em0 from athn0:network to any


Rule 5 replaces the source IP address with the IP address assigned to
em0-as well as replaces the source port (for TCP and UDP) with an
ephemeral port. Rule 6 does _not_ pass traffic out of em0 from the IP
address assigned to em0 but instead passes traffic where the IP address
is from athn0:network, so of course it won't work.

It would be a lot easier to just have a pass out rule and only filter
ingress traffic.


Is there anything you see in these rules, especially
in rules 5 and 6, that is not correct? I don't think
so, I've taken this almost verbatim from the pf FAQ
https://www.openbsd.org/faq/pf/nat.html.


You did not read that FAQ carefully enough, so I wouldn't say you
have followed it "almost verbatim". Under Configuring NAT, the example
shows

match out on interface [af] \
   from src_addr to dst_addr \
   nat-to ext_addr [pool_type] [static-port]
[...]
pass out [log] on interface [af] [proto protocol] \
   from ext_addr [port src_port] \
   to dst_addr [port dst_port]

Notice the pass out rule which states "from *ext_addr*" _not_ "from
src_addr".

You are also not specifying the IP version which you likely should since
you probably don't want to rely on NAT for IPv6. For example

match out log on em0 inet from athn0:network nat-to (em0)
pass out



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Stephan Neuhaus

On 6/23/23 13:19, Stephan Neuhaus wrote:

[...]


Some people have replied to this post off-list and
have made the entirely reasonable conjecture that the
packet changes its effective source address the moment
the match rule matches. With the changed source
address, the pass rule no longer matches. That is
entirely possible and agrees with all the experimental
evidence I have.

Still, I don't think that this is what's going on, for
the following reasons.

1. It is in conflict with the documentation. The FAQ
http://www.openbsd.org/faq/pf/nat.html says

match
When a packet traverses the ruleset and matches a match rule, any 
optional parameters specified in that rule are remembered for future use 
(made "sticky").


pass
This rule allows the packet to be transmitted. If the packet was 
previously matched by a match rule where parameters were specified, they 
will be applied to this packet. [...]


This makes it very clear that the nat-to in the match
rule is only "remembered for future use", and is
applied to the packet only when it is finally subject
to a pass rule.

Similarly, "The Book of pf", 3rd ed., has a match/pass
combo on p.53 that goes

match out on $ext_if inet from $localnet nat-to ($ext_if)
pass quick inet proto { tcp, udp } from $localnet to port $udp_services

As you can see, the pass rule has the packet's
original source specification $localnet, not the
natted-to $(ext_if).

2. The match/pass combo would be much less useful. If
the packet would immediately change its effective
source address to that of the outgoing interface, it
would for example become very hard in later rules to
distinguish between NATed packets and packets
originating on the firewall.

Cheers

Stephan



Re: Weird pf NAT failure on apu2

2023-06-23 Thread Stephan Neuhaus

On 6/23/23 13:19, Stephan Neuhaus wrote:

Hi list [...]

In other words, now the same packets that weren't
passed using the match/pass combo are not passed when
the nat-to is part of the pass rule.


That should have been "...combo are NOW passed...". Sorry.

Cheers

Stephan



Weird pf NAT failure on apu2

2023-06-23 Thread Stephan Neuhaus

Hi list

I am using a PC Engines apu2 board as a firewall. Or
rather, I want to use it as one, but it doesn't work
as I think it should.

First up, some information about my system. It has
three gigabit wired Ethernet interfaces, em0, em1, and
em2, as well as an 802.11n interface, athn0. Only em0
and athn0 will be relevant for this case.

# uname -a
OpenBSD my.host.name 7.3 GENERIC.MP#1125 amd64
# ifconfig em0 # I've zeroed out the lladdr
em0: flags=8843 mtu 1500
lladdr 00:00:00:00:00:00
description: egress interface
index 1 priority 0 llprio 3
groups: egress
media: Ethernet autoselect (1000baseT 
full-duplex,master,rxpause,txpause)

status: active
inet 192.168.0.2 netmask 0xff00 broadcast 192.168.0.255

# ifconfig athn0 # I've zeroed out the lladdr, bssid and changed the nwid.
athn0: flags=8843 mtu 1500
lladdr 00:00:00:00:00:00
description: wireless interface
index 4 priority 4 llprio 3
groups: wlan
media: IEEE802.11 autoselect mode 11n hostap
status: active
ieee80211: nwid mynw chan 56 bssid 00:00:00:00:00:00 -67dBm 
wpakey wpaprotos wpa2 wpaakms psk wpaciphers ccmp wpagroupcipher ccmp

inet 192.168.3.2 netmask 0xff00 broadcast 192.168.3.255

What I want to do is NAT the wireless interface to the
egress interface. I have this experimental pf setup,
which has many problems, and which therefore has a big
comment at the top:

# PF configuration file to test matching and NAT
#
# DO NOT USE IN PRODUCTION
#
set skip on lo

block log all # Rule 0

pass in on em0 proto tcp to any port 22# Rule 1
pass out on em0 proto tcp from any port 22 # Rule 2
pass out on em0 proto udp to any port 53   # Rule 3

pass in on athn0   # Rule 4

# Rule 5
match out log on em0 from athn0:network to any nat-to (em0)

# Rule 6
pass out log on em0 from athn0:network to any

Rules 1--3 are there so I can do my experiments over
SSH. These rules affect the rule numbering as shown by
pflog, but are otherwise not the point.

Is there anything you see in these rules, especially
in rules 5 and 6, that is not correct? I don't think
so, I've taken this almost verbatim from the pf FAQ
https://www.openbsd.org/faq/pf/nat.html.

When I connect my phone to the wireless network on
athn0, this is what I see:

# doas tcpdump -n -e -ttt -i pflog0
tcpdump: WARNING: snaplen raised from 116 to 160
tcpdump: listening on pflog0, link-type PFLOG
Jun 23 12:48:28.349710 rule def/(ip-option) pass in on athn0: :: > 
ff02::16: HBH multicast listener report v2, 1 group record(s) [hlim 1]
Jun 23 12:48:28.714929 rule 5/(match) match out on em0: 
192.168.3.32.54151 > 172.217.168.68.443: S 940430546:940430546(0) win 
65535  (DF)
Jun 23 12:48:28.714932 rule 0/(match) block out on em0: 
192.168.3.32.54151 > 172.217.168.68.443: S 940430546:940430546(0) win 
65535  (DF)
Jun 23 12:48:28.716461 rule 5/(match) match out on em0: 
192.168.3.32.37973 > 216.58.215.227.80: S 2291102750:2291102750(0) win 
65535  (DF)
Jun 23 12:48:28.716463 rule 0/(match) block out on em0: 
192.168.3.32.37973 > 216.58.215.227.80: S 2291102750:2291102750(0) win 
65535  (DF)
Jun 23 12:48:29.728732 rule 5/(match) match out on em0: 
192.168.3.32.54151 > 172.217.168.68.443: S 940430546:940430546(0) win 
65535  (DF)
Jun 23 12:48:29.728736 rule 0/(match) block out on em0: 
192.168.3.32.54151 > 172.217.168.68.443: S 940430546:940430546(0) win 
65535  (DF)


As you can see, the packet is being matched by the
match rule (rule 5) but then NOT matched by the pass
rule (rule 6) and consequently by the block-all rule
(rule 0).

When I remove rule 5 and change rule 6 to
this (making it the new rule 5):

pass out log on em0 from athn0:network to any nat-to (em0)

this is what I see in the logs:

Jun 23 12:50:59.791736 rule def/(ip-option) pass in on athn0: :: > 
ff02::16: HBH multicast listener report v2, 1 group record(s) [hlim 1]
Jun 23 12:51:00.091647 rule def/(ip-option) pass in on athn0: :: > 
ff02::16: HBH multicast listener report v2, 1 group record(s) [hlim 1]
Jun 23 12:51:00.152530 rule 5/(match) pass out on em0: 
192.168.3.32.37988 > 216.58.215.227.80: S 749016608:749016608(0) win 
65535  (DF)
Jun 23 12:51:00.152614 rule 5/(match) pass out on em0: 
192.168.3.32.54168 > 172.217.168.68.443: S 2019795291:2019795291(0) win 
65535  (DF)


In other words, now the same packets that weren't
passed using the match/pass combo are not passed when
the nat-to is part of the pass rule.

No matter how I read the docs, there is no way I can explain what's 
happening. Yet my setup is so simple that I MUST be doing something 
wrong, right?


Can you help me see what's going on?

Cheers

Stephan

PS: I didn't want to make this message even longer by
including a dmesg, but it is of course available on
request.