3.5 KiB
mdns-reflector — IPv4 + IPv6 mDNS reflector for MikroTik RouterOS
A lightweight mDNS reflector (multicast DNS repeater) designed to run as a container on MikroTik RouterOS 7.x. It relays mDNS packets (port 5353, groups 224.0.0.251 and ff02::fb) between all specified interfaces — both IPv4 and IPv6 — filling the gap where RouterOS' built-in /ip dns set mdns-repeat-ifaces= only supports IPv4.
How it works
- Opens one IPv4 and one IPv6 UDP socket per interface, bound to that interface via
SO_BINDTODEVICE - Joins the mDNS multicast groups on each interface
- Spawns one reader thread per interface; packets received on any interface are forwarded to every other interface
- Writes a health heartbeat to
/tmp/mdns-healthevery 10 seconds - Runs as non-root user
mdnswithcap_net_raw,cap_net_bind_servicecapabilities
Quick start
# Build
podman build -t mdns-reflector .
# Run (auto-detect non-loopback interfaces)
podman run --rm --network host mdns-reflector
# Run with explicit interfaces
podman run --rm --network host \
-e INTERFACES="ether1 bridge" \
mdns-reflector
MikroTik RouterOS container setup
RB5009 running RouterOS 7.x:
/container config set registry-url=https://git.sb20.xengi.de
/container add \
remote-image=git.sb20.xengi.de/xengi/mdns-reflector:latest \
interface=bridge \
root-dir=mdns-reflector \
envlist=mdns-env \
start-on-boot=yes
/container env add name=mdns-env key=INTERFACES value="bridge iot private"
/container start [find where image~"mdns-reflector"]
Note: MikroTik containers require
--network host-like behavior, which you get by attaching the container to a single interface (usually your LAN bridge). TheINTERFACESenv var tells the reflector which interfaces inside the host to bridge mDNS across.
Unprivileged container considerations
This container already runs as non-root user
mdns. On RouterOS, ensure the container has sufficient privileges:/container set [find where image~"mdns-reflector"] \ nesting=yes \ hostname=mdns-reflector
Environment variables
| Variable | Default | Description |
|---|---|---|
INTERFACES |
all non-lo interfaces | Space-separated list of interface names to bridge |
Health check
The container exposes a Docker HEALTHCHECK driven by healthcheck.sh. It verifies:
- Health heartbeat file exists and is < 30 seconds old
mdns-repeaterprocess is running- At least one bound UDP socket exists on port 5353
Then on RouterOS, pull the updated image:
/container pull [find where image~"mdns-reflector"]
Building from source
# Multi-stage build (produces ~3 MB image)
podman build -t mdns-reflector .
# Or compile the C binary directly
gcc -static -O2 -o mdns-repeater mdns-repeater.c -lpthread
Files
| File | Purpose |
|---|---|
mdns-repeater.c |
IPv4/IPv6 mDNS reflector |
Dockerfile |
Multi-stage Alpine build |
entrypoint.sh |
Interface detection & launcher |
healthcheck.sh |
Docker HEALTHCHECK probe |
.dockerignore |
Reduces build context size |
License
MIT