steve@linuxbox:~$ dig myname.mydomain.com @ns1.mydomain.com
; <<>> DiG 9.8.1-P1 <<>> myname.mydomain.com @ns1.mydomain.com
;; global options: +cmd
;; connection timed out; no servers could be reached
Whereas, a request for a name with a public IP would work:
steve@linuxbox:~$ dig mypublicname.mydomain.com @ns1.mydomain.com
; <<>> DiG 9.8.1-P1 <<>> mypublicname.mydomain.com @ns1.mydomain.com
;; global options: +cmd
;; Got answer:
--snip--
mypublicname.mydomain.com. 86400 IN A 4.2.2.2
So... what is happening?
As I often do, my first step into looking was a packet capture. I captured whilst doing first a "public" request and then a "private" request. The result was as below:
So, for a "normal", "public" request, the response is fine. For the "private" request, the server replies correctly, but our NAT router is sending an ICMP Destination Unreachable and the response never reaches the client. So, this immediately says that the router is doing some level of inspection at Layer 5 or above and electing to drop our DNS response, which we don't want.
A quick bit of Googling later and I found this incredibly helpful article: https://plone.lucidsolutions.co.nz/networking/cisco/ios/a-workaround-for-nat-rewriting-dns-packets
This makes complete sense. So, I added the no-payload option to my NAT statement and immediately, all my DNS requests started working!