# https://github.com/daeuniverse/dae/discussions/81 # https://github.com/daeuniverse/dae/blob/main/example.dae # load all dae files placed in ./config.d/ include { config.d/*.dae } global { ##### Software options. # tproxy port to listen on. It is NOT a HTTP/SOCKS port, and is just used by eBPF program. # In normal case, you do not need to use it. tproxy_port: 12345 # Set it true to protect tproxy port from unsolicited traffic. Set it false to allow users to use self-managed # iptables tproxy rules. tproxy_port_protect: true # If not zero, traffic sent from dae will be set SO_MARK. It is useful to avoid traffic loop with iptables tproxy # rules. so_mark_from_dae: 1 # Log level: error, warn, info, debug, trace. log_level: info # Disable waiting for network before pulling subscriptions. disable_waiting_network: false ##### Interface and kernel options. # The LAN interface to bind. Use it if you want to proxy LAN. # Multiple interfaces split by ",". lan_interface: br-lan # The WAN interface to bind. Use it if you want to proxy localhost. # Multiple interfaces split by ",". Use "auto" to auto detect. # # Disable this to avoid problems with the proxy server that prevent the subscription link from being updated # wan_interface: auto # Automatically configure Linux kernel parameters like ip_forward and send_redirects. Check out # https://github.com/daeuniverse/dae/blob/main/docs/en/user-guide/kernel-parameters.md to see what will dae do. auto_config_kernel_parameter: false ##### Node connectivity check. # Host of URL should have both IPv4 and IPv6 if you have double stack in local. # First is URL, others are IP addresses if given. # Considering traffic consumption, it is recommended to choose a site with anycast IP and less response. #tcp_check_url: 'http://cp.cloudflare.com' tcp_check_url: 'http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111' # The HTTP request method to `tcp_check_url`. Use 'HEAD' by default because some server implementations bypass # accounting for this kind of traffic. tcp_check_http_method: HEAD # This DNS will be used to check UDP connectivity of nodes. And if dns_upstream below contains tcp, it also be used to check # TCP DNS connectivity of nodes. # First is URL, others are IP addresses if given. # This DNS should have both IPv4 and IPv6 if you have double stack in local. #udp_check_dns: 'dns.google.com:53' udp_check_dns: 'dns.google.com:53,8.8.8.8,2001:4860:4860::8888' check_interval: 30s # Group will switch node only when new_latency <= old_latency - tolerance. check_tolerance: 50ms ##### Connecting options. # Optional values of dial_mode are: # 1. "ip". Dial proxy using the IP from DNS directly. This allows your ipv4, ipv6 to choose the optimal path # respectively, and makes the IP version requested by the application meet expectations. For example, if you # use curl -4 ip.sb, you will request IPv4 via proxy and get a IPv4 echo. And curl -6 ip.sb will request IPv6. # This may solve some weird full-cone problem if your are be your node support that. Sniffing will be disabled # in this mode. # 2. "domain". Dial proxy using the domain from sniffing. This will relieve DNS pollution problem to a great extent # if have impure DNS environment. Generally, this mode brings faster proxy response time because proxy will # re-resolve the domain in remote, thus get better IP result to connect. This policy does not impact routing. # That is to say, domain rewrite will be after traffic split of routing and dae will not re-route it. # 3. "domain+". Based on domain mode but do not check the reality of sniffed domain. It is useful for users whose # DNS requests do not go through dae but want faster proxy response time. Notice that, if DNS requests do not # go through dae, dae cannot split traffic by domain. # 4. "domain++". Based on domain+ mode but force to re-route traffic using sniffed domain to partially recover # domain based traffic split ability. It doesn't work for direct traffic and consumes more CPU resources. dial_mode: domain # Allow insecure TLS certificates. It is not recommended to turn it on unless you have to. allow_insecure: false # Timeout to waiting for first data sending for sniffing. It is always 0 if dial_mode is ip. Set it higher is useful # in high latency LAN network. sniffing_timeout: 100ms # TLS implementation. tls is to use Go's crypto/tls. utls is to use uTLS, which can imitate browser's Client Hello. tls_implementation: tls # The Client Hello ID for uTLS to imitate. This takes effect only if tls_implementation is utls. # See more: https://github.com/daeuniverse/dae/blob/331fa23c16/component/outbound/transport/tls/utls.go#L17 utls_imitate: chrome_auto } # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/dns.md for full examples. 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 #} upstream { # Value can be scheme://host:port, where the scheme can be tcp/udp/tcp+udp. # 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://223.5.5.5:53' googledns: 'tcp+udp://8.8.8.8: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 # other custom rules qname(full:analytics.google.com) -> googledns # do not block google analytics(console) qname(regex: '.+\.nixos.org$') -> googledns qname(geosite:category-ads) -> reject qname(geosite:category-ads-all) -> reject qtype(aaaa) -> reject qname(regex: '.+\.linkedin$') -> googledns } # 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(domain resolved to a private ip), re-lookup using googledns. ip(geoip:private) && !qname(geosite:cn) -> googledns fallback: accept } } } # Node group (outbound). group { proxy { filter: name(keyword: 'Hong Kong') filter: name(keyword: '香港') filter: name(keyword: 'Singapore') filter: name(keyword: '新加坡') # Filter nodes and give a fixed latency offset to archive latency-based failover. # In this example, there is bigger possibility to choose US node even if original latency of US node is higher. filter: name(keyword: 'USA') [add_latency: -500ms] filter: name(keyword: '美国') [add_latency: -500ms] filter: name(keyword: 'UK') [add_latency: -300ms] # filter: name(keyword: '英国') [add_latency: -300ms] # filter: name(keyword: 'Japan') [add_latency: 300ms] # filter: name(keyword: '日本') [add_latency: 300ms] # Other filters: # Filter nodes from the global node pool defined by the subscription and node section above. # filter: subtag(regex: '^my_', another_sub) && !name(keyword: 'ExpireAt:') # Filter nodes from the global node pool defined by tag. # filter: name('node_a','node_b') # Select the node with min average of the last 10 latencies from the group for every connection. policy: min_avg10 # Other policies: # random - Randomly select a node from the group for every connection. # fixed(0) - Select the first node from the group for every connection. # min - Select the node with min last latency from the group for every connection. # min_moving_avg - Select the node with min moving average of latencies from the group for every connection. } media { filter: name(keyword: 'Hong Kong') filter: name(keyword: '香港') filter: name(keyword: 'Singapore') filter: name(keyword: '新加坡') filter: name(keyword: 'USA') [add_latency: -500ms] filter: name(keyword: '美国') [add_latency: -500ms] filter: name(keyword: 'UK') [add_latency: -300ms] filter: name(keyword: '英国') [add_latency: -300ms] filter: name(keyword: 'Japan') [add_latency: 300ms] filter: name(keyword: '日本') [add_latency: 300ms] policy: min_avg10 } ssh-proxy { filter: name(keyword: 'UK') filter: name(keyword: '英国') policy: min_avg10 } sg { filter: name(keyword: 'Singapore') filter: name(keyword: '新加坡') policy: min_avg10 } usa { filter: name(keyword: 'USA') filter: name(keyword: '美国') policy: min_avg10 } } # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md for full examples. # Pname has the highest priority, so should be placed in the front. # Priority of other rules is the same as the order of the rules defined in this file. routing { ### Preset rules. # Network managers in localhost should be direct to # avoid false negative network connectivity check when binding to WAN. pname(NetworkManager) -> direct pname(systemd-networkd) -> direct # Put it in the front to prevent broadcast, multicast and other packets that should be sent to the LAN from being # forwarded by the proxy. # "dip" means destination IP. dip(224.0.0.0/3, 'ff00::/8') -> direct # This line allows you to access private addresses directly instead of via your proxy. If you really want to access # private addresses in your proxy host network, modify the below line. dip(geoip:private) -> direct # --- Core rules ---# # Disable HTTP3(QUIC) because it usually consumes too much cpu/mem resources. l4proto(udp) && dport(443) -> block # Direct access to all Chinese mainland-related IP addresses dip(geoip:cn) -> direct domain(geosite:cn) -> direct # Block ads domain(full:analytics.google.com) -> proxy # do not block google analytics(console) domain(geosite:category-ads) -> block domain(geosite:category-ads-all) -> block # DNS dip(8.8.8.8, 8.8.4.4) -> proxy dip(223.5.5.5, 223.6.6.6) -> direct domain(full:dns.alidns.com) -> direct domain(full:dns.googledns.com) -> proxy domain(full:dns.opendns.com) -> proxy # --- Rules for other commonly used sites ---# # SSH - tcp port 22 is blocked by many proxy servers. dport(22) && !dip(geoip:cn) && !domain(geosite:cn) -> ssh-proxy ### OpenAI domain(geosite:openai) -> sg domain(regex:'.+\.openai$') -> sg ### Media domain(geosite:netflix) -> media ### Proxy domain(suffix: linkedin.com) -> proxy domain(keyword:'linkedin') -> proxy domain(regex:'.+\.linkedin\.com$') -> proxy domain(regex:'.+\.quay\.io$') -> proxy domain(regex:'.+\.notion\.so$') -> proxy domain(regex:'.+\.amazon\.com$') -> proxy domain(regex:'.+\.oracle\.com$') -> proxy domain(regex:'.+\.docker\.com$') -> proxy domain(regex:'.+\.kubernetes\.io$') -> proxy domain(regex:'.+\.nixos\.org$') -> proxy domain(geosite:microsoft) -> proxy domain(geosite:linkedin) -> proxy domain(geosite:twitter) -> proxy domain(geosite:telegram) -> proxy domain(geosite:google) -> proxy domain(geosite:apple) -> proxy domain(geosite:category-container) -> proxy domain(geosite:category-dev) -> proxy domain(geosite:google-scholar) -> proxy domain(geosite:category-scholar-!cn) -> proxy ### Direct domain(regex:'.+\.edu\.cn$') -> direct domain(keyword:'baidu') -> direct domain(keyword:'bilibili') -> direct domain(keyword:'taobao') -> direct domain(keyword:'alibabadns') -> direct domain(keyword:'alicdn') -> direct domain(keyword:'tbcache') -> direct domain(keyword:'zhihu') -> direct domain(keyword:'douyu') -> direct domain(geosite:cloudflare-cn) -> direct # --- Fallback rules ---# # Access all other foreign sites domain(geosite:geolocation-!cn) -> proxy !dip(geoip:cn) -> proxy fallback: direct }