Micro-daemon that advertises mDNS/DNS-SD services for BigFred OS.
Quietly retries when interfaces, the BigFred control socket, or the microinit watch socket are unavailable. Always starts successfully. Survives network drop/return and interface add/remove via rtnetlink (with polling fallback). Resolves hostnames per receiving interface so a WiFi client gets the WiFi address.
- Static DNS-SD services from
$DATA_DIR/etc/microdns.json(default/data) - Hostname A records for configured
hostvalues (e.g.bigfred→bigfred.local) - Own legacy unicast / one-shot mDNS responder (RFC 6762 §6.7) so browsers and OS
resolvers (Android
getaddrinfo) can resolve.localnames — not only DNS-SD browsers. Needed because mdns-sd 0.20.3 answers unicast but hardcodes transaction ID=0(dns_parser.rs:let id = if self.multicast { 0 } else { self.id }whileDnsOutgoing.multicastis never set false). Removelegacy_unicastwhen upstream fixes that encoding. - Optional dcc-bus discovery: when
bigfred.enabled(default true), polls the loco-server Unix socket ($DATA_DIR/run/bigfred.sock) fordcc_bus_listand advertises_z21._udp/_withrottle._tcpon the ports in that JSON. Missing socket is retried everyretry.bigfredMs(default 45s). - Optional microinit watch: when
microinit.enabled(default true), holds one connection to$DATA_DIR/run/microinit.sock({type:watch,label_keys:["microdns-port"]}) and advertises running services that havemicrodns-port+microdns-type.microdns-hostis optional (kernel hostname if omitted).microdns-txt-*labels become TXT pairs. Reconnect backoff isretry.microinitReconnectMs(default 3s). Last-good ads are kept across a dropped socket. - Optional Z21 UDP LAN discovery beacon (LAN_GET_SERIAL_NUMBER reply broadcast)
- Unix control socket (
$DATA_DIR/run/microdns.sock):microdns services listqueries the live daemon - Hot-reload via inotify on the config file
- Static musl builds for linux/arm64 and linux/amd64
Integration-style unit tests live under tests/ (one file per module), matching
the microinit layout. Run with cargo test / make test.
Default path: $DATA_DIR/etc/microdns.json. Created with defaults if missing.
{
"services": [
{
"name": "bigfred",
"type": "_http._tcp",
"protocol": "tcp",
"port": 8080,
"host": "bigfred",
"txt": { "path": "/" }
}
],
"bigfred": { "enabled": true },
"microinit": { "enabled": true },
"dccBus": {
"beacon": true
},
"retry": {
"bigfredMs": 45000,
"pollMs": 25000,
"mdnsMs": 3000,
"ifaceMs": 5000,
"microinitReconnectMs": 3000
},
"skipInterfaces": [],
"interfaces": []
}bigfred.enabled(defaulttrue): poll loco-server for dcc-bus programs. Setfalseto skip dcc-bus ads.microinit.enabled(defaulttrue): watch microinit for labeled services. Setfalseif this host has no microinit socket.dccBus.beacon(defaulttrue): Z21 LAN serial broadcast on advertised UDP ports.retry.bigfredMs(default45000): wait between probes while the socket is down.retry.pollMs(default25000) is the poll interval once connected. Existing files may still useretry.microinitMs; that alias still maps topollMs(BigFred), not the microinit watch. Useretry.microinitReconnectMsfor watch reconnect backoff.- Retry intervals are configurable; config changes are hot-reloaded.
skipInterfaces(default[]): extra interface-name prefixes to skip (case-insensitive), in addition to the built-in docker/veth/br-*/cni/ flannel/virbr list. Empty by default so mDNS advertises on every usable interface, includingwlan*(a laptop on WiFi). Add["wlan"]on a hub that reserves the WiFi radio for another purpose (e.g. the BigFred hub, wherewireless-programmerowns the radio) so mDNS does not leakbigfred.local/ dcc-bus beacons onto a device config network. Entries are name prefixes, not globs or exact names:"wlan"coverswlan0/wlan1but notwlp3s0, and a short entry like"e"would takeeth0andenp1s0with it, leaving nothing to advertise on.interfaces(default[]): optional allowlist of interface-name prefixes (same prefix rules asskipInterfaces). Empty means use every usable interface that is not skipped. When set (e.g.["eth","enp"]), only matching interfaces are used; a listed interface that disappears logs a warning and is retried — it does not crash the daemon.- Hostname A/AAAA answers (
bigfred.local) are selected per receiving interface (viaIP_PKTINFO): a client querying on WiFi gets the WiFi address, not the Ethernet one. Interface add/remove/address changes are detected via rtnetlink with polling fallback.
microdns serve
# or
microdns run
# or just
microdnsList what a running daemon is advertising (static services[] plus dynamic
_z21._udp / _withrottle._tcp from the last dcc_bus_list and microinit
label watch; not Z21 LAN beacons):
microdns services list
microdns services list -o json
microdns services list --socket /data/run/microdns.sockHuman columns: NAME, TYPE, PROTO, PORT, HOST, SOURCE (static, dccBus, or microinit).
JSON is a pretty-printed { "services": [ ... ] } with the same rows (camelCase,
plus optional host / txt). The CLI talks to the live daemon over the ctl
socket — it does not read microdns.json on its own. If the socket is missing,
the error is the same shape as bf (is microdns running?).
Flags:
--config <path>— config file (default$DATA_DIR/etc/microdns.json)--data-dir <path>— setDATA_DIRbefore start--socket <path>— ctl socket (default$DATA_DIR/run/microdns.sock)-o, --output human|json—services listoutput (defaulthuman)--version/info— build and release metadata
export RUSTUP_TOOLCHAIN=stable
make build
make release
make release-musl # aarch64-unknown-linux-musl → dist/microdns-linux-arm64
make test
make clippyMIT