TuxInvader / nginx-dns

Sample Configuration for DNS over HTTPS (DoH/DoT gateway) and GSLB with NGINX
BSD 2-Clause "Simplified" License
197 stars 48 forks source link

DoH returns 502 Bad Gateway #13

Open domingo13 opened 2 years ago

domingo13 commented 2 years ago

I'm using the provide example file "nginx-doh-and-dot-to-dns.conf" on a vanilla Ubuntu 20.04 server and all DoH request returns something like this:

 curl -k "https://localhost/dns-query?name=dr.dk&type=A" 
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.21.4</center>
</body>
</html>

cat /var/log/nginx/doh-access.log 127.0.0.1 - - [20/Dec/2021:15:36:57 +0100] "GET /dns-query?name=dr.dk&type=A HTTP/2.0" [ 1640011017.583, 2.144, 2.144 . ] 502 157 "-" - - - - - MISS 127.0.0.1 - - [20/Dec/2021:15:50:43 +0100] "GET /dns-query?name=dr.dk&type=A HTTP/2.0" [ 1640011843.444, 2.158, 2.159 . ] 502 157 "-" - - - - - MISS 127.0.0.1 - - [20/Dec/2021:15:54:25 +0100] "GET /dns-query?name=dr.dk&type=A HTTP/2.0" [ 1640012065.675, 2.293, 2.293 . ] 502 157 "-" - - - - - MISS

cat /var/log/nginx/error.log 2021/12/20 15:54:23 [warn] 997#997: 7 js: process_doh_request: QS Params: name=dr.dk,type=A 2021/12/20 15:54:23 [warn] 997#997: 7 js: process_doh_request: DNS Req: GET /dns-query?name=dr.dk&type=A HTTP/1.1 2021/12/20 15:54:25 [error] 997#997: *5 upstream prematurely closed connection while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /dns-query?name=dr.dk&type=A HTTP/2.0", upstream: "http://127.0.0.1:8053/dns-query?name=dr.dk&type=A", host: "localhost"

I can see that it makes a connection to 8.8.8.8: tcpdump -nn port 53 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes 16:12:39.503706 IP 10.234.143.248.48290 > 8.8.8.8.53: Flags [S], seq 3079223311, win 64240, options [mss 1460,sackOK,TS val 3428279322 ecr 0,nop,wscale 7], length 0 16:12:39.533797 IP 8.8.8.8.53 > 10.234.143.248.48290: Flags [S.], seq 3540410280, ack 3079223312, win 65535, options [mss 1430,sackOK,TS val 1093201396 ecr 3428279322,nop,wscale 8], length 0 16:12:39.533860 IP 10.234.143.248.48290 > 8.8.8.8.53: Flags [.], ack 1, win 502, options [nop,nop,TS val 3428279352 ecr 1093201396], length 0 16:12:41.810625 IP 8.8.8.8.53 > 10.234.143.248.48290: Flags [F.], seq 1, ack 1, win 256, options [nop,nop,TS val 1093203419 ecr 3428279352], length 0 16:12:41.810626 IP 8.8.8.8.53 > 10.234.143.248.48290: Flags [F.], seq 1, ack 1, win 256, options [nop,nop,TS val 1093203650 ecr 3428279352], length 0 16:12:41.810699 IP 10.234.143.248.48290 > 8.8.8.8.53: Flags [.], ack 2, win 502, options [nop,nop,TS val 3428281629 ecr 1093203650,nop,nop,sack 1 {1:2}], length 0 16:12:41.810970 IP 10.234.143.248.48290 > 8.8.8.8.53: Flags [F.], seq 1, ack 2, win 502, options [nop,nop,TS val 3428281629 ecr 1093203650], length 0 16:12:41.835986 IP 8.8.8.8.53 > 10.234.143.248.48290: Flags [.], ack 2, win 256, options [nop,nop,TS val 1093203698 ecr 3428281629], length 0

but nothing is transmitted.

What I'm I missing?

TuxInvader commented 2 years ago

Hi @domingo13 ,

The dns query should be in this format: https://datatracker.ietf.org/doc/html/rfc8484#section-4.1.1

The url in your example should be "http://127.0.0.1:8053/dns-query?dns=<< base64 encoded DNS packet >>. It looks like you are tyring to use the JSON API for DoH as mentioned here: https://developers.google.com/speed/public-dns/docs/doh/json, but this project doesn't support that at this time.

own3mall commented 2 years ago

@TuxInvader what all would be needed to be done to support the JSON API? That would be extremely useful!

mallory98e commented 1 year ago

I'm sorry but how on earth that example even makes sense.

What he suggest is:

echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB|base64 -d wwwexamplecom

So without the dots how could it separate the tags of a domain name, it can be test.company.de or whatever.

Is there a proper implementation of this whole DoH thingy which works with Android 13 and other clients?

The reason I asking is because newer android phones go for DoT by default if they can instead of using plain old DNS on port 53, but in the future they might even default to DoH. I assume they would use the JSON interface for it.

TuxInvader commented 1 year ago

I'm sorry but how on earth that example even makes sense.

What he suggest is:

echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB|base64 -d wwwexamplecom

So without the dots how could it separate the tags of a domain name, it can be test.company.de or whatever.

Is there a proper implementation of this whole DoH thingy which works with Android 13 and other clients?

The reason I asking is because newer android phones go for DoT by default if they can instead of using plain old DNS on port 53, but in the future they might even default to DoH. I assume they would use the JSON interface for it.

The base64 string is an encoded DNS packet, your terminal is only displaying the ASCII characters. If you pipe the decoded data to od then you'll see more detail: echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB | base64 -d | od -ax

To answer your question, each record is prefixed with a length, so the dots are unnecessary. The "www" record is encoded as 7703 7777 hex - the 03 is the field length and the 77s are ASCII 'w'.

mallory98e commented 1 year ago

I'm sorry but how on earth that example even makes sense. What he suggest is: echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB|base64 -d wwwexamplecom So without the dots how could it separate the tags of a domain name, it can be test.company.de or whatever. Is there a proper implementation of this whole DoH thingy which works with Android 13 and other clients? The reason I asking is because newer android phones go for DoT by default if they can instead of using plain old DNS on port 53, but in the future they might even default to DoH. I assume they would use the JSON interface for it.

The base64 string is an encoded DNS packet, your terminal is only displaying the ASCII characters. If you pipe the decoded data to od then you'll see more detail: echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB | base64 -d | od -ax

To answer your question, each record is prefixed with a length, so the dots are unnecessary. The "www" record is encoded as 7703 7777 hex - the 03 is the field length and the 77s are ASCII 'w'.

Whose idea was this :/ Yeah I see that it makes sense for domain names like domaaaaaaaaaaaaaaaaaaaaaaaain.com to save some space.

Anyway. Is there any tool (preferably in the base os not some python/perl) which can create such weird base64 output from input data?

TuxInvader commented 1 year ago

If you want to generate the string, then you could use netcat with dig, something like this should work:

nc -undl 5553 -w 1 |  base64 > dns.txt &
dig -p 5553 @localhost www.google.com +tries=1 +qid=0 +timeout=1 
cat dns.txt

But dig can generate DoH requests for you too using +https or +http-plain. Eg:

dig -p 8080 @localhost www.google.com +tries=1 +qid=0 +timeout=1 +https
mallory98e commented 10 months ago

@TuxInvader what all would be needed to be done to support the JSON API? That would be extremely useful!

I closed this thread with this:

https://github.com/satishweb/docker-doh

I found a project which does support both and works out of the box with a single docker image. Hope it helps!