Featured image of post 自建DNS实现分流及广告过滤

自建DNS实现分流及广告过滤

使用mosdns+AdGuardHome自建加密DNS

由于运营商默认提供的DNS有很多的污染,许多域名直接0.0.0.0或者127.0.0.1伺候,导致上网体验并不是很好,故想到自建加密DNS来抵御污染。

DNS污染

一开始使用的是AdGuardHome,然而在我看到了CloudflareSpeedTest这个项目后,就萌生了ip重定向这个需求,为此我又套了一层mosdns(经典为醋包饺子)。既然上了mosdns,就干脆做配上分流吧,于是现在的这套方案就形成了。虽然我的这些需求一个mosdns就可以解决,但AdGuardHome的前端ui、更方便的广告过滤、数据统计这些功能是mosdns所没有的。

# 23.2.8新方案

由于CloudFlare的优选IP在不同设备上速度都不同,所以在设备本地搭建更优。于是,我现在将mosdns从服务器上移到了本地。当然,在路由器上部署要更好,但我家的路由器性能太弱了,就算了。同时,去广告就交给mosdns,这样就无需使用两个软件进行套娃了。

mosdns在这段时间也更新了V5版本,原先的配置文件也无法使用了,正好做出V5可用的配置。

在该配置文件中,需要用上以下项目提供的域名/IP文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Powered by luoboQAQ
log:
  level: info

plugins:
  # 缓存插件
  - tag: cache
    type: cache
    args:
      size: 10240
      lazy_cache_ttl: 86400
      # 将缓存保存在磁盘
      dump_file: ./cache.dump

  # 转发至本地服务器的插件
  - tag: forward_local
    type: forward
    args:
      upstreams:
        - tag: alidns_doh
          addr: "https://223.5.5.5/dns-query"
        - tag: dnspod_doh
          addr: "https://120.53.53.53/dns-query"

  # 转发至远程服务器的插件
  - tag: forward_remote
    type: forward
    args:
      upstreams:
        - tag: easymosdns
          addr: "https://doh.apad.pro/dns-query"
          bootstrap: "223.5.5.5"
        - tag: dns_sb
          addr: "https://45.11.45.11/dns-query"

  # fallback 用本地服务器 sequence
  # 返回不包含本地 ip 则 reject
  - tag: local_ip_sequence
    type: sequence
    args:
      - exec: $forward_local
      - matches: resp_ip &./data/CN-ip-cidr.txt
        exec: accept
      - exec: drop_resp # v5.1.2 以后不能用 reject

  # fallback 用远程服务器 sequence
  - tag: remote_sequence
    type: sequence
    args:
      - exec: $forward_remote
      # CloudFlare劫持到优选IP
      - matches:
          - resp_ip &./data/cloudflare.txt
        exec: black_hole 172.67.210.33
      - exec: accept

  # fallback插件
  - tag: fallback
    type: fallback
    args:
      primary: local_ip_sequence
      secondary: remote_sequence
      threshold: 500
      always_standby: true

  # 主要运行逻辑插件
  - tag: main
    type: sequence
    args:
      - matches: qtype 65
        exec: reject 3

      # 去广告
      - matches: qname &./data/reject-list.txt
        exec: reject 3
      - matches: qname &./data/ad-domains.txt
        exec: reject 3       

      - exec: prefer_ipv4

      - exec: $cache
      - matches: has_resp
        exec: accept

      - matches: qname &./data/direct-list.txt
        exec: $forward_local
      - matches: has_resp
        exec: accept
    
      - exec: $fallback

  # 启动 udp服务器
  - type: udp_server
    args:
      entry: main
      listen: 127.0.0.1:53

此配置文件参考了该回答

# 方案设计

首先由AdGuardHome接受请求,判断是否为广告域名:

  • 是:直接拦截,结束流程
  • 否:继续传入mosdns

判断是否为国内域名:

  • 是:向本地DNS查询
  • 否:向远端DNS查询

判断是否为CloudFlare的IP:

  • 是:修改响应为优选的IP
  • 否:不进行操作

# 系统搭建

# 搭建mosdns

如何安装和配置mosdns,官方文档已经写的非常详细了,直接看文档就好了。

配置文件主要参考了pmkol/easymosdns

这里主要分享一下我的配置:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Powered by luoboQAQ
log:
    file: "./mosdns.log"
    level: error

# 数据源设置
data_providers:
  - tag: CloudFlareIP
    file: "./rules/cloudflare.txt" 
    auto_reload: true
  - tag: chinalist
    file: "./rules/geosite_cn.txt"
    auto_reload: true

plugins:
  # 缓存的插件
  - tag: cache
    type: cache
    args:
      size: 10240
      lazy_cache_ttl: 86400
      cache_everything: true
 
  # 匹配PTR类型请求的插件
  - tag: query_is_ptr
    type: query_matcher
    args:
      qtype: [12]

  # 匹配TYPE65类型请求的插件
  - tag: qtype65
    type: query_matcher
    args:
      qtype: [65]

  # 屏蔽请求的插件
  - tag: black_hole
    type: blackhole
    args:
      rcode: 0
      ipv4: "127.0.0.1"
      ipv6: "::1"

  # 匹配本地域名的插件
  - tag: query_is_cn_domain
    type: query_matcher
    args:
      domain:
        - "provider:chinalist"

  # 转发至本地服务器的插件
  # [local|alidns]
  - tag: forward_local
    type: fast_forward
    args:
      upstream:
        - addr: "udp://100.100.2.138"
  - tag: forward_alidns
    type: fast_forward
    args:
      upstream:
        - addr: "https://dns.alidns.com:443/dns-query"
          dial_addr: "223.5.5.5"

  # CloudFlare劫持的插件
  - tag: response_is_cloudflare_ip
    type: response_matcher
    args:
      ip:
        - "provider:CloudFlareIP"
  - tag: hijack_cloudflare_ip
    type: blackhole
    args:
      ipv4: 104.16.111.240

  # 转发至远端服务器的插件
  - tag: forward_easymosdns
    type: fast_forward
    args:
      upstream:
        - addr: "https://doh.apad.pro/dns-query"
          bootstrap: "223.5.5.5"

  # 主要的运行逻辑插件
  - tag: main_sequence
    type: sequence
    args:
      exec: 
        # 缓存
        - cache

        # 屏蔽TYPE65类型请求
        - if: qtype65
          exec:
          - black_hole
          - _return    

        # 分流
        - if: "(query_is_cn_domain) || (query_is_ptr)"
          exec:
            - forward_alidns
          else_exec:
            - forward_easymosdns
        # CloudFlare劫持到优选IP
        - if: response_is_cloudflare_ip
          exec: 
            - hijack_cloudflare_ip
            - _return
        

servers:
    - exec: main_sequence
      timeout: 5
      listeners:
        - addr: 127.0.0.1:5533
          protocol: udp

其中,cloudflare.txt来自于上面的CloudflareSpeedTest项目,是包含ipv4和ipv6的CloudflareIP段。

geosite_cn.txt是国内域名的集合,来自Loyalsoldier/v2ray-rules-dat,将geosite.dat使用mosdns v2dat unpack-domain 解包得到。

这里我没有启用mosdns的缓存,因为我在AdGuardHome里启用,就不重复缓存了。如果你是直接使用mosdns,那么就可以启用缓存。

事实上,还是要开启mosdns的缓存,以此来减小DNS查询的延时。

# 搭建AdGuardHome

这里我为了方便,就直接使用了docker,其实可以不用的说

1
2
3
4
5
6
docker run --name adguardhome\
    --restart unless-stopped\
    -v /root/adguardhome/work:/opt/adguardhome/work\
    -v /root/adguardhome/conf:/opt/adguardhome/conf\
    --net=host\
    -d adguard/adguardhome

我比较懒,就直接让容器使用了host模式,这样就不用配置端口了。

设置方面

  • 上游DNS服务器填入127.0.0.1:5533,即mosdns的端口。

  • 启用启用 EDNS 客户端子网,使DNS查询附上用户的ip,使解析的ip地址靠近本地位置。

  • 开启乐观缓存,设置覆盖最小TTL值为600,覆盖最大TTL值为3600,避免每次都要查询

  • 开启启用加密(HTTPS、DNS-over-HTTPS、DNS-over-TLS),启用DoH

  • 根据自己的喜好添加过滤规则

    我推荐启用CHN: anti-AD,这个列表还是很不错的

# Nginx反代配置

这里为了避免DoH被滥用,我修改了默认的路径,同时将默认路径返回444(中断连接)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
server {
    listen 80;
    listen 443 ssl http2;
    server_name you.domain;

    if ($server_port !~ 443){
        rewrite ^(/.*)$ https://$host$1 permanent;
    }

    ssl_certificate ./cert/xxx.pem;
    ssl_certificate_key ./cert/xxxx.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    #表示使用的加密套件的类型。
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
    ssl_prefer_server_ciphers on;

    location /set/ {
        proxy_pass http://127.0.0.1:11451/;
        proxy_redirect / /set/;
        proxy_cookie_path / /set/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

     location /query {
        proxy_http_version 1.1;
        proxy_pass https://127.0.0.1:11450/dns-query;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

     location / {
        return 444;
    }

}

# 客户端配置

# Windows

在win11 22H2中,在 设置——网络和Internet中 就可以设置加密DNS,输入服务器ip地址后选择手动模板就可以输入DoH地址了。

手动设置DoH

如果还没有升级到这个版本,可以用管理员模式运行powershell执行下面的命令

1
Add-DnsClientDohServerAddress -ServerAddress '123.xx.xx.xx' -DohTemplate 'https://your.domain/dns-query' -AllowFallbackToUdp $False -AutoUpgrade $True

随后直接将你服务器的ip设置成DNS服务器就可以了,系统会自动使用DoH进行请求。

# Android

安卓系统从9开始支持DoT,只要在连接与共享——私人DNS填入服务器的域名即可。

根据谷歌的公告,从13开始,安卓开始支持DoH。在此之前,想要使用DoH就只能依靠第三方软件了。

# 后记

单独使用AdGuardHome的情况下,开启缓存平均处理时间是5ms;AdGuardHome+mosdns目前是11ms。

折腾了两层解析,只是为了实现CloudFlare的IP优选,速度果然不出所料的慢了一点(当然也可能是缓存还没完全)。就当是学习了,正常使用留其一即可。_(:з)∠)_

通过这次折腾,对DNS的认识更加深了一步,也水了一篇博客

Licensed under CC BY-NC-SA 4.0
最后更新于 2023-03-27 15:23:00