Page MenuHomeFreeBSD

bridge: default to not filtering L3
ClosedPublic

Authored by kp on Oct 15 2022, 10:02 AM.
Tags
None
Referenced Files
F105267505: D37009.diff
Sat, Dec 14, 6:31 AM
Unknown Object (File)
Fri, Dec 6, 3:11 PM
Unknown Object (File)
Tue, Dec 3, 6:57 PM
Unknown Object (File)
Mon, Nov 25, 9:52 PM
Unknown Object (File)
Mon, Nov 25, 5:16 AM
Unknown Object (File)
Sun, Nov 24, 1:47 PM
Unknown Object (File)
Sat, Nov 23, 9:08 PM
Unknown Object (File)
Fri, Nov 22, 10:56 AM

Details

Summary

Change the default for net.link.bridge.pfil_member and
net.link.bridge.pfil_bridge to zero.

That is, default to not calling layer 3 firewalls on the bridge or its
member interfaces.

With either of these enabled the bridge will, during L2 processing,
remove the Ethernet header from packets, feed them to L3 firewalls,
re-add the Ethernet header and send them out.

Not only does this interact very poorly with firewalls which defer
packets, or reassemble and refragment IPv6, it also causes considerable
confusion for users, because the firewall gets called in unexpected
ways.

For example, a bridge which contains a bhyve tap and the host's LAN
interface. We'd expect traffic between the LAN and bhyve VM to pass, no
matter what (layer 3) firewall rules are set on the host. That's not the
case as long as pfil_bridge or pfil_member are set.

MFC: never

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 47849
Build 44736: arc lint + arc unit

Event Timeline

kp requested review of this revision.Oct 15 2022, 10:02 AM

Git blame shows that pfil_bridge and pfil_member were introduced in the initial version (from OpenBSD).

The pfil framework has inet, inet6 and ethernet headers. As if_bridge is created to bridge L2 links, it seems checking ethernet header is enough. So for what reason the inet and inet6 headers are also checked?

Is transparent firewall need that ?

I'm not familiar with OpenBSD, some context lost.

I believe the primary use case for that is a "filtering bridge". Essentially a firewall that doesn't show up in a traceroute. It's documented here, although for ipf: https://docs.freebsd.org/en/articles/filtering-bridges/

This is a little off topic, but every time I looked into ip_input(), ip_output, ether_demux() and ether_output_frame(), I was wondering that if any firewall is enabled then all interfaces are affected, no matter whether they should be involved or not.

Is it possible to explicitly disable pfil on some interfaces so that the impact is as little as possible.

Something like ifp->pfil_link_disabled, ifp->pfil_inet_disabled and ifp->pfil_inet6_disabled, and always check them along with PFIL_HOOKED_{IN/OUT} .

In D37009#840455, @kp wrote:

I believe the primary use case for that is a "filtering bridge". Essentially a firewall that doesn't show up in a traceroute. It's documented here, although for ipf: https://docs.freebsd.org/en/articles/filtering-bridges/

This is what so called transparent firewall.

As a workaround, move the affected bridge and the bridge members to separate vnet (without firewall enabled).

The document https://docs.freebsd.org/en/articles/filtering-bridges/ should be update to reflect this change.

Anyway, I'm +1 for the change.

This revision is now accepted and ready to land.Oct 15 2022, 2:58 PM

This is fine but needs a serious UPDATING entry and RELNOTES. People running vm's of a bridge that uses private addresses and use any firewall for NAT-ing trafic will need to enable it themselves, or no NAT will happen.

This is fine but needs a serious UPDATING entry and RELNOTES. People running vm's of a bridge that uses private addresses and use any firewall for NAT-ing trafic will need to enable it themselves, or no NAT will happen.

Sorry, I'm not sure I follow. Are you suggesting that people are running transparent bridges to do NAT? Surely not... That's ... ew.... No, just ... no.

Outgoing traffic from a private address from the bridge to the internet needs to pass the firewall so that I can be NAT-ed.
EG: 10.0.0.1 on the bridge for the host, 10.0.0.2 in the VM/VNET jail with 10.0.0.1 as gateway, trying to reach the public address space.
Is this so ew? As this is what I use right now :-D, I really thought it was common?

Basically, my NAT rule will not see any traffic after changing these defaults, because of the pfil_bridge sysctl value.

Outgoing traffic from a private address from the bridge to the internet needs to pass the firewall so that I can be NAT-ed.
EG: 10.0.0.1 on the bridge for the host, 10.0.0.2 in the VM/VNET jail with 10.0.0.1 as gateway, trying to reach the public address space.
Is this so ew? As this is what I use right now :-D, I really thought it was common?

It's a crazy setup. Bridges should bridge and not munge packets. It's also the sort of setup that's going to break a number of "edge cases". The second you turn on scrub reassemble your IPv6 traffic is going to break, for example.

Do not do this. It's a terrible no good bad idea.

If you want to bridge your VMs to the network bridge them (i.e. include your LAN NIC in the bridge). If you want to NAT them, route them, i.e. do not include the LAN NIC in the bridge and set net.inet.ip.forwarding=1.

If you want to NAT them, route them, i.e. do not include the LAN NIC in the bridge and set net.inet.ip.forwarding=1.

This is exactly what I'm doing, I only have tap ifaces included in the bridge from the various VM's.

If you want to NAT them, route them, i.e. do not include the LAN NIC in the bridge and set net.inet.ip.forwarding=1.

This is exactly what I'm doing, I only have tap ifaces included in the bridge from the various VM's.

Then this change shouldn't affect your setup. Your traffic is still going to pass through the firewall when it gets routed, and can get NAT-ed then. You're going to save unneeded (and very confusing and difficult to design rules for) passes through the firewall on L2, but this doesn't mean that traffic that comes into the host on an if_bridge doesn't get firewall at all. It still hits the L3 hooks in all the usual places.

Ah yes indeed, I just tested, keeps working fine! Ignore my remarks, sorry for the noise.

Ah yes indeed, I just tested, keeps working fine! Ignore my remarks, sorry for the noise.

It sort of reinforces the "this setting confuses users" part of my argument :)

This revision was automatically updated to reflect the committed changes.