PF Working example for bhyve/vm and vm-public bridge

Please,
  • Have installed Ubuntu 23.04 VM via vm(8) scripts (on 13.2-RELEASE)
  • Have vm-public bridge created via vm switch create public and added my Intel igb0 there
  • There's a tap0 as well
  • When I disable PF firewall, my VM is perfectly able to obtain IPv4 via DHCP from my home router 192.168.0.1 and use that to access internet
After spending a couple of hours and trying to get VM access to internet even when PF firewall is running I'm giving up and please....

If anybody could copy-paste his own pf.conf just to see a working example for such scenario, it'd be great.

Thank you in advance!
 
I will help you with that, it took me a sweet time too back then. What is your current content of pf.conf? What you need is to make sure you filter only traffic coming in on the external interface. Traffic out and bridge can be unfiltered. I don't use DHCP, so this might not be a problem of pf.conf. I use static IP and NAT, as it's more convenient for me. I guess you don't use NAT, since you didn't mention it, right?
 
You likely need to tweak the sysctls that configure how pf and the bridge interact. See the 'PACKET FILTERING' section of the bridge(4) man page for reference.

These are what I have for a system with a bridged interface similar to yours.

In /etc/sysctl.conf :
Code:
net.link.bridge.pfil_member=0
net.link.bridge.pfil_bridge=0
net.link.bridge.pfil_local_phys=1

This lets it still filter with your preferred pf rules on igb0 for locally destined packets, but will otherwise pass data along the igb0<--[bridge]-->tap0 path. (If you want pf to do filtering of data that can reach the VM over the bridge, you'll need to enable one of the first two, and build the appropriate rules.)

For DHCP to work, I belive you also need net.link.bridge.pfil_onlyip=0, but that may not be required with the above values set; I honestly can't remember. If everything except DHCP (i.e. everything works if you assign a static IP in the VM) is working, this is the culprit.
Edit: looking at the code, if _member and _bridge are both 0, _onlyip doesn't come into play at all.

Related sysctl descriptions:
Code:
$ sysctl -d net.link.bridge | grep pfil
net.link.bridge.pfil_local_phys: Packet filter on the physical interface for locally destined packets
net.link.bridge.pfil_member: Packet filter on the member interface
net.link.bridge.pfil_bridge: Packet filter on the bridge interface
net.link.bridge.pfil_onlyip: Only pass IP packets when pfil is enabled
 
For reference, the defaults:

Code:
net.link.bridge.pfil_local_phys=0
net.link.bridge.pfil_member=1
net.link.bridge.pfil_bridge=1
net.link.bridge.pfil_onlyip=1

Note I believe you can leave (most of) the defaults and build the PF rules to allow packets in on your physical interface and destined for your VM, but to me it's much cleaner to take PF out of the equation for the bridge traffic, and just write the rules for locally destined (as if there was no bridge at all) packets. With this approach, you deal with any firewall you want on the VM on the VM rather than having the additional complexity of the host pre-filtering the traffic.

You will need to disable the pfil_onlyip option if _member or _bridge are =1 to support DHCP.
 
Thank you guys, I've finally resolved the pf configuration using NAT. It's soooo good... amazing firewall.
 
Back
Top