Solved Can you explain packet flow with PF and why $ext_if doesn't see $localnet when going out on the internet

Hi guys !

Some time lurker here, this forum motivated me to change my router (Ubiquiti) to a Vanilla FreeBSD on a computer that was stored somewhere
Starting to learn PF with some forum threads here and with the PF book often recommended

So actually I have 4 NICS on the computer 1 WAN 1 LAN and 2 OPT
After starting to play with nat I have some issue understanding the packet flow with PF

I read on some book named: Building Firewall with OpenBSD and PF that:
Code:
Packets sent from internal hosts to the firewall and destined to external host (I suppose internet)
it will matches the IN rule on the interface connecting private network to the firewall (so $int_if)

Same packet will matche the OUT rules on the firewall external interface ($ext_if)

So in my configuration, if I do something like:
Code:
ext_if = "em0"
int_if = "em1"
localnet = "em1:network"

nat log on $ext_if inet from $localnet to any -> ($ext_if)
block log all

pass in log on $int_if from $localnet
pass out log on $ext_if from $localnet

It should let my host from LAN network to access internet, isn't it ?

For some reason it doesn't work and I need to put this rule to make it works:
Code:
pass out log on $ext_if from $ext_if

And I completly don't understand this one

Can some people here help me understand the packet flow in the firewall and why what I wrote doesn't work ?

Thank you guys !
Stay Safe, stay sharp !
Have a good day
 
From some reason it doesn't work and I need to put this rule to make it works:
NAT is done before the rules are evaluated. As your $localnet traffic is NAT'ed to the address of $ext_if the traffic will be from $ext_if to any. On the $ext_if interface you should not see any traffic with a source address from $localnet.
 
Ahhh ! I see
THANK YOU, even with few reading, blog post and forum, I didn't understand that

So to be able to block any future network I will just have to block the network in question to reach the IN of the interface
Let's say I have two networks

Code:
int_if = "em1"
guest_if = "em2"

# If I want to let em1 access internet it will be
pass in log on $int_if from $localnet
# If I want to block guest from accessing internet I will do that ?
block in log on $guest_if from $guestnet

Still letting this rule to let traffic pass to internet
Code:
pass out log on $ext_if from $ext_if

Out of curiosity, is there a better way to handle the out $ext to $ext rule ?

Again, thank you kind sir !
 
is there a better way to handle the out $ext to $ext rule
It's not $ext to $ext. It's from $ext to any.

These are all the same, just a different notation:
Code:
pass on $ext_if all
pass on $ext_if from any
pass on $ext_if from any to any

Code:
# If I want to let em1 access internet it will be 
pass in log on $int_if from $localnet 
# If I want to block guest from accessing internet I will do that ? 
block in log on $guest_if from $guestnet
Yes, you could do that. You can also do this:
Code:
pass in on $exit_if from !$guestnet to any
That allows everything except from $guestnet
 
Thanks, will take note
I think I saw it on the book

BTW, I read on the same book that if you do that
Code:
pass on $ext_if all
Or the others you mentioned, it means that IN and OUT will be taken into account

Isn't it too dangerous ?
Bear with me, I'm new to that but eager to learn

Thank you again
 
Code:
pass on $ext_if all
is the same as
Code:
pass in on $ext_if all
pass out on $ext_if all

Dangerous? Why would it? Yes, it's better to define it more strict by adding the direction. But I gave that example to illustrate that all, from any and from any to any are the same. Similarly, from $ext_if and from $ext_if to any is the same too. To keep things more readable I would suggest to always include the to in your rules, even if it's to any. You always define rules from something to something.
 
Yeah, misunderstood the answer

Anyway, it's resolve for me, I have the answer I was looking for

Thank again SirDice

EDIT: Changed the title to help other looking for something similar
 
Note that you can add pass to a nat on rule to avoid needing to explicitly allow the traffic in your filter rules. This can be easier to maintain that adding the required rules separately in the file.

Quoting pf.conf(5):
Packets that match a translation rule are only automatically passed if the pass modifier is given, otherwise they are still subject to block and pass rules.
 
Hey SirDice
You shown me last time that I could pass all requests except on $iot_net with
Code:
pass on log $ext_if from !iot_net

But for some reasons it doesn't work
`pfctl` give me this:

Code:
/etc/pf.conf:83: syntax error
Which is the line I wrote above

Any Ideas ?
 
The "on" has to be next to the "$ext_if". I know pass in log on $ext_if works. I think pass in on $ext_if log works too.
 
Ok, I misread the line but kind of same thing
Code:
nat log on $ext_if inet from !$iot_net to any -> ($ext_if)
 
Ok, maybe it's something else, other parts of my config:

Code:
### STATES, QUEUES AND TYPES ###
IOT_NETWORK   = "vlan30"
iot_net       = "$IOT_NETWORK:network"

# Each rule will use those options
TcpState = "flags S/SAFR modulate state"
UdpState = "keep state"
################################

### Miscs Options ###
set skip on lo
set block-policy drop

##### TRAFFIC NORMALIZATION #####
scrub in all
antispoof quick for $ext_if
#################################
 
Ok, maybe it's something else, other parts of my config:

Code:
### STATES, QUEUES AND TYPES ###
IOT_NETWORK   = "vlan30"
iot_net       = "$IOT_NETWORK:network"

# Each rule will use those options
TcpState = "flags S/SAFR modulate state"
UdpState = "keep state"
################################

### Miscs Options ###
set skip on lo
set block-policy drop

##### TRAFFIC NORMALIZATION #####
scrub in all
antispoof quick for $ext_if
#################################

I got nothin'. Maybe try it without the iot macros (i.e., hard-code the network address for testing).
 
Maybe the vlan30 is not recognized
When I hardcode it:
Code:
nat log on $ext_if inet from !vlan30:network to any -> ($ext_if)

I have that with pfctl:
Code:
could not parse host specification
 
That's where I figured you're having troubles. According to the syntax specification for pf.conf(5) a host is
Code:
[ "!" ] ( address [ "/" mask-bits ] | "<" string ">" )
And an address is
Code:
( interface-name | interface-group |
              "(" ( interface-name | interface-group ) ")" |
              hostname | ipv4-dotted-quad | ipv6-coloned-hex )

And your line looks legit to me. Two things I'd try: omit the "!", and try parens around the vlan20:network
 
So when I put it in parenthesis without the exclamation mark, I have:
Code:
nat log on $ext_if inet from (vlan20:network) to any -> ($ext_if)

$ Rules must be in order: options, normalization, queueing, translation, filtering
 
Now we are getting somewhere! You should be able to put the bang ("!") back in there.

Here's roughly what I use:
Code:
ext_if="..."
ip1="..."
internal_net="..."
table <spamd> persist
table...

# Options
set skip on lo
set block-policy drop
# Normalization
scrub in

# Translation
no rdr on $ext_if proto tcp from {...} to $ip2 port smtp
rdr pass on $ext_if proto tcp from any to any port smtp -> 127.0.0.1 port spamd
nat on $ext_if from $internal_net to any -> $ip1

# Filtering
block in
pass out keep state
block quick from <brutes>

# Need ICMP for path MTU
pass in quick inet proto icmp all icmp-type { echoreq unreach } keep state
...

Do you have some filter lines (maybe a block line) before your nat rule?
 
Nothing more than what I shared above, that's why I don't understand

I have some block under nat too
Code:
##### PACKET FILTERING #####
block log all
block in quick on $ext_if from <rfc6890>
block in quick on $ext_if from <BLOCKTEMP>
block in quick on $ext_if from <BLOCKLONG>
 
Ok, it seems the antispoof line was put to soon it the file
When I put it AFTER the nat rule and with the block rule, no more issues
 
From the pf.conf man page I found that:
Code:
The antispoof directive expands to a set of filter rules which will block all traffic 
with a source IP from the network(s) directly connected to the specified interface(s) from entering the system through any other interface.

As it expend to block traffic, it needs to be after the nat rule with the rest of the block traffic bloc
 
Back
Top