# 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-health` every 10 seconds - Runs as non-root user `mdns` with `cap_net_raw,cap_net_bind_service` capabilities ## Quick start ```bash # 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: ```routeros /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). The `INTERFACES` env 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: > > ```routeros > /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: 1. Health heartbeat file exists and is < 30 seconds old 2. `mdns-repeater` process is running 3. At least one bound UDP socket exists on port 5353 Then on RouterOS, pull the updated image: ```routeros /container pull [find where image~"mdns-reflector"] ``` ## Building from source ```bash # 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