Skip to content

DNS

dae will intercept all UDP traffic to port 53 and sniff DNS. Here gives some examples and templates for DNS configuration.

Schema

DoH3

h3://<host>:<port>/<path>
http3://<host>:<port>/<path>

default port: 443
default path: /dns-query

DoH

https://<host>:<port>/<path>

default port: 443
default path: /dns-query

DoT

tls://<host>:<port>

default port: 853

DoQ

quic://<host>:<port>

default port: 853

UDP

udp://<host>:<port>

default port: 53

TCP

tcp://<host>:<port>

default port: 53

TCP and UDP

tcp+udp://<host>:<port>

default port: 53

Examples

Complete reference example
shell
dns {
    # For example, if ipversion_prefer is 4 and the domain name has both type A and type AAAA records, the dae will only
    # respond to type A queries and response empty answer to type AAAA queries.
    ipversion_prefer: 4

    # Give a fixed ttl for domains. Zero means that dae will request to upstream every time and not cache DNS results
    # for these domains.
    fixed_domain_ttl {
        ddns.example.org: 10
        test.example.org: 3600
    }

    # Bind to local address to listen for DNS queries
    #bind: '127.0.0.1:5353'

    upstream {
        # Scheme list: tcp, udp, tcp+udp, https, tls, http3, h3, quic, details see above Schema.
        # If host is a domain and has both IPv4 and IPv6 record, dae will automatically choose
        # IPv4 or IPv6 to use according to group policy (such as min latency policy).
        # Please make sure DNS traffic will go through and be forwarded by dae, which is REQUIRED for domain routing.
        # If dial_mode is "ip", the upstream DNS answer SHOULD NOT be polluted, so domestic public DNS is not recommended.

        alidns: 'udp://dns.alidns.com:53'
        googledns: 'tcp+udp://dns.google:53'

        # alih3: 'h3://dns.alidns.com:443'
        # alih3_path: 'h3://dns.alidns.com:443/dns-query'
        # alihttp3: 'http3://dns.alidns.com:443'
        # alihttp3_path: 'http3://dns.alidns.com:443/dns-query'
        # ali_quic: 'quic://dns.alidns.com:853'

        # h3_custom_path: 'h3://dns.example.com:443/custom-path'
        # http3_custom_path: 'http3://dns.example.com:443/custom-path'

        # ali_doh: 'https://dns.alidns.com:443'
        # ali_dot: 'tls://dns.alidns.com:853'

        # doh_custom_path: 'https://dns.example.com:443/custom-path'
    }
    # The routing format of 'request' and 'response' is similar with section 'routing'.
    # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md
    routing {
        # According to the request of dns query, decide to use which DNS upstream.
        # Match rules from top to bottom.
        request {
            # Built-in outbounds in 'request': asis, reject.
            # You can also use user-defined upstreams.

            # Available functions for ordinary DNS requests: qname, qtype.
            # Additional internal dae selectors in the same block: sub, node, subnode.
            # - sub(): subscription fetch requests
            # - node(): node host resolution requests
            # - subnode(): node host resolution requests for subscription-derived nodes
            #   and it is checked before node()
            # Internal selectors:
            # - only affect dae's own DNS lookups
            # - must target names defined in dns.upstream
            # - do not use fallback
            # - cannot be mixed with qname/qtype in the same rule

            # DNS request name (omit suffix dot '.').
            qname(geosite:category-ads-all) -> reject
            qname(geosite:google@cn) -> alidns # Also see: https://github.com/v2fly/domain-list-community#attributes
            qname(suffix: abc.com, keyword: google) -> googledns
            qname(full: ok.com, regex: '^yes') -> googledns
            # DNS request type
            qtype(a, aaaa) -> alidns
            qtype(cname) -> googledns
            # disable ECH to avoid affecting traffic split
            qtype(https) -> reject

            # Route dae's own subscription fetch DNS to googledns.
            # sub(my_sub) -> googledns
            # Route all nodes with "hk" in their name to googledns.
            # node(name_keyword: hk) -> googledns
            # Use alidns for nodes from subscription "my_sub" before node() rules are checked.
            # subnode(subtag: my_sub) -> alidns

            # If no match, fallback to this upstream.
            fallback: asis
        }
        # According to the response of dns query, decide to accept or re-lookup using another DNS upstream.
        # Match rules from top to bottom.
        response {
            # Built-in outbounds in 'response': accept, reject.
            # You can use user-defined upstreams.

            # Available functions: qname, qtype, upstream, ip.
            # Accept the response if the request is sent to upstream 'googledns'. This is useful to avoid loop.
            upstream(googledns) -> accept
            # If DNS request name is not in CN and response answers include private IP, which is most likely polluted
            # in China mainland. Therefore, resend DNS request to 'googledns' to get correct result.
            ip(geoip:private) && !qname(geosite:cn) -> googledns
            fallback: accept
        }
    }

}

Templates

Choose a template for the required DNS behavior.

shell
# Use alidns for China mainland domains and googledns for others.
dns {
  upstream {
    googledns: 'tcp+udp://dns.google:53'
    alidns: 'udp://dns.alidns.com:53'
  }
  routing {
    # According to the request of dns query, decide to use which DNS upstream.
    # Match rules from top to bottom.
    request {
      # Lookup China mainland domains using alidns, otherwise googledns.
      qname(geosite:cn) -> alidns
      # fallback is also called default.
      fallback: googledns
    }
  }
}
shell
# Use alidns for all DNS queries and fallback to googledns if pollution result detected.
dns {
  upstream {
    googledns: 'tcp+udp://dns.google:53'
    alidns: 'udp://dns.alidns.com:53'
  }
  routing {
    # According to the request of dns query, decide to use which DNS upstream.
    # Match rules from top to bottom.
    request {
      # fallback is also called default.
      fallback: alidns
    }
    # According to the response of dns query, decide to accept or re-lookup using another DNS upstream.
    # Match rules from top to bottom.
    response {
      # Trusted upstream. Always accept its result.
      upstream(googledns) -> accept
      # Possibly polluted, re-lookup using googledns.
      ip(geoip:private) && !qname(geosite:cn) -> googledns
      # fallback is also called default.
      fallback: accept
    }
  }
}

Source: dae upstream · AGPL-3.0 license.