Having built the nginx-proxy-avahi-helper container to expose proxied instances as mDNS CNAME entries on my LAN I also wanted a way to allow these containers to also be able to resolve other devices that are exposed via mDNS on my LAN.
By default the Docker DNS service does not resolve mDNS hostnames, it either takes the docker hosts DNS server settings or defaults to using Goolge’s 8.8.8.8 service.
The containers themselves can’t do mDNS resolution unless you set their network mode to host
mode which isn’t really what I want.
You can pass a list of DNS servers to a docker container when it’s started with the --dns=
command line argument which means that if I can run a bridge that will convert normal DNS requests into mDNS resquests on my LAN I should be able to get the containers to resolve the local devices.
I’ve played with writing DNS proxies before when I was looking at DoH so I had a reasonably good idea where to start.
const dgram = require('dgram')
const dnsPacket = require('dns-packet')
const mdnsResolver = require('mdns-resolver')
const port = process.env["DNS_PORT"] || 53
const server = dgram.createSocket('udp4')
server.on('listening', () => {
console.log("listening")
})
server.on('message', (msg, remote) => {
const packet = dnsPacket.decode(msg)
var response = {
type: "response",
id: packet.id,
questions: [ packet.questions[0] ],
answers: []
}
mdnsResolver.resolve(packet.questions[0].name, packet.questions[0].type)
.then(addr => {
response.answers.push({
type: packet.questions[0].type,
class: packet.questions[0].class,
name: packet.questions[0].name,
ttl: 30,
data: addr
})
server.send(dnsPacket.encode(response), remote.port)
})
.catch (err => {
server.send(dnsPacket.encode(response), remote.port)
})
})
server.bind(port)
This worked well but I ran into a small problem with the mdns-resolver
library which wouldn’t resolve CNAMEs, but a small pull request soon fixed that.
The next spin of the code added support to send any request not for a .local
domain to an upstream DNS server to resolve which means I don’t need to add as may DNS servers to each container.
All the code is on github here.
Bonus points
This will also allow Windows machines, which don’t have native mDNS support, to do local name resolution.