Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
Local wildcard DNS on macOS with dnsmasq#
I wanted to get wildcard DNS running on my Mac laptop, for development purposes. I wanted http://anything.mysite.lan/ to point to my localhost IP address.
I figured out how to do this using dnsmasq, installed via Homebrew.
THIS MAY BE UNNECESSARY#
Tip from Daniel Landau - anything.localhost (and foo.anything.localhost) should resolve to 127.0.0.1 already. This seems to work on macOS, so this entire TIL is likely obsolete.
1dig foo.bar.localhost1; <<>> DiG 9.10.6 <<>> foo.bar.localhost2;; global options: +cmd3;; Got answer:4;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 587645;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 16
7;; OPT PSEUDOSECTION:8; EDNS: version: 0, flags:; udp: 5129;; QUESTION SECTION:10;foo.bar.localhost. IN A11
12;; AUTHORITY SECTION:13. 10800 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2023063000 1800 900 604800 8640014
15;; Query time: 241 msec16;; SERVER: 127.0.0.1#53(127.0.0.1)17;; WHEN: Fri Jun 30 07:15:48 PDT 202318;; MSG SIZE rcvd: 121Also this broke DNS for me on other networks - see note at the bottom for details.
Original TIL continues here#
Some clues:
- This conversation with ChatGPT inspired me to look at
dnsmasq. - This Gist about dnsmasq from 2013 has a ton of relevant comments.
Installing and configuring dnsmasq#
I installed dnsmasq using Homebrew:
1brew install dnsmasqThen I viewed the configuration file that had been installed like this:
1cat $(brew --prefix)/etc/dnsmasq.confBased on the discussion in the Gist comments I decided to point *.lan (which includes any level of subdomains, so you can do foo.bar.lan) to 127.0.0.1. I did that using:
1echo 'address=/.lan/127.0.0.1' >> $(brew --prefix)/etc/dnsmasq.confStarting the service using sudo#
I tried running brew services start dnsmasq without sudo and it appeared to work, but didn’t. The correct command to run is:
1sudo brew services start dnsmasqWeirdly, even the brew services list command needs to be run as sudo. Here’s what I get with and without sudo for that command:
1brew services list1Name Status User File2caddy none3dnsmasq error 512 root ~/Library/LaunchAgents/homebrew.mxcl.dnsmasq.plist4unbound none1sudo brew services list1Name Status User File2caddy none3dnsmasq started root /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist4unbound noneTesting dnsmasq#
Running dig and specifically telling it to use the new 127.0.0.1 DNS server works:
1dig foo.test.lan @127.0.0.11; <<>> DiG 9.10.6 <<>> foo.test.lan @127.0.0.12;; global options: +cmd3;; Got answer:4;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 106185;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 16
7;; OPT PSEUDOSECTION:8; EDNS: version: 0, flags:; udp: 40969;; QUESTION SECTION:10;foo.test.lan. IN A11
12;; ANSWER SECTION:13foo.test.lan. 0 IN A 127.0.0.114
15;; Query time: 0 msec16;; SERVER: 127.0.0.1#53(127.0.0.1)17;; WHEN: Fri Jun 30 05:43:11 PDT 202318;; MSG SIZE rcvd: 57Configuring macOS to use the new DNS server#
I searched for “dns” in macOS system preferences, clicked on “DNS servers” and used the + button to add 127.0.0.1 to my list of DNS servers, leaving the previous entry in there too.
Having done this, running cat /etc/resolv.conf showed me this, with a confusing warning message:
1#2# macOS Notice3#4# This file is not consulted for DNS hostname resolution, address5# resolution, or the DNS query routing mechanism used by most6# processes on this system.7#8# To view the DNS configuration used by this system, use:9# scutil --dns10#11# SEE ALSO12# dns-sd(1), scutil(8)13#14# This file is automatically generated.15#16nameserver 127.0.0.117nameserver 10.0.0.1Running scutil --dns gave me this (truncated):
1scutil --dns1DNS configuration2
3resolver #14 nameserver[0] : 127.0.0.15 nameserver[1] : 10.0.0.16 flags : Request A records, Request AAAA records7 reach : 0x00030002 (Reachable,Local Address,Directly Reachable Address)8
9resolver #210 # ...11DNS configuration (for scoped queries)12
13resolver #114 nameserver[0] : 127.0.0.115 nameserver[1] : 10.0.0.116 if_index : 15 (en0)17 flags : Scoped, Request A records, Request AAAA records18 reach : 0x00020002 (Reachable,Directly Reachable Address)Finally, I ran a quick HTTP server using python -m http.server 8005 and confirmed that http://foo.bar.lan:8005/ in my browser worked as expected - which it did.
This broke DNS for me on other networks#
When I tried connecting to other networks later on the same day I found that DNS lookups were not working.
I eventually figured out why by running scutil --dns and noting that it was always trying to hit 10.0.0.1.
The fix was to open up the DNS servers area in Network settings again and remove ALL of the nameservers from that list. Once I did that the DNS server for the WiFi network I was connected to started working again.