radioactiveAHM/DnsSafeguard

DoH server (ECH) issues

Closed this issue · 16 comments

I'm not really sure what I did wrong

❯ openssl ecparam -genkey -name prime256v1 -out key.pem

❯ openssl req -new -x509 -days 36500 -key key.pem -out cert.pem -config san.cnf

❯ certutil -addstore -enterprise -f CA cert.pem
CA "Intermediate Certification Authorities"
Signature matches Public Key
Certificate "WR2" added to store.
CertUtil: -addstore command completed successfully.

❯ DnsSafeguard
DNS cache cleared
DoH server Listening on 127.0.0.1:443
QUIC Connecting
QUIC Connecting
QUIC Connection Established
QUIC Connection Established
DoH server: received fatal alert: CertificateUnknown

Raw access seems to work though

❯ DnsSafeguard
DNS cache cleared
DoH server Listening on 127.0.0.1:443
QUIC Connecting
QUIC Connecting
QUIC Connection Established
QUIC Connection Established
DoH server: tls handshake eof
DoH server: received fatal alert: UnknownCA
QUIC Connecting
connection is closed
QUIC 0RTT Connection Established
DoH server: peer is incompatible: SupportedVersionsExtensionRequired
Test-NetConnection 127.0.0.1 -Port 443

ComputerName     : 127.0.0.1
RemoteAddress    : 127.0.0.1
RemotePort       : 443
InterfaceAlias   : Loopback Pseudo-Interface 1
SourceAddress    : 127.0.0.1
TcpTestSucceeded : True

❯ curl -sSL https://127.0.0.1/dns-query
curl: (60) SSL peer certificate or SSH remote key was not OK
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

❯ Invoke-WebRequest https://127.0.0.1/dns-query
Invoke-WebRequest: Authentication failed because the remote party sent a TLS alert: 'ProtocolVersion'.

Accessing https://127.0.0.1/dns-query in Firefox (security.enterprise_roots.enabled is set to true) results in:

config.json
{
	"protocol": "h3",
	"server_name": "doh3.dns.nextdns.io",
	"custom_http_path": "/redacted",
	"socket_addrs": "45.90.28.0:443",
	"udp_socket_addrs": "127.0.0.1:53",
	"disable_domain_sni": true,
	"fragmenting": {
		"enable": false,
		"method": "single"
	},
	"noise": {
		"enable": false,
		"ntype": "rand",
		"content": "google.com",
		"packet_length": 1,
		"packets": 1,
		"sleep": 1000,
		"continues": false
	},
	"ipv6": {
		"enable": true,
		"protocol": "h3",
		"server_name": "doh3.dns.nextdns.io",
		"custom_http_path": "/redacted",
		"socket_addrs": "[2a07:a8c0::]:443",
		"udp_socket_addrs": "[::1]:53",
		"disable_domain_sni": true,
		"fragmenting": {
			"enable": false,
			"method": "single"
		},
		"noise": {
			"enable": false,
			"ntype": "rand",
			"content": "google.com",
			"packet_length": 1,
			"packets": 3,
			"sleep": 500,
			"continues": false
		}
	},
	"quic": {
		"congestion_controller": "bbr",
		"keep_alive_interval": 5,
		"datagram_receive_buffer_size": 16777216,
		"datagram_send_buffer_size": 8388608,
		"connecting_timeout_sec": 2
	},
	"connection": {
		"h1_multi_connections": 3,
		"dot_nonblocking_dns_query_lifetime": 5,
		"reconnect_sleep": 1,
		"max_reconnect": 5,
		"max_reconnect_sleep": 30
	},
	"doh_server": {
		"enable": true,
		"listen_address": "127.0.0.1:443",
		"certificate": "cert.pem",
		"key": "key.pem",
		"log_errors": true
	},
	"rules": []
}

You have to install a certificate to system so the system can trust.
To install a certificate so the Windows 11 can trust it, follow these steps:

  1. Rename the Certificate File:
    • Rename cert.pem to cert.crt The icon of cert.crt should change.
  2. Install the Certificate:
    • Right-click on cert.crt and select Install Certificate.
    • In the Store Location section, select Local Machine and click Next.
    • Choose Place all certificates in the following store, then click Browse.
    • Select Trusted Root Certification Authorities and click OK.
    • Click Next and complete the wizard.
  3. Verify in Firefox: Try accessing the desired site in Firefox. If it doesn’t work, repeat the installation process but select Third-Party Root Certification Authorities instead of Trusted Root Certification Authorities.
  4. Update DnsSafeguard Configuration: Don’t forget to rename cert.pem to cert.crt in the DnsSafeguard configuration file.

Yea I've tried the Trusted Root Certification Authorities, Intermediate Certificate Authorities, & Third-Party Root Certification Authorities stores, but neither seems to work. Test-NetConnection seems to be the only thing that actually does the tls exchange, but no request clients are working. Chromium doesn't work either.

Try this link https://127.0.0.1/?dns=PhcBAAABAAAAAAAABnZvcnRleARkYXRhCW1pY3Jvc29mdANjb20AAAEAAQ. The browser should save DNS query response as a 59Kb file.

You should use https://127.0.0.1/dns-query{?dns} for browsers and don't miss {?dns} part.

Edit: The {?dns} part indicates that the browser should encode the DNS query to base64url format as an HTTP URL query.

Try this link https://127.0.0.1/?dns=PhcBAAABAAAAAAAABnZvcnRleARkYXRhCW1pY3Jvc29mdANjb20AAAEAAQ. The browser should save DNS query response as a 59Kb file.

Yes, this works.

You should use https://127.0.0.1/dns-query{?dns} for browsers and don't miss {?dns} part.

This doesn't seem to. Setting network.trr.custom_uri & network.trr.uri to https://127.0.0.1/dns-query with or without the trailing dns-query & {?dns} doesn't. Nor does ECH work without the TRR resolver (setting network.trr.mode to 0 or 5), regardless of whether network.dns.native_https_query_win10 is true, or not. Realistically TRR shouldn't need to be enabled (ff 129+).

Using q doesn't seem to work either, but it's error might be more useful.

❯ q google.com '@https://127.0.0.1/'
time="2024-12-03T23:40:53-05:00" level=fatal msg="requesting https://127.0.0.1:443/?dns=zH8BAAABAAAAAAAABmdvb2dsZQNjb20AAA8AAQ: Get \"https://127.0.0.1:443/?dns=zH8BAAABAAAAAAAABmdvb2dsZQNjb20AAA8AAQ\": net/http: HTTP/1.x transport connection broken: malformed HTTP response \"\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\""

❯ q google.com '@https://127.0.0.1/dns-query'
time="2024-12-03T23:40:57-05:00" level=fatal msg="requesting https://127.0.0.1:443/dns-query?dns=NwUBAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ: Get \"https://127.0.0.1:443/dns-query?dns=NwUBAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ\": net/http: HTTP/1.x transport connection broken: malformed HTTP response \"\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\""

❯ q google.com '@https://127.0.0.1/' --http2
time="2024-12-03T23:41:00-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/?dns=ZmcBAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: overflowing header size"

❯ q google.com '@https://127.0.0.1/dns-query' --http2
time="2024-12-03T23:41:05-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/dns-query?dns=nBABAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: buffer size too small"

It seems the issue is related to the HTTP version. Currently, the local DoH server supports only HTTP/2 (H2), while your client is using HTTP/1.1. I’m working on adding support for HTTP/1.1.

The good news is that the link I provided is working, indicating that the local H2 server is functioning correctly and the certificate is trusted. Please wait 1-3 days for me to implement HTTP/1.1 support for the local DoH server.

The bug you’re encountering is actually a client-side issue with your browser. Your browser is sending an H2 ALPN but then using HTTP/1.1.

Also i have to implement the POST method for the DoH server. I'll notify you for testing.

@brian6932 Can you build the app and test?

Getting the same issue on 58226fe HTTP/2. New error for HTTP/1.1.

❯ q google.com '@https://127.0.0.1/'
time="2024-12-05T19:59:52-05:00" level=fatal msg="requesting https://127.0.0.1:443/?dns=qn0BAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ: Get \"https://127.0.0.1:443/?dns=qn0BAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ\": net/http: HTTP/1.x transport connection broken: malformed HTTP status code \"OK\""

❯ q google.com '@https://127.0.0.1/dns-query'
time="2024-12-05T20:00:43-05:00" level=fatal msg="requesting https://127.0.0.1:443/dns-query?dns=p80BAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ: Get \"https://127.0.0.1:443/dns-query?dns=p80BAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ\": net/http: HTTP/1.x transport connection broken: malformed HTTP status code \"OK\""

@brian6932, I fixed the HTTP/1.1 malformed bug and the H2 POST method handling issue. The browser must decide whether to use ECH or not; we can't control that. You might want to check if the normal local DoH is working.

Check the new alpn option in the config file, which indicates the HTTP versions served. The variants are h2 and http/1.1. If you use both like "alpn": ["h2", "http/1.1"], then both versions are served. If you keep having issues with H2, use only http/1.1 like "alpn": ["http/1.1"] if it works better for you.

For me, both H2 and HTTP/1.1 work fine with both Edge and Firefox. However, Edge performs better using the GET method with https://127.0.0.1:443/dns-query{?dns} URL, while Firefox works better with the POST method using https://127.0.0.1:443/dns-query.

edit: Also, ECH works fine with both browsers.

Yes Firefox works now, when setting network.trr.custom_uri & network.trr.uri to https://127.0.0.1.
I unfortunately can't get any to work OOTB, network.trr.mode 0 or 5 with network.dns.native_https_query_win10 true doesn't work for whatever reason (this is possibly currently broken, in the DNSQuery_A API on Windows 10), neither does q, or doge (these 2 don't seem to use the same native resolver).

❯ q google.com '@https://127.0.0.1'
time="2024-12-07T14:59:39-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/dns-query?dns=7t8BAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: overflowing header size"

❯ q google.com '@https://127.0.0.1' --http2
time="2024-12-07T14:59:50-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/dns-query?dns=kdQBAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: overflowing header size"

❯ doge google.com -H '@https://127.0.0.1/'
Error [tls]: The message received was unexpected or badly formatted. (os error -2146893018)
Error [tls]: The message received was unexpected or badly formatted. (os error -2146893018)

I’m not sure what’s causing these issues. For HTTP/1.1, I’m adhering to standards similar to those used by Google and Cloudflare’s public DoH servers. The HTTP response, including headers and body, is sent in a single TCP segment, just like Google and Cloudflare’s public DoH servers. For HTTP/2, responses are managed by the H2 crate, which also follows the standards. There might be some conditions I missed that are causing bugs, so I need to write more tests. Thanks for testing, and I’ll notify you if I need further testing assistance.

@brian6932 This looks fine to me.
Screenshot 2024-12-08 020913

Updated to 2a8d51d, and still getting this, but with a little more detail. Querying A, AAAA, NS, MX, & HTTPS names work fine, but TXT fails. When the command is used without the 3rd arg, it queries all types.

❯ q google.com TXT '@https://127.0.0.1'
time="2024-12-07T17:59:12-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/dns-query?dns=kUsBAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: overflow unpacking uint16"

❯ q google.com TXT '@https://127.0.0.1' --http2
time="2024-12-07T17:59:19-05:00" level=fatal msg="unpacking DNS response from https://127.0.0.1:443/dns-query?dns=ZcYBAAABAAAAAAAABmdvb2dsZQNjb20AABAAAQ: dns: overflowing header size"

❯ q google.com TXT '@https://doh3.dns.nextdns.io'
google.com. 23m43s TXT "MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
google.com. 23m43s TXT "apple-domain-verification=30afIBcvSuDV2PLX"
google.com. 23m43s TXT "cisco-ci-domain-verification=479146de172eb01ddee38b1a455ab9e8bb51542ddd7f1fa298557dfa7b22d963"
google.com. 23m43s TXT "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com. 23m43s TXT "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com. 23m43s TXT "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com. 23m43s TXT "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com. 23m43s TXT "google-site-verification=4ibFUgB-wXLQ_S7vsXVomSTVamuOXBiVAzpR5IZ87D0"
google.com. 23m43s TXT "google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
google.com. 23m43s TXT "google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
google.com. 23m43s TXT "onetrust-domain-verification=de01ed21f2fa4d8781cbc3ffb89cf4ef"
google.com. 23m43s TXT "v=spf1 include:_spf.google.com ~all"

❯ q google.com TXT '@https://doh3.dns.nextdns.io' --http2
google.com. 23m33s TXT "MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
google.com. 23m33s TXT "apple-domain-verification=30afIBcvSuDV2PLX"
google.com. 23m33s TXT "cisco-ci-domain-verification=479146de172eb01ddee38b1a455ab9e8bb51542ddd7f1fa298557dfa7b22d963"
google.com. 23m33s TXT "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com. 23m33s TXT "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com. 23m33s TXT "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com. 23m33s TXT "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com. 23m33s TXT "google-site-verification=4ibFUgB-wXLQ_S7vsXVomSTVamuOXBiVAzpR5IZ87D0"
google.com. 23m33s TXT "google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
google.com. 23m33s TXT "google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
google.com. 23m33s TXT "onetrust-domain-verification=de01ed21f2fa4d8781cbc3ffb89cf4ef"
google.com. 23m33s TXT "v=spf1 include:_spf.google.com ~all"

@brian6932, I fixed the bug. The issue was that I initially thought the DNS query max size was 512 bytes for both request and response, but the response can actually be up to 4096 bytes. So, I changed the buffer size for all protocols, and the q app is now working well. Thanks for testing; I couldn't have figured it out without you.

I am still getting the issue above with doge, but the error's too vague for me to really tell anything from it. It's likely just lacking support for self-signed certs.