A few years ago I came up with the revelation that being able to use a domain name to access services on my local network would be amazingly usefull.
And so with out doing any research, I set out to implement this.
I initially thought of using mDNS, however only having a basic understanding of how it worked, as well as a probably irrational fear of gossip based protocols, I settled on hosting my own internal DNS server and configuring it to essentially ‘poison’ any responses for domains I owned.
Looking into DNS servers, I found there are essentially two types, Authoritative, and Recursing.
An authoritative server is the authority for it’s domains. It knows the IP address for domains under it’s jurisdiction, but will return nothing for any other site. For example, Google’s authoritative server ns1.google.com
will respond with an ip for google.com
but microsoft.com
returns nothing.
A recursing DNS server’s job is to find the answer to any request. It does this by locating the authoritative DNS server for each domain in the request. Google’s 8.8.8.8
or Cloudflare’s 1.1.1.1
are examples of public DNS recursors.
My usecase would essentially be a combonation of both, because my plan was to have my router distribute my DNS server via DHCP responces, I would need to serve any request users had, even if it wasn’t a request for a local service, acting like a recursor. On the other hand any request for one of my services would need to be responded to as if it was the Authoritative Server, skiping the recursive step that would give an incorrect responce.
After a bit of googleing I came across PowerDNS Recursor, it has a Lua based scripting interface which would allow me to modify the behavior and responses of the recursor on the fly. I did not however, notice that it already had a ready made way to act as a authoritative server for certian domains… And so I made a Lua script!
-- map of domains to redirect
redir_A = {
["pve.kbnt.ca"] = "192.168.151.138",
["pve2.kbnt.ca"] = "192.168.151.221",
}
-- creates a domain set, PowerDNS's high performance domain matcher
matcher_A = newDS()
for key in pairs(redir_A) do
matcher_A:add{key}
end
function preresolve(dq) -- function called before a DNS request is resolved
if dq.qtype == pdns.A or dq.qtype == pdns.ANY then -- Check if the request is for an A record
if matcher_A:check(dq.qname) then -- check if the requested domain is in our domain set
local qn = dq.qname:toStringNoDot()
if redir_A[qn] then
dq:setRecords({})
dq:addAnswer(pdns.A, redir_A[qn], 1600) -- add our IP to the request answer
dq.rcode = pdns.NOERROR -- mark the query as resolved
dq.variable = false -- mark the result as non-varible so that PDNS will cache the result
-- pdnslog("Try set " .. qn .. " " .. redir_A[qn])
return true; -- tell PDNS we've handled the query
end
end
end
return false; -- tell PDNS to continue handleing the query normally
end
This solution has worked well for quite a while, allowing anyone on the network to have access to local services.
Unfortunately, Chrome and other browsers have begain using DNS over HTTPS, skipping my server entirely. Another issue is DNSSEC, Cloudflair, my external DNS provider uses DNSSEC to cryptographicley sign responces for my domains. Because of this, some clients have started ignoring my server’s responces as they haven’t been signed.
Because of this my DNS hack doesn’t work as well as it once did. I’ll probably have to just learn how mDNS works, i’ve also found something called search domains which sound promising… Things for the future!