# ============================================================
# OxiDNS 完整配置：国内外分流 + 广告拦截 + 规则自动更新 + 缓存加速
# 部署：docker compose 接管宿主机 53 端口
# 使用前请至少修改：api.http.auth 的账号密码、forward_oversea 的上游地址
# ============================================================

api:
  http:
    listen: "0.0.0.0:9199"
    auth:
      type: basic
      # TODO：请务必改成你自己的强密码（字母+数字+符号，12位以上）
      username: "admin"
      password: "ChangeMe_2026!"
    webui:
      root: "/etc/oxidns/webui"
      index: "index.html"

log:
  level: info
  # 日志落到 data 目录，容器重建后还能留下来
  file: "/var/lib/oxidns/oxidns.log"

runtime:
  worker_threads: 4

plugins:
  # ============================================================
  # 一、规则数据（geosite / geoip / 广告规则）
  # ============================================================

  # ----- Geo 数据（直接读 .dat）-----
  - tag: geosite_cn
    type: geosite
    args:
      file: "/etc/oxidns/rules/geosite.dat"
      selectors: ["cn"]

  - tag: geosite_no_cn
    type: geosite
    args:
      file: "/etc/oxidns/rules/geosite.dat"
      selectors: ["geolocation-!cn"]

  - tag: geoip_cn
    type: geoip
    args:
      file: "/etc/oxidns/rules/geoip.dat"
      selectors: ["cn"]

  # ----- 广告 / 追踪域名规则 -----
  # 支持 AdGuard 语法（||domain^），白名单 @@ 优先
  - tag: ad_rules
    type: adguard_rule
    args:
      files:
        - "/etc/oxidns/rules/adguard_ad.txt"
      # 内联白名单：防止误杀常用域名（按需追加）
      rules:
        - "@@||www.googleadservices.com^"   # 示例，按需开关
        - "@@||pagead2.googlesyndication.com^"

  # ============================================================
  # 二、缓存（加速 + 降负载）
  # ============================================================
  - tag: cache_main
    type: cache
    args:
      size: 16384              # 缓存条目数（默认 4096，调大减少回源）
      short_circuit: true      # 缓存命中立即返回，不再走后续匹配
      cache_negative: true     # 负缓存：解析失败也缓存，防重试风暴
      cache_min_ttl: 60        # 最小缓存 60s，避免短 TTL 频繁回源
      lazy_cache_ttl: 3600     # 最长缓存 1h（原为 86400，防 IP 长期不更新）

  # ============================================================
  # 三、上游 DNS
  # ============================================================

  # ----- 国内上游（阿里 + DNSPod，直连稳定）-----
  - tag: forward_cn
    type: forward
    args:
      concurrent: 2
      response_selection: fastest
      upstreams:
        - addr: "223.5.5.5:53"
          timeout: 5s
        - addr: "119.29.29.29:53"
          timeout: 5s

  # ----- 国外上游（DoH）-----
  # 这里只是示例，请替换成你自己的网络能连通的 DoH/DoT 地址：
  # 自建 DoH、Cloudflare、Google、NextDNS 都行。
  # bootstrap：DoH 上游写的是域名，得先把这个域名解析成 IP 才能连上，
  # 这一步不能交给 OxiDNS 自己办（会绕成环），所以指定一个纯 IP 的普通 DNS。
  # 如果上游直接写 https://1.1.1.1/dns-query 这种 IP 形式，可以删掉 bootstrap。
  - tag: forward_oversea
    type: forward
    args:
      concurrent: 2
      response_selection: fastest
      bootstrap: "223.5.5.5:53"
      upstreams:
        - addr: "https://dns.cloudflare.com/dns-query"
          timeout: 8s
        - addr: "https://dns.google/dns-query"
          timeout: 8s

  # ============================================================
  # 四、处理序列
  # ============================================================

  # ----- 广告黑洞：返回 0.0.0.0 / :: -----
  - tag: ad_blocked
    type: sequence
    args:
      - exec: 'black_hole 0.0.0.0 ::'
      - exec: accept

  # ----- 国内序列：响应 IP 必须是 CN -----
  - tag: local_seq
    type: sequence
    args:
      - exec: $cache_main
      - matches: has_resp
        exec: accept
      - exec: $forward_cn
      - matches: "resp_ip $geoip_cn"
        exec: accept
      - exec: drop_resp

  # ----- 国外序列 -----
  - tag: remote_seq
    type: sequence
    args:
      - exec: $cache_main
      - matches: has_resp
        exec: accept
      - exec: $forward_oversea

  # ----- 主序列（广告拦截在最前）-----
  - tag: main
    type: sequence
    args:
      # 0. 广告 / 追踪域名拦截（最高优先级）
      - matches: "question $ad_rules"
        exec: goto ad_blocked
      # 1. 查缓存
      - exec: $cache_main
      - matches: has_resp
        exec: accept
      # 2. 国内 / 国外分流
      - matches: "qname $geosite_cn"
        exec: goto local_seq
      - matches: "qname $geosite_no_cn"
        exec: goto remote_seq
      # 3. 未知域名默认走国外（按需可改 local_seq）
      - exec: goto remote_seq

  # ============================================================
  # 五、规则自动更新（cron）
  # ============================================================
  - tag: cron_update
    type: cron
    args:
      timezone: Asia/Shanghai
      jobs:
        # geosite / geoip 每天更新
        - name: update_geo_rules
          interval: 1d
          executors:
            - $download_geo
            - $reload_geo
        # 广告规则每周更新
        - name: update_ad_rules
          interval: 7d
          executors:
            - $download_ad
            - $reload_ad

  - tag: download_geo
    type: download
    args:
      timeout: 120s
      startup_if_missing: true
      downloads:
        - url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
          dir: /etc/oxidns/rules
          filename: geosite.dat
        - url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/geoip-only-cn-private.dat"
          dir: /etc/oxidns/rules
          filename: geoip.dat

  - tag: reload_geo
    type: reload_provider
    args:
      - $geosite_cn
      - $geosite_no_cn
      - $geoip_cn

  - tag: download_ad
    type: download
    args:
      timeout: 120s
      startup_if_missing: true
      downloads:
        # 使用 AdGuard 语法的广告规则源（原生兼容，无需转换）
        - url: "https://cdn.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-easylist.txt"
          dir: /etc/oxidns/rules
          filename: adguard_ad.txt

  - tag: reload_ad
    type: reload_provider
    args:
      - $ad_rules

  # ============================================================
  # 六、监听 53（host 模式直接绑宿主机）
  # ============================================================
  - tag: udp_server
    type: udp_server
    args:
      entry: main
      listen: "0.0.0.0:53"

  - tag: tcp_server
    type: tcp_server
    args:
      entry: main
      listen: "0.0.0.0:53"
