mullvad / dns-blocklists

Lists and configuration for our DNS blocking service
1.14k stars 49 forks source link

Getting 400 when resolving DoH base DNS #118

Closed SansSerif1 closed 1 year ago

SansSerif1 commented 1 year ago

Hello! I'm trying to set up encrypted DNS via https://base.dns.mullvad.net/dns-query on my Linux machine, currently with dns-over-https, however every response I get from the server is just 400 Bad Request.

If I do dig @127.0.0.1 -p 53 mullvad.net, I get this:

; <<>> DiG 9.18.19 <<>> @127.0.0.1 -p 53 mullvad.net
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 33241
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;mullvad.net.                   IN      A

;; Query time: 166 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sat Nov 04 14:44:01 CET 2023
;; MSG SIZE  rcvd: 29

And the doh client prints this:

2023/11/04 14:38:18 random mode start
127.0.0.1:56220 - - [04/Nov/2023:14:44:01 +0100] "mullvad.net. IN A"
2023/11/04 14:44:01 choose upstream: upstream type: IETF, upstream url: https://base.dns.mullvad.net/dns-query
2023/11/04 14:44:01 HTTP error from upstream https://base.dns.mullvad.net/dns-query: 400 Bad Request

If I try to resolve manually via Cloudflare, I get a normal response:

*   Trying 104.16.249.249:443...
* Connected to cloudflare-dns.com (104.16.249.249) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=cloudflare-dns.com
*  start date: Jan 12 00:00:00 2023 GMT
*  expire date: Jan 11 23:59:59 2024 GMT
*  subjectAltName: host "cloudflare-dns.com" matched cert's "cloudflare-dns.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://cloudflare-dns.com/dns-query?name=mullvad.net&type=A
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: cloudflare-dns.com]
* [HTTP/2] [1] [:path: /dns-query?name=mullvad.net&type=A]
* [HTTP/2] [1] [user-agent: curl/8.4.0]
* [HTTP/2] [1] [accept: application/dns-json]
> GET /dns-query?name=mullvad.net&type=A HTTP/2
> Host: cloudflare-dns.com
> User-Agent: curl/8.4.0
> accept: application/dns-json
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 200
< server: cloudflare
< date: Sat, 04 Nov 2023 13:48:35 GMT
< content-type: application/dns-json
< access-control-allow-origin: *
< content-length: 218
< cf-ray: 820d50c22a472d80-ARN
<
* Connection #0 to host cloudflare-dns.com left intact
{"Status":0,"TC":false,"RD":true,"RA":true,"AD":true,"CD":false,"Question":[{"name":"mullvad.net","type":1}],"Answer":[{"name":"mullvad.net","type":1,"TTL":60,"data":"45.83.223.209"}],"Comment":["EDE(18): Prohibited"]}

However if I try the same with the Mullvad DNS, the 400 error code gets shown once again:

*   Trying 194.242.2.4:443...
* Connected to base.dns.mullvad.net (194.242.2.4) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=se-sto-dns-001.mullvad.net
*  start date: Oct 16 11:16:15 2023 GMT
*  expire date: Jan 14 11:16:14 2024 GMT
*  subjectAltName: host "base.dns.mullvad.net" matched cert's "base.dns.mullvad.net"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://base.dns.mullvad.net/dns-query?name=mullvad.net&type=A
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: base.dns.mullvad.net]
* [HTTP/2] [1] [:path: /dns-query?name=mullvad.net&type=A]
* [HTTP/2] [1] [user-agent: curl/8.4.0]
* [HTTP/2] [1] [accept: application/dns-json]
> GET /dns-query?name=mullvad.net&type=A HTTP/2
> Host: base.dns.mullvad.net
> User-Agent: curl/8.4.0
> accept: application/dns-json
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 400
<
* Connection #0 to host base.dns.mullvad.net left intact

What am I doing wrong?

oskaralmlov commented 1 year ago

Hi!

Have you done any specific configuration in the client except for providing the hostname of our service?

A 400 response suggests that the client has provided an invalid query.

What happens if you do this: dig +https @base.dns.mullvad.net <domain>

SansSerif1 commented 1 year ago

Hello, thanks for replying!

Have you done any specific configuration in the client except for providing the hostname of our service?

Pretty much no, just got rid of the default servers, so the only one is the mullvad one. Here is my config:

listen = [
    "127.0.0.1:52",
    "[::1]:52",
]

[upstream]
upstream_selector = "random"

[[upstream.upstream_ietf]]
    url = "https://base.dns.mullvad.net/dns-query"
    weight = 50

[others]
bootstrap = [
    "194.242.2.4:53",
]
passthrough = [
]
timeout = 30
no_cookies = true
no_ecs = false
no_ipv6 = false
no_user_agent = false
verbose = true
insecure_tls_skip_verify = false

A 400 response suggests that the client has provided an invalid query.

Oh, so what should I try in curl instead of curl 'https://base.dns.mullvad.net/dns-query?name=mullvad.net&type=A'? Does the server support a query like this?

What happens if you do this: dig +https @base.dns.mullvad.net <domain>

Well it works, but I cannot see how does that work under the hood (what request get sent where). I can code my own resolver that just uses dig as a backend, tho :)

oskaralmlov commented 1 year ago

Hi, sorry for taking so long to reply, we have been busy with so many other things :)

So the issue here is that the application that you are using is trying to use the Google JSON API [1] which isn't supported by the software that we use (BIND) to provide the DoH/Encrypted DNS service.

As for why it's working on Cloudflare it's because they've decided to support Google's JSON API [2].

In order to perform a lookup using curl you need to get the query in wire format [3] which would look like this:

user@hostname:~# curl --silent https://dns.mullvad.net/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB | hexdump  -c

0000000  \0  \0 201 200  \0 001  \0 001  \0  \0  \0  \0 003   w   w   w
0000010  \a   e   x   a   m   p   l   e 003   c   o   m  \0  \0 001  \0
0000020 001 300  \f  \0 001  \0 001  \0  \0 250 210  \0 004   ] 270 330
0000030   "                                                            
0000031

[1] https://developers.google.com/speed/public-dns/docs/doh/json [2] https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/ [3] https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-wireformat

TL;DR: We don't support that request format. Hope this helps :)

SansSerif1 commented 1 year ago

Hello, thanks for replying :) I've reread the dns-over-https docs, and it says that it does use Google JSON, but it should also support the IETF RFC8484 requests. Could not get that to work, so I tried another software, smartdns. However, that does not seems to work too and there are no mentions of it using the Google JSON format in the docs, this time.

Here is my little config, set up to disable caching so I can see the real results:

server-name dns
resolv-hostname no
user nobody
bind 127.0.0.1:52
cache-size 0
cache-persist no
prefetch-domain no
serve-expired no
speed-check-mode ping
force-qtype-SOA 65
dualstack-ip-selection yes
log-level info
log-file /var/log/smartdns/smartdns.log
audit-enable no
server https://all.dns.mullvad.net/dns-query # <--- MULLVAD
server https://dns.quad9.net/dns-query # <--- QUAD9

(Trying with dig @127.0.0.1 -p 52 example.com) Response with Mullvad:

; <<>> DiG 9.18.19 <<>> @127.0.0.1 -p 52 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 7232
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.                   IN      A

;; Query time: 2143 msec
;; SERVER: 127.0.0.1#52(127.0.0.1) (UDP)
;; WHEN: Mon Nov 27 19:20:03 CET 2023
;; MSG SIZE  rcvd: 29

Response with Quad9:

; <<>> DiG 9.18.19 <<>> @127.0.0.1 -p 52 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52824
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.com.                   IN      A

;; ANSWER SECTION:
example.com.            19412   IN      A       93.184.216.34

;; Query time: 216 msec
;; SERVER: 127.0.0.1#52(127.0.0.1) (UDP)
;; WHEN: Mon Nov 27 19:29:05 CET 2023
;; MSG SIZE  rcvd: 45

I do not know what am I doing wrong, neither do I think that smartdns does not support the default IETF format :/ Would it be possible in future to make the servers support more formats, so more software can work with your servers?

Thanks much for this amazing service and assistance, have a perfect day :)