把同一个域名按访问者的运营商(电信 / 联通 / 移动)解析到不同的 IP,让用户就近访问、提升体验。本文给出一份生产可用的 BIND9 智能 DNS 完整配置。

说明:文中所有 IP 均为 RFC1918 私有段示例(10.x.x.x / 192.168.x.x / 172.16.x.x),仅用于演示,请替换为您的真实线路 IP;域名 emporerlinux.com 为示例域名,请替换为您自己的域名。

一、什么是智能 DNS

普通 DNS 对所有查询返回同一个 IP;智能 DNS(Smart DNS / View-based DNS)则会根据客户端的来源 IP(运营商、地域)返回不同的解析结果。

典型应用场景:

  • 多线机房:电信用户解析到电信线路 IP,联通用户解析到联通 IP,避免跨网访问慢
  • CDN 调度:把不同地区用户调度到最近的边缘节点
  • 灰度/容灾:某条线路故障时,让对应运营商用户走备用 IP

BIND9 通过 view + acl 原生支持这种能力。

二、整体架构

                  ┌─────────────────────────────────────┐
客户端 DNS 查询 ──▶│            BIND9 named              │
                  │  ┌────────────────────────────────┐ │
                  │  │ view "ctc"  ← 电信 ACL         │──▶ 电信线路 zone
                  │  │ view "cuc"  ← 联通 ACL         │──▶ 联通线路 zone
                  │  │ view "cmcc" ← 移动 ACL         │──▶ 移动线路 zone
                  │  │ view "any"  ← 兜底(其他来源) │──▶ 默认 zone
                  │  └────────────────────────────────┘ │
                  └─────────────────────────────────────┘

匹配规则:named 按 view 声明顺序自上而下匹配,第一个命中的 match-clients 生效,因此兜底的 any 必须放在最后。

三、目录结构

配置按职责拆分到不同文件,便于维护:

/etc/named/
├── named.conf                  # 主配置:include 其它文件
├── conf/
│   ├── named.ca                # 根域 hint
│   ├── acl.conf                # 汇总所有 ACL(include 各 acl/*.acl)
│   └── view.conf               # 汇总所有 view(include 各 view/*.view)
├── acl/
│   ├── ctc.acl                 # 电信 IP 段
│   ├── cuc.acl                 # 联通 IP 段
│   └── cmcc.acl                # 移动 IP 段
├── view/
│   ├── ctc.view                # 电信视图
│   ├── cuc.view                # 联通视图
│   ├── cmcc.view               # 移动视图
│   └── any.view                # 兜底视图
└── zone/
    ├── emporerlinux.com/
    │   ├── ctc.zone  cuc.zone  cmcc.zone  any.zone   # 各线路 zone(差异部分)
    │   └── all.zone                                      # 公共记录(被 $INCLUDE 复用)
    └── emporerlinux.net/
        ├── ctc.zone  cuc.zone  cmcc.zone  any.zone
        └── all.zone

拆分原则:会变的(zone 记录)和不变的(ACL、view 结构)分开,改一条 A 记录不用碰 view 配置。

四、配置详解

1. 主配置 named.conf

只做 include,保持清爽:

include "conf/acl.conf";       # 加载所有 ACL
include "conf/view.conf";      # 加载所有 view

2. ACL 汇总 conf/acl.conf

把各运营商的 IP 段都 include 进来:

include "acl/cuc.acl";
include "acl/cmcc.acl";
include "acl/ctc.acl";

3. 运营商 ACL 定义 acl/ctc.acl

每个文件定义一个命名 ACL,里面是该运营商的 IP 段(CIDR)。

⚠️ 下面的 IP 全是 RFC1918 私有段,仅为示例占位。生产环境请替换为真实的运营商 IP 段(可从 CNNIC / apnic 公开数据获取,或用 whois -h whois.apnic.net 查询)。

# acl/ctc.acl —— 电信(示例:用 10.0.0.0/10 代表电信地址段)
acl "ctc" {
    10.0.0.0/10;
};

# acl/cuc.acl —— 联通(示例:用 10.64.0.0/10 代表联通地址段)
acl "cuc" {
    10.64.0.0/10;
};

# acl/cmcc.acl —— 移动(示例:用 10.128.0.0/10 代表移动地址段)
acl "cmcc" {
    10.128.0.0/10;
};

4. view 汇总 conf/view.conf

按顺序 include 各 view(顺序很重要,兜底 any 必须最后):

include "view/ctc.view";
include "view/cuc.view";
include "view/cmcc.view";
include "view/any.view";

5. 视图定义 view/ctc.view

每个 view 用 match-clients 匹配 ACL,并为每个域指定对应的 zone 文件:

# view/ctc.view —— 电信用户看到的解析
view "ctc" {
    match-clients { "ctc"; };

    zone "." {
        type hint;
        file "conf/named.ca";
    };

    zone "emporerlinux.com" {
        type master;
        file "zone/emporerlinux.com/ctc.zone";
    };

    zone "emporerlinux.net" {
        type master;
        file "zone/emporerlinux.net/ctc.zone";
    };
};
# view/cuc.view —— 联通
view "cuc" {
    match-clients { "cuc"; };

    zone "." {
        type hint;
        file "conf/named.ca";
    };

    zone "emporerlinux.com" {
        type master;
        file "zone/emporerlinux.com/cuc.zone";
    };

    zone "emporerlinux.net" {
        type master;
        file "zone/emporerlinux.net/cuc.zone";
    };
};
# view/cmcc.view —— 移动
view "cmcc" {
    match-clients { "cmcc"; };

    zone "." {
        type hint;
        file "conf/named.ca";
    };

    zone "emporerlinux.com" {
        type master;
        file "zone/emporerlinux.com/cmcc.zone";
    };

    zone "emporerlinux.net" {
        type master;
        file "zone/emporerlinux.net/cmcc.zone";
    };
};
# view/any.view —— 兜底(其它所有来源,必须放最后)
view "any" {
    match-clients { "any"; };

    zone "." {
        type hint;
        file "conf/named.ca";
    };

    zone "emporerlinux.com" {
        type master;
        file "zone/emporerlinux.com/any.zone";
    };

    zone "emporerlinux.net" {
        type master;
        file "zone/emporerlinux.net/any.zone";
    };
};

6. zone 文件(核心:差异 + 复用)

每个域下有 5 个 zone 文件:4 个线路文件(ctc/cuc/cmcc/any)+ 1 个公共文件(all.zone)。

线路文件只放「该线路不同的部分」,公共记录通过 $INCLUDE 复用:

# zone/emporerlinux.com/ctc.zone —— 电信线路专属记录
$TTL 600
@   IN  SOA  ns1.emporerlinux.com. admin.emporerlinux.com. (
            2026072401   ; 序列号(每次改动 +1)
            3600         ; 刷新
            900          ; 重试
            86400        ; 过期
            600 )        ; 最小 TTL
    IN  NS   ns1.emporerlinux.com.
    IN  NS   ns2.emporerlinux.com.

; —— 电信线路专属:www 指向电信线路 IP(示例用 192.168.10.x)——
www IN  A    192.168.10.100

; —— 公共记录(所有线路都一样)——
$INCLUDE "zone/emporerlinux.com/all.zone";
# zone/emporerlinux.com/all.zone —— 公共记录(所有线路共享,示例 IP)
ns1  IN  A    10.0.0.53
ns2  IN  A    10.0.0.54
mail IN  A    172.16.0.25
@    IN  MX 10 mail.emporerlinux.com.

这样设计的好处:

场景 传统做法 本方案
改 www 的电信 IP 改 ctc.zone 改 ctc.zone(一样)
新增一条所有线路通用的记录 改 4 个 zone 文件 只改 all.zone 一处
新增运营商线路 大改 加一个 acl + view + zone 文件

五、验证配置

改完配置先检查语法,再 reload:

# 1. 检查主配置语法
named-checkconf /etc/named/named.conf

# 2. 检查 zone 文件语法(域名 + 文件路径)
named-checkzone emporerlinux.com /etc/named/zone/emporerlinux.com/ctc.zone

# 3. 重新加载配置(不中断服务)
rndc reload

# 或重载 named
systemctl reload named

六、测试智能解析

dig 指定不同源 IP 模拟各运营商查询:

# 模拟电信用户查询(-b 绑定本地源 IP,该 IP 属于电信 ACL 示例段 10.0.0.0/10)
dig @127.0.0.1 www.emporerlinux.com -b 10.0.0.100 +short
# 预期返回: 192.168.10.100(电信线路 IP)

# 模拟联通用户(10.64.0.0/10 段)
dig @127.0.0.1 www.emporerlinux.com -b 10.64.0.100 +short

# 不指定源 IP(走 any 兜底)
dig @127.0.0.1 www.emporerlinux.com +short

如果返回的 IP 和预期一致,说明 view 分流生效。

七、生产注意事项

  1. ACL 要定期更新:运营商 IP 段会调整,建议每月从 apnic 同步一次。
  2. 兜底 view 必须放最后any 放前面会导致所有匹配都走兜底。
  3. view 间 zone 必须一致:每个 view 都要包含所有域,否则某些运营商查不到。
  4. 序列号要递增:zone 文件 SOA 序列号每次改动必须 +1,否则从 DNS 不同步。
  5. 配合主从同步:多台 DNS 时,view 配合 allow-transferalso-notify 做主从,注意从服务器也要有相同的 view + ACL 配置。
  6. 客户端真实 IP:如果前面有 DNS 负载均衡(如 F5/LVS),match-clients 看到的是 LB 的 IP,不是真实客户端 IP。这种场景需要 LB 做 EDNS Client Subnet 透传。

八、总结

组件 作用
acl 定义运营商 IP 段
view + match-clients 按来源 IP 分流到不同 zone
zone 文件 + $INCLUDE 线路差异 + 公共记录复用
named-checkconf / dig -b 验证语法 + 测试分流

核心思路一句话:用 view 把客户端按 ACL 分类,每类看到不同的解析结果。配置拆分到多文件后,维护成本低、扩展运营商线路也容易。


作者:EmporerLinux | 分类:网络服务
本文首发于 emporerlinux.com,转载请注明出处。

文章作者: emporer
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Emporer-Linux
喜欢就支持一下吧