103 lines
3.5 KiB
Markdown
103 lines
3.5 KiB
Markdown
# 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
|
|
|