dae icon indicating copy to clipboard operation
dae copied to clipboard

feat: support DoH, DoT, DoH3, DoQ

Open EkkoG opened this issue 1 year ago • 18 comments

Background

dae lacks support for some encrypted DNS protocols, this PR adds support for DoH, DoT, DoH3, DoQ

TODO

  • [x] support config DoH and DoH3 url path
  • [x] dns.google.com compatible issue

Checklist

  • [x] The Pull Request has been fully tested
  • [x] There's an entry in the CHANGELOGS
  • [ ] There is a user-facing docs PR against https://github.com/daeuniverse/dae

Full Changelogs

  • feat: support DoH, DoT, DoH3, DoQ

Issue Reference

Closes #321 Closes #583

Test Result

time="Sep 24 15:58:37" level=trace msg="Received UDP(DNS) 192.168.33.244:41532 <-> 192.168.33.1:53: wq.io. A" time="Sep 24 15:58:37" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="tls://dns.google:853" time="Sep 24 15:58:37" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4 6] l4protos=[tcp] upstream="tls://dns.google:853" use="8.8.8.8:853" time="Sep 24 15:58:37" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="tls://dns.google:853" time="Sep 24 15:58:37" level=info msg="192.168.33.244:41532 <-> 8.8.8.8:853" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=50022 pname=dig policy=fixed qtype=A time="Sep 24 15:58:37" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

time="Sep 24 15:57:36" level=trace msg="Received UDP(DNS) 192.168.33.244:50965 <-> 192.168.33.1:53: wq.io. A" time="Sep 24 15:57:36" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="http3://dns.alidns.com:443" time="Sep 24 15:57:36" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="http3://dns.alidns.com:443" use="223.5.5.5:443" time="Sep 24 15:57:36" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="http3://dns.alidns.com:443" time="Sep 24 15:57:36" level=info msg="192.168.33.244:50965 <-> 223.5.5.5:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=direct pid=49833 pname=dig policy=fixed qtype=A time="Sep 24 15:57:36" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

time="Sep 24 15:56:57" level=trace msg="Received UDP(DNS) 192.168.33.244:39025 <-> 192.168.33.1:53: wq.io. A" time="Sep 24 15:56:57" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="https://dns.alidns.com:443" time="Sep 24 15:56:57" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4 6] l4protos=[tcp] upstream="https://dns.alidns.com:443" use="223.5.5.5:443" time="Sep 24 15:56:57" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="https://dns.alidns.com:443" time="Sep 24 15:56:57" level=info msg="192.168.33.244:39025 <-> 223.5.5.5:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=49693 pname=dig policy=fixed qtype=A time="Sep 24 15:56:57" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

EkkoG avatar Sep 24 '24 16:09 EkkoG

UPDATE!

DoH3 scheme is h3 now

time="Sep 24 17:15:26" level=trace msg="Received UDP(DNS) 192.168.33.244:52874 <-> 192.168.33.1:53: wq.io. A" time="Sep 24 17:15:26" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443" time="Sep 24 17:15:26" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="h3://dns.alidns.com:443" use="223.5.5.5:443" time="Sep 24 17:15:26" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443" time="Sep 24 17:15:26" level=info msg="192.168.33.244:52874 <-> 223.5.5.5:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=direct pid=51456 pname=dig policy=fixed qtype=A time="Sep 24 17:15:26" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

And I will try to make both h3 and http3 work

EkkoG avatar Sep 24 '24 17:09 EkkoG

This is turely an exciting job! I will take the time to review it.

mzz2017 avatar Sep 24 '24 17:09 mzz2017

Both h3 and http3 can be DoH3's scheme now

EkkoG avatar Sep 24 '24 17:09 EkkoG

Finally, someone has taken action on DNS. Awesome. ~~By the way, can you also support DoQ, like Ali's quic://223.5.5.5? It seems to be there, haha.~~ By the way, currently only TLS and HTTPS are working; it seems that TCP is also broken.

douglarek avatar Sep 25 '24 02:09 douglarek

I do not change the behavior of TCP dns and I just tested it works well

time="Sep 25 02:59:13" level=trace msg="Received UDP(DNS) 192.168.33.244:50348 <-> 192.168.33.1:53: wq.io. A"
time="Sep 25 02:59:13" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="tcp://dns.google:53"
time="Sep 25 02:59:13" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4 6] l4protos=[tcp] upstream="tcp://dns.google:53" use="8.8.4.4:53"
time="Sep 25 02:59:13" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="tcp://dns.google:53"
time="Sep 25 02:59:13" level=info msg="192.168.33.244:50348 <-> 8.8.4.4:53" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=59922 pname=dig policy=fixed qtype=A
time="Sep 25 02:59:13" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

DoQ is working in process

ODoH is on the plan

EkkoG avatar Sep 25 '24 03:09 EkkoG

Since DoH3 is broken by FakeNetPacketConn's implementation, I have forked the outbound package and temporary disable some code about quic.OOBCapablePacketConn implement, If you have any conclusions about this issue, please let me know. cc @mzz2017

EkkoG avatar Sep 25 '24 15:09 EkkoG

time="Sep 25 17:03:19" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="quic://dns-unfiltered.adguard.com:853"
time="Sep 25 17:03:19" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="quic://dns-unfiltered.adguard.com:853" use="94.140.14.140:853"
time="Sep 25 17:03:21" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="quic://dns-unfiltered.adguard.com:853"
time="Sep 25 17:03:21" level=info msg="192.168.33.244:58565 <-> 94.140.14.140:853" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=direct pid=9110 pname=dig policy=fixed qtype=A
time="Sep 25 17:03:21" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0
time="Sep 25 17:11:04" level=trace msg="Received UDP(DNS) 192.168.33.244:58042 <-> 192.168.33.1:53: wq.io. A"
time="Sep 25 17:11:04" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="quic://dns-unfiltered.adguard.com:853"
time="Sep 25 17:11:04" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="quic://dns-unfiltered.adguard.com:853" use="94.140.14.140:853"
time="Sep 25 17:11:06" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="quic://dns-unfiltered.adguard.com:853"
time="Sep 25 17:11:06" level=info msg="192.168.33.244:58042 <-> 94.140.14.140:853" _qname=wq.io. dialer="香港 IEPL [02] [Air]" dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=proxy pid=10400 pname=dig policy=min_moving_avg qtype=A
time="Sep 25 17:11:06" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

DoQ support has been added

EkkoG avatar Sep 25 '24 17:09 EkkoG

Cool!

  • alidns: 'tcp://dns.alidns.com:53' ✅
  • alidns: 'h3://dns.alidns.com' ✅
  • alidns: 'http3://dns.alidns.com' ✅
  • alidns: 'quic://dns.alidns.com' # I remember using it before, not sure why it doesn't work now.
  • alidns: 'tls://dns.alidns.com' ✅
  • adguard: 'quic://dns.adguard.com:784' ✅
  • adguard: 'quic://dns-unfiltered.adguard.com' ✅

douglarek avatar Sep 26 '24 03:09 douglarek

@douglarek DoQ should work with alidns now

EkkoG avatar Sep 26 '24 05:09 EkkoG

dae version unstable-20240926.pr-649.r17.bc5204 x86_64

Doh upstream https://cloudflare-dns.com/dns-query

[Sep 26 03:14:38] WARN handlePkt: Post "https://104.16.248.249:443/dns-query": tls: failed to verify certificate: x509: certificate is valid for 1.0.0.1, 1.1.1.1, 162.159.36.1, 162.159.46.1, 2606:4700:4700::1001, 2606:4700:4700::1111, 2606:4700:4700::64, 2606:4700:4700::6400, not 104.16.248.249

tkszhzy avatar Sep 26 '24 07:09 tkszhzy

@tkszhzy Please run curl -v https://cloudflare-dns.com/dns-query on your computer and upload the outputs

MarksonHon avatar Sep 26 '24 07:09 MarksonHon

@tkszhzy Please run curl -v https://cloudflare-dns.com/dns-query on your computer and upload the outputs

root@debian:~# curl -v https://cloudflare-dns.com/dns-query

  • Trying 104.16.248.249:443...
  • Connected to cloudflare-dns.com (104.16.248.249) port 443 (#0)
  • ALPN: offers h2,http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • CAfile: /etc/ssl/certs/ca-certificates.crt
  • CApath: /etc/ssl/certs
  • 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: Jul 30 00:00:00 2024 GMT
  • expire date: Jan 21 23:59:59 2025 GMT
  • subjectAltName: host "cloudflare-dns.com" matched cert's "cloudflare-dns.com"
  • issuer: C=US; O=DigiCert Inc; CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1
  • SSL certificate verify ok.
  • using HTTP/2
  • h2h3 [:method: GET]
  • h2h3 [:path: /dns-query]
  • h2h3 [:scheme: https]
  • h2h3 [:authority: cloudflare-dns.com]
  • h2h3 [user-agent: curl/7.88.1]
  • h2h3 [accept: /]
  • Using Stream ID: 1 (easy handle 0x55af1632cce0)

GET /dns-query HTTP/2 Host: cloudflare-dns.com user-agent: curl/7.88.1 accept: /

  • 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 < server: cloudflare < date: Thu, 26 Sep 2024 08:18:58 GMT < access-control-allow-origin: * < cf-ray: 8c91d38aeac0d1f5-ICN <
  • Connection #0 to host cloudflare-dns.com left intact

tkszhzy avatar Sep 26 '24 08:09 tkszhzy

by dns testing tool:

root@debian:~# dnslookup www.yahoo.com https://cloudflare-dns.com/dns-query dnslookup master Server: https://cloudflare-dns.com/dns-query

dnslookup result (elapsed 238.519706ms): ;; opcode: QUERY, status: NOERROR, id: 34483 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION: ;www.yahoo.com. IN A

;; ANSWER SECTION: www.yahoo.com. 39 IN CNAME me-ycpi-cf-www.g06.yahoodns.net. me-ycpi-cf-www.g06.yahoodns.net. 39 IN A 180.222.106.12 me-ycpi-cf-www.g06.yahoodns.net. 39 IN A 180.222.106.11 me-ycpi-cf-www.g06.yahoodns.net. 39 IN A 180.222.109.252 me-ycpi-cf-www.g06.yahoodns.net. 39 IN A 180.222.109.251

tkszhzy avatar Sep 26 '24 08:09 tkszhzy

dae version unstable-20240926.pr-649.r17.bc5204 x86_64

Doh upstream https://cloudflare-dns.com/dns-query

[Sep 26 03:14:38] WARN handlePkt: Post "https://104.16.248.249:443/dns-query": tls: failed to verify certificate: x509: certificate is valid for 1.0.0.1, 1.1.1.1, 162.159.36.1, 162.159.46.1, 2606:4700:4700::1001, 2606:4700:4700::1111, 2606:4700:4700::64, 2606:4700:4700::6400, not 104.16.248.249

This is because current DoH request not set the SNI, 104.16.248.249 is not just host DNS server, and CloudFlare does not provide a valid IP cert for this IP, so the cert check is fail, you can use IP URL like https://1.1.1.1/dns-query to avoid this issue.

Also I have fix the issue, you can keep this usage.

For this case and user who want use a self-host DoH server and user can get a IP certificate, set SNI is required.

When SNI and HTTP host is mismatch, Cloudflare will return a 403

echo -n 'q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | base64 --decode | curl --header 'content-type: application/dns-message' --header 'Host: 1.1.1.1' --data-binary @- https://one.one.one.one/dns-query -v -4
*   Trying 1.0.0.1:443...
* Connected to one.one.one.one (1.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* 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 to use h2
* Server certificate:
*  subject: CN=one.one.one
*  start date: Jul 30 03:28:47 2024 GMT
*  expire date: Oct 28 03:28:46 2024 GMT
*  subjectAltName: host "one.one.one.one" matched cert's "*.one.one.one"
*  issuer: C=US; O=Google Trust Services; CN=WE1
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55a39ec621c0)
> POST /dns-query HTTP/2
> Host: 1.1.1.1
> user-agent: curl/7.74.0
> accept: */*
> content-type: application/dns-message
> content-length: 33
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
* We are completely uploaded and fine
< HTTP/2 403 
< server: cloudflare
< date: Thu, 26 Sep 2024 09:47:20 GMT
< content-type: text/html
< content-length: 151
< cf-ray: 8c9254fd5f67ce0d-SIN
< 
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
* Connection #0 to host one.one.one.one left intact
echo -n 'q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | base64 --decode | curl --header 'content-type: application/dns-message' --data-binary @- https://one.one.one.one/dns-query -v -4 --output - | hexdump
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 1.0.0.1:443...
* Connected to one.one.one.one (1.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [19 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2528 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [79 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=one.one.one
*  start date: Jul 30 03:28:47 2024 GMT
*  expire date: Oct 28 03:28:46 2024 GMT
*  subjectAltName: host "one.one.one.one" matched cert's "*.one.one.one"
*  issuer: C=US; O=Google Trust Services; CN=WE1
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* Using Stream ID: 1 (easy handle 0x55812b3cf1c0)
} [5 bytes data]
> POST /dns-query HTTP/2
> Host: one.one.one.one
> user-agent: curl/7.74.0
> accept: */*
> content-type: application/dns-message
> content-length: 33
> 
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [238 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [238 bytes data]
* old SSL session ID is stale, removing
{ [5 bytes data]
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
} [5 bytes data]
* We are completely uploaded and fine
{ [5 bytes data]
< HTTP/2 200 
< server: cloudflare
< date: Thu, 26 Sep 2024 09:55:06 GMT
< content-type: application/dns-message
< access-control-allow-origin: *
< content-length: 49
< cf-ray: 8c92605f2c864c95-SIN
< alt-svc: h3=":443"; ma=86400
< 
{ [5 bytes data]
100    82  100    49  100    33   1814   1222 --:--:-- --:--:-- --:--:--  3153
* Connection #0 to host one.one.one.one left intact
0000000 cdab 8081 0100 0100 0000 0000 7703 7777
0000010 6507 6178 706d 656c 6303 6d6f 0000 0001
0000020 c001 000c 0001 0001 0400 00bb 5d04 d7b8
0000030 000e                                   
0000031

And for AliDNS, it return 200

echo -n 'q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | base64 --decode | curl --header 'content-type: application/dns-message' --header 'Host: 223.5.5.5' --data-binary @- https://dns.alidns.com/dns-query -v -4 --output - | hexdump
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 223.5.5.5:443...
* Connected to dns.alidns.com (223.5.5.5) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [15 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2238 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [78 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=CN; ST=\U6D59\U6C5F\U7701; L=\U676D\U5DDE\U5E02; O=\U963F\U91CC\U5DF4\U5DF4\UFF08\U4E2D\U56FD\UFF09\U7F51\U7EDC\U6280\U672F\U6709\U9650\U516C\U53F8; CN=*.alidns.com
*  start date: Jan  5 06:41:06 2024 GMT
*  expire date: Feb  5 06:41:05 2025 GMT
*  subjectAltName: host "dns.alidns.com" matched cert's "*.alidns.com"
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign ECC OV SSL CA 2018
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* Using Stream ID: 1 (easy handle 0x55b8e1dc6820)
} [5 bytes data]
> POST /dns-query HTTP/2
> Host: 223.5.5.5
> user-agent: curl/7.74.0
> accept: */*
> content-type: application/dns-message
> content-length: 33
> 
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [130 bytes data]
* We are completely uploaded and fine
{ [5 bytes data]
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
} [5 bytes data]
< HTTP/2 200 
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
< cache-control: max-age=1.000000
< content-type: application/dns-message
< content-length: 64
< date: Thu, 26 Sep 2024 09:56:27 GMT
< 
{ [5 bytes data]
100    97  100    64  100    33    659    340 --:--:-- --:--:-- --:--:--  1000
* Connection #0 to host dns.alidns.com left intact
0000000 cdab 0081 0100 0100 0000 0000 7703 7777
0000010 6507 6178 706d 656c 6303 6d6f 0000 0001
0000020 0301 7777 0777 7865 6d61 6c70 0365 6f63
0000030 006d 0100 0100 0000 0100 0400 b85d 0ed7
0000040

So we also need to keep the SNI and HTTP host same, also keep them same is best, so I implement it. You can try the latest build.

Feel free to report any issues or feedback.

EkkoG avatar Sep 26 '24 10:09 EkkoG

So we also need to keep the SNI and HTTP host same, also keep them same is best, so I implement it. You can try the latest build.

Feel free to report any issues or feedback.

Latest build is cool .

Thanks to all of dae team !

tkszhzy avatar Sep 26 '24 10:09 tkszhzy

ODoH is too hard to find a proxy server, I give up to implement it, for guys who interest in DNS protocol like ODoH or DNS protocol has similar approach, you can have a look at https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/relays.md , it has more relay server available.

EkkoG avatar Sep 27 '24 02:09 EkkoG

https://one.one.one.one

time="Sep 27 14:58:00" level=trace msg="Received UDP(DNS) 192.168.33.244:41194 <-> 192.168.33.1:53: wq.io. A"
time="Sep 27 14:58:00" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="https://one.one.one.one:443/dns-query"
time="Sep 27 14:58:00" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4 6] l4protos=[tcp] upstream="https://one.one.one.one:443/dns-query" use="1.0.0.1:443"
time="Sep 27 14:58:00" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="https://one.one.one.one:443/dns-query"
time="Sep 27 14:58:00" level=info msg="192.168.33.244:41194 <-> 1.0.0.1:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=26995 pname=dig policy=fixed qtype=A
time="Sep 27 14:58:00" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

https://one.one.one.one/dns-query

time="Sep 27 14:59:09" level=trace msg="Received UDP(DNS) 192.168.33.244:60963 <-> 192.168.33.1:53: wq.io. A"
time="Sep 27 14:59:09" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="https://one.one.one.one:443/dns-query"
time="Sep 27 14:59:09" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4 6] l4protos=[tcp] upstream="https://one.one.one.one:443/dns-query" use="1.0.0.1:443"
time="Sep 27 14:59:09" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="https://one.one.one.one:443/dns-query"
time="Sep 27 14:59:09" level=info msg="192.168.33.244:60963 <-> 1.0.0.1:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=27283 pname=dig policy=fixed qtype=A
time="Sep 27 14:59:09" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

https://dns.vlo.cc/jiu/acer

time="Sep 27 15:00:37" level=trace msg="Received UDP(DNS) 192.168.33.244:42147 <-> 192.168.33.1:53: westus-0.in.applicationinsights.azure.com. A"
time="Sep 27 15:00:37" level=trace msg="Request to DNS upstream" question=[{westus-0.in.applicationinsights.azure.com. 1 1}] upstream="https://dns.vlo.cc:443/jiu/acer"
time="Sep 27 15:00:37" level=trace msg="Choose DNS path" choose="tcp+4" ipversions=[4] l4protos=[tcp] upstream="https://dns.vlo.cc:443/jiu/acer" use="42.51.21.57:443"
time="Sep 27 15:00:37" level=trace msg=Accept question=[{westus-0.in.applicationinsights.azure.com. 1 1}] upstream="https://dns.vlo.cc:443/jiu/acer"
time="Sep 27 15:00:37" level=info msg="192.168.33.244:42147 <-> 42.51.21.57:443" _qname=westus-0.in.applicationinsights.azure.com. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="tcp4(DNS)" outbound=direct pid=7768 pname=node policy=fixed qtype=A
time="Sep 27 15:00:37" level=trace msg="Update DNS record cache" _qname=westus-0.in.applicationinsights.azure.com. ans="westus-0.in.applicationinsights.azure.com.(A): 127.0.0.1" rcode=0

h3://dns.alidns.com

time="Sep 27 15:02:34" level=trace msg="Received UDP(DNS) 192.168.33.244:44467 <-> 192.168.33.1:53: wq.io. A"
time="Sep 27 15:02:34" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443/dns-query"
time="Sep 27 15:02:34" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="h3://dns.alidns.com:443/dns-query" use="223.5.5.5:443"
time="Sep 27 15:02:35" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443/dns-query"
time="Sep 27 15:02:35" level=info msg="192.168.33.244:44467 <-> 223.5.5.5:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=direct pid=27852 pname=dig policy=fixed qtype=A
time="Sep 27 15:02:35" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

h3://dns.alidns.com/dns-query

time="Sep 27 15:03:18" level=trace msg="Received UDP(DNS) 192.168.33.244:48868 <-> 192.168.33.1:53: wq.io. A"
time="Sep 27 15:03:18" level=trace msg="Request to DNS upstream" question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443/dns-query"
time="Sep 27 15:03:18" level=trace msg="Choose DNS path" choose="udp+4" ipversions=[4 6] l4protos=[udp] upstream="h3://dns.alidns.com:443/dns-query" use="223.5.5.5:443"
time="Sep 27 15:03:20" level=trace msg=Accept question=[{wq.io. 1 1}] upstream="h3://dns.alidns.com:443/dns-query"
time="Sep 27 15:03:20" level=info msg="192.168.33.244:48868 <-> 223.5.5.5:443" _qname=wq.io. dialer=direct dscp=0 mac="08:00:27:95:8e:32" network="udp4(DNS)" outbound=direct pid=27996 pname=dig policy=fixed qtype=A
time="Sep 27 15:03:20" level=trace msg="Update DNS record cache" _qname=wq.io. ans="wq.io.(A): 107.170.234.66" rcode=0

DoH/DoH3 custom url path has supported.

EkkoG avatar Sep 27 '24 15:09 EkkoG

关于 dns.google.com 作为域名服务器的问题

这个域名 Google 应该是不想作为 DNS 服务器来用的,顶多用来展示自己的网站用的,算是一个别名

浏览器打开 https://dns.google.com/ 是重定向的到 https://dns.google/ 的

一个合法的 GET 请求也是重定向的

curl -v -L https://dns.google.com/dns-query\?dns\=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ > /dev/null 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Host dns.google.com:443 was resolved.
* IPv6: 2001:4860:4860::8888, 2001:4860:4860::8844
* IPv4: 8.8.8.8, 8.8.4.4
*   Trying [2001:4860:4860::8888]:443...
* Connected to dns.google.com (2001:4860:4860::8888) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
} [319 bytes data]
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* (304) (IN), TLS handshake, Unknown (8):
{ [15 bytes data]
* (304) (IN), TLS handshake, Certificate (11):
{ [3957 bytes data]
* (304) (IN), TLS handshake, CERT verify (15):
{ [78 bytes data]
* (304) (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* (304) (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=dns.google
*  start date: Aug 26 07:16:10 2024 GMT
*  expire date: Nov 18 07:16:09 2024 GMT
*  subjectAltName: host "dns.google.com" matched cert's "dns.google.com"
*  issuer: C=US; O=Google Trust Services; CN=WR2
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://dns.google.com/dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: dns.google.com]
* [HTTP/2] [1] [:path: /dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
> GET /dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ HTTP/2
> Host: dns.google.com
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/2 301 
< location: https://dns.google/dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ
< strict-transport-security: max-age=31536000
< x-content-type-options: nosniff
< server: sffe
< content-length: 292
< x-xss-protection: 0
< date: Fri, 27 Sep 2024 15:43:21 GMT
< expires: Fri, 27 Sep 2024 16:13:21 GMT
< cache-control: public, max-age=1800
< content-type: text/html; charset=UTF-8
< age: 8
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
< 
* Ignoring the response-body
100   292  100   292    0     0   5417      0 --:--:-- --:--:-- --:--:--  5509
* Connection #0 to host dns.google.com left intact
* Issue another request to this URL: 'https://dns.google/dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ'
* Host dns.google:443 was resolved.
* IPv6: 2001:4860:4860::8844, 2001:4860:4860::8888
* IPv4: 8.8.4.4, 8.8.8.8
*   Trying [2001:4860:4860::8844]:443...
* Connected to dns.google (2001:4860:4860::8844) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
} [315 bytes data]
* (304) (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* (304) (IN), TLS handshake, Unknown (8):
{ [15 bytes data]
* (304) (IN), TLS handshake, Certificate (11):
{ [3957 bytes data]
* (304) (IN), TLS handshake, CERT verify (15):
{ [78 bytes data]
* (304) (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* (304) (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=dns.google
*  start date: Aug 26 07:16:10 2024 GMT
*  expire date: Nov 18 07:16:09 2024 GMT
*  subjectAltName: host "dns.google" matched cert's "dns.google"
*  issuer: C=US; O=Google Trust Services; CN=WR2
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://dns.google/dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: dns.google]
* [HTTP/2] [1] [:path: /dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
> GET /dns-query?dns=wgEBIAABAAAAAAABAndxAmlvAAABAAEAACkE0AAAAAAADAAKAAgZQlXAovOmeQ HTTP/2
> Host: dns.google
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/2 200 
< x-content-type-options: nosniff
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< access-control-allow-origin: *
< date: Fri, 27 Sep 2024 15:43:29 GMT
< expires: Fri, 27 Sep 2024 15:43:29 GMT
< cache-control: private, max-age=1131
< content-type: application/dns-message
< server: HTTP server (unknown)
< content-length: 50
< x-xss-protection: 0
< x-frame-options: SAMEORIGIN
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
< 
{ [50 bytes data]
100    50  100    50    0     0    467      0 --:--:-- --:--:-- --:--:--   467
* Connection #1 to host dns.google left intact

POST 请求通常不重定向,因为有歧义,所以返回了一个 400 q --http-method=POST @https://dns.google.com/dns-query wq.io FATA[0001] got status code 404 from https://dns.google.com:443/dns-query

所以我认为这个域名不应该作为一个 DNS 服务器来用,即使强行做了兼容,让重定向请求可以正常发出去,整个 DNS 请求过程其实是发了两次 HTTP 请求的,对于 DNS 这种对延时敏感的场景,我觉得这应该是不想看到的事情

综上,我觉不应该兼容这种场景,应该报错

EkkoG avatar Sep 27 '24 15:09 EkkoG

Thanks for your awesome work!

mzz2017 avatar Nov 01 '24 16:11 mzz2017