Resolving query[type=65] to local address for iOS clients in dnsmasq

Hi there,

I've been using OpenWrt 22.03.5 on my Belkin RT3200 for the last couple of months, and have been enjoying it. I'm sort of stumped on something right now, and I can't find a direct answer through Googling, so I was hoping maybe the community had a solution.

For both of the iOS devices on my network, they seem to be hit or miss whether or not they can resolve to my server's local address. The server and the iOS devices are on the same LAN network. I've configured both devices to use a "manual" DNS server of my OpenWrt router.

Here is a portion of my dnsmasq config that shows the DNS records I have setup:

config dnsmasq
        ...
        list address '/mydomain.com/fd17:b6b2:88cd::42b'
        list address '/mydomain.com/192.168.1.69'

Here is the log I'm seeing from logread when I try to query one of my domains from my iOS device:

Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1757 192.168.1.178/56747 query[type=65] sub.mydomain.com from 192.168.1.178
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1757 192.168.1.178/56747 forwarded sub.mydomain.com to 1.0.0.1
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1758 192.168.1.178/53661 query[AAAA] sub.mydomain.com from 192.168.1.178
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1758 192.168.1.178/53661 config sub.mydomain.com is fd17:b6b2:88cd::42b
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1759 192.168.1.178/62199 query[A] sub.mydomain.com from 192.168.1.178
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1759 192.168.1.178/62199 config sub.mydomain.com is 192.168.1.69
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1757 192.168.1.178/56747 reply sub.mydomain.com is <CNAME>
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1757 192.168.1.178/56747 reply pixie.porkbun.com is NODATA
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1760 192.168.1.178/50035 query[A] pixie.porkbun.com from 192.168.1.178
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1760 192.168.1.178/50035 forwarded pixie.porkbun.com to 1.0.0.1
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1760 192.168.1.178/50035 reply pixie.porkbun.com is 44.227.76.166
Sun Dec  3 03:35:25 2023 daemon.info dnsmasq[1]: 1760 192.168.1.178/50035 reply pixie.porkbun.com is 44.227.65.245

Right now, my domain is parked on Porkbun, but it looks like both the A and AAAA records are resolving to the correct internal address. It's the pesky query[type=65] that is being forwarded to the Cloudflare DNS server and returning the NODATA response from my parked domain. I figure this is why I can intermittently connect to my local server, since sometimes the correct local address is returned to the device before the other response can return.

Reading through the docs, I've tried out the banip package (which I have other future uses for), but as I understand it, the "doh" list won't really help me in this situation because it is dnsmasq that is forwarding the request to my upstream DNS server anyway. Maybe I'm misunderstanding this, but it didn't seem to help when I added the "doh" list.

I've also seen others have similar questions on the PiHole subreddit which were solved by enabling a specific filter to ignore these types of DNS queries. This kind of functionality doesn't seem to natively exist in the OpenWrt version of dnsmasq.

Are there any other solutions to this beyond setting up a local DNS server separate from OpenWrt? I'm sure a local DNS server is a future project for me, but I was hoping to solve this within OpenWrt to tide me over until then.

Thank you very much!

Same issue here. In my case, it started when I renamed my local server/domain settings from example.local to lan, before that everything worked fine.

Someone suggested to add the following to /etc/dnsmasq.conf:

dns-rr=example.com,65,

However, that doesn't do anything for me (I assumed example.com should be replaced by the hostname that I want to be able to resolve entirely locally).

Alternatively, I've come across iptables rules that will block type=65 requests:

iptables -t raw -I OUTPUT -p udp --dport 53 -m comment --comment DNS_Type_65 -m string --hex-string "|0000410001|" --algo bm --to 65535 --icase -j DROP
iptables -t raw -I OUTPUT -p tcp --dport 53 -m comment --comment DNS_Type_65 -m string --hex-string "|0000410001|" --algo bm --to 65535 --icase -j DROP

I have no idea if this is possible with nftables though.

1 Like

I stumbled across the same suggestion of using the dns-rr option. However, that didn't work for me either.

I would be curious if this can be done with nftables as well. I am not knowledgeable enough at the moment to experiment with them.

I did come across an additional resource regarding a dnsmasq patch that apparently adds this type of filtering. I'm not sure if this is a recommended workaround for something like OpenWrt though. I haven't had a chance to test it either.

1 Like

I guess we both Duckduckgo'd the exact same things, I also found the aforementioned patch :sweat_smile:

At the moment I have higher priority things to do, but once those are done my intention is to see if I can set up a build environment for OpenWRT and compile a custom dnsmasq for it with the patches.

1 Like

Try also

config dnsmasq
        ...
        list address '/*.mydomain.com/fd17:b6b2:88cd::42b'
        list address '/*.mydomain.com/192.168.1.69'

I don't think dnsmasq is set up to handle/intercept SVCB records yet.

Are you sure about that?
I ran some tests and after setting this option, queries (type 65) for the specified domain are no longer forwarded to the upstream DNS servers.

dnsmasq returns this:

;; ANSWER SECTION:
example.com.            0       IN      TYPE65  \# 0
2 Likes

No, turns out I queried the server incorrectly :sweat_smile:

iOS is now able to resolve the hostnames I've defined that way a few times, then they stop working again. All private relay settings are turned off. I'll try and run dnsmasq with logging enabled to see if that provides any clues.

1 Like

I have something very similar already:

option local '/lan/'
option domain 'lan'
list address '/nas.lan/.nas.lan/192.168.23.2'

That works fine, foo.bar.nas.lan resolves to 192.168.23.2 as expected.

Is using a wildcard (*) different?

You are correct, it looks like the config does prevent forwarding to any upstream DNS servers. However, I don't think I have the value of the record quite right. Using nothing as the third argument returns a malformed response from dig. If I fill that third position with some zeroes, I can get something in the answer section. I know this position requires hex, but I'm unsure of which record to put here.

Additionally, it seems I have to restart dnsmasq rather than just reload. This may have been why I didn't see anything at first - I thought a reload would be sufficient.

Here's the answer section I get from digging.

;; ANSWER SECTION:
example.com. 0     IN      HTTPS   0 .

Then the corresponding dnsmasq log entry shows that it is not being forwarded upstream anymore. I'm just not getting the reply I want.

Sat Dec 23 18:26:20 2023 daemon.info dnsmasq[1]: 219 192.168.1.241/52032 query[type=65] example.com from 192.168.1.241
Sat Dec 23 18:26:20 2023 daemon.info dnsmasq[1]: 219 192.168.1.241/52032 config example.com is <type=65>

Also, using a wildcard in the first position of the dns-rr entry does not seem to do anything as this seems to make it forward the query upstream again. Perhaps there's something else I haven't considered. Adding each of my subdomains would be a hassle, but at least I'd have local resolution on these iOS devices!

1 Like

I don't believe a wildcard (*) resolves any differently here. According to these dnsmasq man pages it should match identically if the wildcard is omitted.

--address=/example.com/# will return NULL addresses for example.com and its subdomains.

Yes. A wildcard is a glob, and before a . it matches (only) all subdomains.

The manpage says this (which says "as with --server", and "The domain specification works in the same way as for --server,"):

 For historical reasons, the pattern /.google.com/ is equivalent to /google.com/ if you wish to match any subdomain of google.com but NOT google.com itself, use /*.google.com/ 

I guess the problem here is that the HTTPS - type 65 - record is not handled without --dns-rr.

1 Like

I just found that the version of dig that I was using (the one that comes with macOS) is too old to properly deal with these queries, which made me think everything worked fine.

But trying on a Linux server yielded "malformed message packet" errors, same as you.

I now use this:

dns-rr=test.lan,65,000000

Which seems to please both dig and iOS :partying_face:

And indeed, I now have to add an entry for every local host I want to be able to access via iDevice, but that's a small price to pay to get this working again :blush:

2 Likes

Small issue: it looks like Chrome-based (desktop) browsers don't like this. I tested both Brave (my main browser) and Thorium, and with both opening a hostname with a dns-rr line results in an automatic upgrade to HTTPS, and a subsequent "ERR_SSL_UNRECOGNIZED_NAME_ALERT" error.

Safari doesn't seem to care, so it's something specific to the other two browsers.

I added specific "mobile" hostnames for the hosts that I want to be able to open on iOS, which solves the issue (at least for Thorium, Brave keeps trying to upgrade, but it looks to be cache-related. EDIT: restarting Brave fixed it).

On my iOS devices, it's a little hard to test if this actually worked on Safari, since it sometimes resolves the correct local address without issue for a week or so even after clearing browsing data. At the moment, my other web services are behaving appropriately without the dns-rr entry.

My main test for this has been to use the Jellyfin iOS app. This iOS app still has trouble resolving to the local address when I fill the dns-rr option with 000000, so I may need to ask a question in the appropriate forum for Jellyfin. I could try using a properly formatted hex response that includes the local IP of the server, but I believe other data needs to be included in this hex value that I'm unsure of.

I was hoping to resolve this in a more elegant way, and that might come when I setup something like a PiHole. I still may try that dnsmasq patch and report back.

1 Like

I give up with trying to get dnsmasq to handle this, I can't get it to work reliably :frowning:

My preferred local domain is .lan, but for local hosts that I want to be able to access on a mobile device I'm now using hostname.home.local:

address=/hostname.home.local/192.168.1.123

iOS handles .local requests differently, since they are also used for mDNS/zeroconf. My guess is that it passes requests to mDNSResponder, which will forward the request to OpenWRT/dnsmasq if it cannot handle the request.

(I initially tried using hostname.local, but mDNSResponder will first try to query the network to see if any hosts respond to that name, which takes a while. Adding a subdomain (.home.local) seems to cause mDNSResponder to forward the request directly)

.local. is reserved for zeroconf/ avahi/ bonjour/ mdns, you mustn't try to use it as static domain.

I'm still using .lan as my local domain and only let dnsmasq resolve a few .home.local hostnames. That's the only way I've found to work around this issue besides setting up something like PiHole.

Any update? I tried setting up Pihole and blocking HTTPS / Type 65 but I cant connect to any of my internal subdomains via iPhone.

My workaround with a separate internal subdomain based on .local for mobile is still working.

TL;DR: my preferred internal domain is .lan, but I never managed to get it working properly for iDevices. Specifically for those I'm now using .home.local, which isn't ideal but at least I can access my internal servers again.

For anyone else looking on how to solve the issue with DNS query[type=65] and preventing to forward upstream any query type that is not A or AAAA:

In Luci > Network > DHCP and DNS add your domain and IP in the Addresses field:
/yourdomain.example.com/192.168.1.2

and then add the same domain to the Local Server field above:
/lan/yourdomain.example.com/

This will prevent the DNS query[type=65] to be forwarded, and the only reply for yourdomain.example.com will be 192.168.1.2

The solution is based on the Dnsmasq documentation that says:

Note that the behaviour for queries which don't match the specified address literal changed in version 2.86. Previous versions, configured with (eg) --address=/example.com/1.2.3.4 and then queried for a RR type other than A would return a NoData answer. From 2.86, the query is sent upstream. To restore the pre-2.86 behaviour, use the configuration --address=/example.com/1.2.3.4 --local=/example.com/

Source: https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html

2 Likes