Fortinet black logo

Administration Guide

DNS over QUIC and DNS over HTTP3 for transparent and local-in DNS modes

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 a HTTP3 DNS server listening for DoH3 connections.

To configure DoQ in transparent mode:
  1. 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
  2. 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
  3. 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
  4. 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 configure DoQ in local-in mode:
  1. 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
  2. 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:
  1. 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
  2. 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
  3. 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
  4. 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:
  1. 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
  2. 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

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 a HTTP3 DNS server listening for DoH3 connections.

To configure DoQ in transparent mode:
  1. 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
  2. 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
  3. 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
  4. 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 configure DoQ in local-in mode:
  1. 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
  2. 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:
  1. 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
  2. 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
  3. 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
  4. 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:
  1. 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
  2. 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