前言

虽然高三了,而且未来想要读的第一专业还不是计算机科学,但是我还是准备整个大活(

所以,我打算送给自己一个权威 DNS 服务器。(虽然要求要有一个 Primary 和一个 Secondary

它应该能干什么?

我对这个权威 DNS 服务器的预期是这样的,它除了解析域名以外,还应该能:

  • 限制每秒的反应次数 (因为我租的服务器性能都不是很够)
  • 根据来访 IP 位址,进行不同的解析
  • 支持动态更新

开整!

在这里,我选择用 bind 作为 DNS 服务器上跑的程序,以 hanxuan.ya 作为示例域名。

Prerequisite

在准备用作 Primary 和 Secondary 服务器的机器上安装 bind

[bai@primary ~]$ sudo apt install bind9

在 Primary 服务器(10.20.30.39, ns.hanxuan.ya)上如此配置 /path/to/bind9/confs/named.conf.local1

zone "hanxuan.ya" {
    type primary;
    file "/path/to/custom/zone/hanxuan.ya";
    notify yes;
    allow-transfer {
        10.20.30.40;
    };
};

在 Secondary 服务器(10.20.30.40, ns-2.hanxuan.ya)上做类似的配置:

zone "hanxuan.ya" {
    type secondary;
    file "/path/to/custom/saved/zone/hanxuan.ya.saved";
    primaries {
        10.20.30.39;
    };
};

实现动态更新的 bind 端设置

然后,我们去整一个 key2

[bai@primary ~]$ dnssec-keygen -a RSASHA1 -b 4096 -n ZONE shiro

接下来,应该会有文件名像这样的两个文件生成: Kshiro.+123+45678.keyKshiro.+123+45678.private

其中,.key 后缀的内容大概长这样:

; This is a zone-signing key, keyid 23816, for shiro.
shiro. IN DNSKEY 256 3 5 AwEAAdxhMSWbsRK/... ... ...

把后面的 secret 复制到 named.conf.local 里头,整完了以后应该长这样:

key "shiro" {
    algorithm rsasha1;
    secret "AwEAAdxhMSWbsRK/... ... ...";
};

zone "hanxuan.ya" {
    ...
};

而且,我们也要对 zone 区块做相应修改:

zone "hanxuan.ya" {
    ...
    update-policy {
        grant shiro subdomain hanxuan.ya. ANY;
    };
};

这样,shiro key 就拥有完全控制 hanxuan.ya 的能力。如果只想让一个 key 的使用者只能控制一个子域名,可以这么写 update-policy

update-policy { grant nya-teacher school.projects.hanxuan.ya. A; };

这样 nya-teacher key 的使用者就只能更改 school.projects.hanxuan.yaA 记录。

此后,我们就可以使用 nsupdate 工具更新 Primary DNS 了。

比如,可以这么干:

[bai@primary ~]$ nsupdate -k Kshiro.+123+45678.key
> server ns.hanxuan.ya
> update delete hanxuan.ya A
> update add hanxuan.ya 3600 A 10.20.30.40
> send

实现动态更新的 CLI

在 2002 年 Leo 发表的文章3 中,他使用了 newip.sh 从脚本 tmp.txt 中更新 A 记录。在这里,我打算采用另外一种简单的方式写一个动态更新的 CLI:


# /path/to/cli/calling/update-cli.py

import os

def change(
    record = 'A',
    ip = '10.20.30.39',
    subdomain = '@',
    ns = 'ns.hanxuan.ya',
    domain = 'hanxuan.ya',
    ttl = 3600,
    keyPath = '/path/to/public/key/public.key'
):
    with open('tmp.txt', 'w+') as f:
        f.write(
            """
            server {ns}
            update delete {subdomain}.{domain} {record}
            update add {subdomain}.{domain} {ttl} {record} {ip}
            send
            """.format(
                ns = ns,
                subdomain = subdomain,
                domain = domain,
                record = record,
                ttl = ttl,
                ip = ip
            )
        )
    os.system('nsupdate -k {key} -v tmp.txt'.format(key = keyPath))
    os.remove('tmp.txt')
    return

效果应该和 newip.sh 差不多(

实现 IP 的识别以及对应的解析

虽然这个站点也没有多少人会来看,但是既然我们都租用了俩服务器,还是可以玩点花的,比如通过识别访问的 IP 地址的位置实现不同的解析4

首先,我们可以在 named.conf.localoptions 区块里加上这个:

options {
    ...
    geoip-directory "/path/to/geoip/db";
};

然后,我们就可以通过运用 ACL (Access Control List5) 来识别访问 IP 的位置了。

例如,hanxuan.ya 在鸭鸭省内和省外的解析若有不同,则我们可以这么写:

acl "dualduck_province" {
    geoip country CN;
    geoip region YA;
};

view "dualduck" {
    match-clients { dualduck_province; };
    zone "hanxuan.ya" {
        file "/path/to/custom/zone/ya/hanxuan.ya";
        type primary;
    };
};

view "default" {
    zone "hanxuan.ya" {
        file "/path/to/custom/zone/non-ya/hanxuan.ya";
        type primary;
    };
};

限制每秒的反应次数

bind 提供了一个叫做 rate-limit 的区块,可以套到 options 或者 view 区块里 16

只要在这些区块里加上这么一段:

rate-limit {
    all-per-second 100000;
};

就可以硬性地限制每秒应对的最多请求数(无论何种类型)为 100,000。

当然,Manual 还给了其他的玩法,可以对请求数的限制做更精细化的要求,但是因为我的目的似乎、好像、可能已经达到了,所以在这里不赘述。

添加 GLUE 记录

在一切都设置好后,我们就可以去域名注册商那里改 GLUE 记录了(

在改完以后,可以这么检查一下是否配置成功:

[bai@local ~]$ dig hanxuan.ya NS +trace
...

hanxuan.ya.     604800  IN  NS  ns.hanxuan.ya.
hanxuan.ya.     604800  IN  NS  ns-2.hanxuan.ya.
...

;; Received 1194 bytes from 42.24.42.24#53(yatld-ns-1.dualduck-telecom.ya) in 5 ms

hanxuan.ya.     604800  IN  NS  ns.hanxuan.ya.
hanxuan.ya.     604800  IN  NS  ns-2.hanxuan.ya. 
;; Received 98 bytes from 10.20.30.39#53(ns.hanxuan.ya) in 70 ms

完成!现在我们有了自己的权威 DNS 服务器(!


  1. ISC Contributors (n.d.). Bind 9 administrator reference manual. BIND 9 Administrator Reference Manual - BIND 9 documentation. https://bind9.readthedocs.io/en/v9.16.20 ↩︎ ↩︎

  2. Oracle (2014). dnssec-keygen. man pages section 1M: System Admintration Commands. https://docs.oracle.com/cd/E36784_01/html/E36871/dnssec-keygen-1m.html ↩︎

  3. Leo. (2002). 動態 DNS 設定技巧. http://www.study-area.org/tips/ddns.htm ↩︎

  4. ISC Contributors (2020). Using the GeoIP Features. https://kb.isc.org/docs/aa-01149 ↩︎

  5. ISC Contributors (2018). Using Access Control Lists (ACLs) with both addresses and keys. https://kb.isc.org/docs/aa-00723 ↩︎

  6. ISC Contributors (2018). Using the Response Rate Limiting Feature. https://kb.isc.org/docs/aa-00994 ↩︎