# OPNsense Bridge Interface? Use Floating Rules for mDNS

Last updated: 2025-03-09

An attempt to save a small part of the world from a lot of keyboard-face-smashing

![A screenshot of OPNsense floating rules](/posts/opnsense-floating-rules/opnsense.jpg)

This is just a quick post documenting a gotcha in OPNsense that was really
confusing until I figured out what was going on, with the hope that it might
help someone avoid a lot of (hopefully metaphorical) keyboard-face-slamming.

**tl;dr: If you're bridging interfaces in OPNsense and can't get mDNS working,
try applying floating rules for the mDNS response packets on the bridge rather
than a rule on the bridge interface. Also, if you're trying to establish mDNS
connectivity from within a Docker network to a physical network, you will need
to use a dockerized Avahi daemon to reflect mDNS.**

---

A key part of this is my router, which instead of a regular commercial router,
is a [E3-1270 v3 X10SLH-N6-ST031](https://www.ebay.com/itm/143586569305)
Supermicro box that was formerly used by IBM SoftLayer. I'm pretty certain of
this because it still has the SoftLayer badge on the front :)

Ever since initially setting it up, for some reason I could never get mDNS
working properly, which is weird because of all the packets that need to get
routed, mDNS should need to get routed the least. Typically, it should work in
any regular network without needing any special configuration, daemons or goat
sacrifices.

The root cause of this is because the X10SLH-N6-ST031 has individual network
interfaces for each port, rather than multiple ports on a single network
interface like on your typical router. This helps with flexibility and
high-throughput environments like a datacenter but not as much environments like
my home network, so I bridged them together into one virtual interface using the
[OPNsense bridge feature](https://docs.opnsense.org/manual/how-tos/lan_bridge.html).
While this normally isn't ideal for network interfaces since it requires more
compute and therefore power than using a dedicated network switch, I have plenty
of CPU to spare and don't mind the overhead.

For a while, I couldn't figure out why mDNS wasn't being routed, because
according to the
[OPNsense documentation](https://docs.opnsense.org/manual/other-interfaces.html#bridge),
"Multicast and broadcast packets are always forwarded to all interfaces that are
part of the bridge." However, after reading more into mDNS, I realized that mDNS
responses are multicast (broadcast) back from `224.0.0.251` or `[ff02::fb]`,
meaning they might look like incoming traffic and get blocked by the firewall (I
think). However, adding pass rules on the LAN interface didn't seem to have any
effect and no packets were getting logged from that rule.

Eventually, I had an idea and recreated the same exact rule as a floating rule
targeted just to the LAN. And then bam, all of a sudden the packets were finally
getting through!

![A screenshot of OPNsense firewall logs with packets being matched](/posts/opnsense-floating-rules/log.jpg)

This is just a hunch, but even though the packets are shown as coming from LAN
in the screenshot above, I have a feeling that packets are actually arriving on
the individual network interfaces and get filtered out by interface-specific
rules before the OPNsense bridge logic can transfer them to the joined LAN
interface, unless there are floating rules that can preempt this logic. Under
the floating rules section, OPNsense displays "If no rule here matches, the
per-interface or default rules are used."

Now, at this point mDNS was working in my network, but I needed to do another
special thing for my usecase, which was letting the
[ESPHome](https://esphome.io/) Docker container in my Docker compose stack
communicate to my local network without needing to use `network: host` so I
could reverse proxy it without binding ports on my host machine. Thankfully,
[flungo](https://github.com/flungo) on Github has a great dockerized version of
the Avahi daemon that
[he uses to do just that](https://github.com/flungo-docker/avahi/issues/2#issuecomment-761841275).

So, using flungo's comment, if you're like me and want to establish mDNS
connectivity from within a Docker network to a physical network, you'll need to
add an extra lan network that your Docker compose stack. Here's the
`docker-compose.yml` format of the Avahi mDNS reflector that flungo suggested:

```yml
services:

  # ...other services...

  avahi:
    image: flungo/avahi:latest
    container_name: avahi
    restart: always
    networks:
      default:
      lan:
        ipv4_address: 192.168.0.9
    environment:
      - REFLECTOR_ENABLE_REFLECTOR=yes

networks:
  default:
    name: main
  lan:
    name: lan
    driver: macvlan
    driver_opts:
      parent: eno1 # this may be different
    ipam:
      config:
        - subnet: 192.168.0.0/24
          gateway: 192.168.0.1
```

In this example above, keep in mind that `eno1` may be different on your machine
depending on the name of your network interface. You can list all the network
interfaces on linux with `ip link show` if you want to double check. You should
also make sure that `192.168.0.9` is reserved in your network, since this is how
your network will communicate to the Avahi reflector and the rest of the Docker
compose stack. After this, mDNS should be fully working in your network and in
your Docker compose stack!

I've included the complete IPv4 and IPv6 OPNsense rules I used to get mDNS
working below. Please email me at <a
href="mailto:olivia@sculley.dev">olivia@sculley.dev</a> if you have any issues
or questions about this post. Thank you!

---

![A screenshot of the IPv4 MDNS OPNsense floating rule](/posts/opnsense-floating-rules/mdns-ipv4.jpg)

![A screenshot of the IPv6 MDNS OPNsense floating rule](/posts/opnsense-floating-rules/mdns-ipv6.jpg)
