DNS over QUIC and DNS over HTTP3 for transparent and local-in DNS modes
DNS over QUIC (DoQ) and DNS over HTTP3 (DoH3) are supported in proxy mode inspection for transparent and local-in explicit modes. With DoQ and DoH3, connections can be established faster than with DNS over TLS (DoT) or DNS over HTTPS (DoH). The FortiGate can also handle the QUIC/TLS handshake and perform deep inspection for HTTP3 and QUIC traffic. This allows for faster and more secure DNS resolution, with improved privacy and reduced latency.
In transparent mode, the FortiGate is acting as a proxy, forwarding DNS queries, and not as a DNS server. In local-in DNS mode, the FortiGate acts as the DNS server and a DNS filter profile is applied in the system DNS server.
The firewall policy must be in proxy mode.
DoQ transparent and local-in query can be achieved using tools or applications in Linux, such as the q tiny command line DNS client from Natesales.
DoH3 transparent and local-in query can be achieved in Linux using q or Curl. In Windows, change the client network DNS server to the FortiGate and treat the FortiGate as an HTTP3 DNS server listening for DoH3 connections.
To enable QUIC in SSL/SSH inspection profiles in the GUI:
-
Go to Security Profiles > SSL/SSH Inspection and click Create New.
-
Under Protocol Port Mapping, set HTTP/3 and DNS over QUIC to Inspect.
-
Configure the remaining settings as required.
-
Click OK.
To configure DoQ in transparent mode in the CLI:
-
Enable QUIC in the ssl-ssh-profile:
config firewall ssl-ssh-profile edit "protocols" config dot set status deep-inspection set quic inspect end next end
-
Configure a DNS filter profile:
config dnsfilter profile edit "dnsfilter_fgd" config ftgd-dns config filters edit 1 set category 30 set action block next end end next end
-
Apply the profiles to a proxy firewall policy:
config firewall policy edit 1 set name "dnsfilter" set srcintf "port2" set dstintf "port1" set action accept set srcaddr "all" set dstaddr "all" set schedule "always" set service "ALL" set utm-status enable set inspection-mode proxy set profile-protocol-options "protocol" set ssl-ssh-profile "protocols" set dnsfilter-profile "dnsfilter_fgd" set logtraffic all set nat enable next end
-
Test the configuration:
On the client, use q to query a FortiGuard category30 domain with the Adguard DNS server over QUIC. The default redirect block IP address should be returned:
pc03:~# q www.sfu.ca @quic://dns.adguard.com --tls-no-verify 2023/08/18 18:53:44 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details. www.sfu.ca. 1m0s A 208.91.112.55 www.sfu.ca. 1m0s AAAA 2620:101:9000:53::55
To enable DNS over HTTP3 or DNS over QUIC on the DNS server in the GUI:
-
Go to Network > DNS Servers.
If this option is not available, go to System > Feature Visibility and enable DNS Database.
-
In the DNS Service on Interface section, edit an existing interface, or create a new one.
-
Set the Mode option as desired.
-
Enable DNS Filter and select a profile.
-
Enable DNS over HTTP3 or DNS over QUIC.
-
Click OK.
To configure DoQ in local-in mode in the CLI:
-
In the FortiGate DNS server configuration, enable DoQ for a port with the previously configured DNS filter profile applied:
config system dns-server edit "port2" set dnsfilter-profile "dnsfilter_fgd" set doq enable next end
-
Test the configuration:
On the client, use q to query a FortiGuard category30 domain with the FortiGate interface over QUIC. The default redirect block IP address should be returned:
pc03:~# q www.mcgill.ca @quic://10.1.100.150 --tls-no-verify 2023/08/18 20:05:53 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details. www.mcgill.ca. 1m0s A 208.91.112.55 www.mcgill.ca. 1m0s AAAA 2620:101:9000:53::55
To configure DoH3 in transparent mode in the CLI:
-
Enable QUIC in the ssl-ssh-profile:
config firewall ssl-ssh-profile edit "protocols" config https set ports 443 8443 set status deep-inspection set quic inspect end next end
-
Configure a DNS filter profile:
config dnsfilter profile edit "dnsfilter_fgd" config ftgd-dns config filters edit 1 set category 30 set action block next end end next end
-
Apply the profiles to a proxy firewall policy:
config firewall policy edit 1 set name "dnsfilter" set srcintf "port2" set dstintf "port1" set action accept set srcaddr "all" set dstaddr "all" set schedule "always" set service "ALL" set utm-status enable set inspection-mode proxy set profile-protocol-options "protocol" set ssl-ssh-profile "protocols" set dnsfilter-profile "dnsfilter_fgd" set logtraffic all set nat enable next end
-
Test the configuration:
On the client with HTTP3 support, use q or Curl to query a FortiGuard category30 domain with the Adguard DNS server or Cloudflare DNS server over QUIC. The default redirect block IP address should be returned:
pc03:~# q www.mcgill.ca --http3 @https://dns.adguard.com --tls-no-verify 2023/08/18 21:04:02 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details. www.mcgill.ca. 1m0s A 208.91.112.55 www.mcgill.ca. 1m0s AAAA 2620:101:9000:53::55
pc03:~# curl -H 'accept: application/dns-message' -v -k --http3 'https://1.1.1.1/dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ' | hexdump * Trying 1.1.1.1:443... * Connect socket 5 over QUIC to 1.1.1.1:443 * Sent QUIC client Initial, ALPN: h3,h3-29,h3-28,h3-27 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 1.1.1.1 (1.1.1.1) port 443 (#0) * h3 [:method: GET] * h3 [:path: /dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ] * h3 [:scheme: https] * h3 [:authority: 1.1.1.1] * h3 [user-agent: curl/7.80.0-DEV] * h3 [accept: application/dns-message] * Using HTTP/3 Stream ID: 0 (easy handle 0x558fdd1c2220) > GET /dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ HTTP/3 > Host: 1.1.1.1 > user-agent: curl/7.80.0-DEV > accept: application/dns-message > < HTTP/3 200 < content-type: application/dns-message < content-length: 44 < { [44 bytes data] 100 44 100 44 0 0 1305 0 --:--:-- --:--:-- --:--:-- 1375 * Connection #0 to host 1.1.1.1 left intact 0000000 cdab 0081 0100 0100 0000 0000 7703 7777 0000010 7503 6362 6302 0061 0100 0100 0cc0 0100 0000020 0100 0000 3c00 0400 5bd0 3770 000002c
To configure DoH3 in local-in mode in the CLI:
-
In the FortiGate DNS server configuration, enable DoH3 for a port with the previously configured DNS filter profile applied:
config system dns-server edit "port2" set dnsfilter-profile "dnsfilter_fgd" set doh3 enable next end
-
Test the configuration:
On the client with HTTP3 support, use q or Curl to query a FortiGuard category30 domain with the FortiGate interface over HTTP3. The default redirect block IP address should be returned:
pc03:~# q www.mcgill.ca --http3 @https://10.1.100.150 --tls-no-verify 2023/08/18 20:37:55 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details. www.mcgill.ca. 1m0s A 208.91.112.55 www.mcgill.ca. 1m0s AAAA 2620:101:9000:53::55
pc03:~# curl -H 'accept: application/dns-message' -v -k --http3 'https://10.1.100.150/dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ' | hexdump * Trying 10.1.100.150:443... * Connect socket 5 over QUIC to 10.1.100.150:443 * Sent QUIC client Initial, ALPN: h3,h3-29,h3-28,h3-27 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 10.1.100.150 (10.1.100.150) port 443 (#0) * h3 [:method: GET] * h3 [:path: /dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ] * h3 [:scheme: https] * h3 [:authority: 10.1.100.150] * h3 [user-agent: curl/7.80.0-DEV] * h3 [accept: application/dns-message] * Using HTTP/3 Stream ID: 0 (easy handle 0x55ced8274250) > GET /dns-query?dns=q80BAAABAAAAAAAAA3d3dwN1YmMCY2EAAAEAAQ HTTP/3 > Host: 10.1.100.150 > user-agent: curl/7.80.0-DEV > accept: application/dns-message > < HTTP/3 200 < content-type: application/dns-message < content-length: 44 < { [44 bytes data] 100 44 100 44 0 0 1893 0 --:--:-- --:--:-- --:--:-- 2000 * Connection #0 to host 10.1.100.150 left intact 0000000 cdab 0081 0100 0100 0000 0000 7703 7777 0000010 7503 6362 6302 0061 0100 0100 0cc0 0100 0000020 0100 0000 3c00 0400 5bd0 3770 000002c