CoreDNS 的 template、hosts、file 插件使用方法

CoreDNS 是一个开源的域名系统(DNS)服务器,用于将域名解析为 IP 地址以实现网络通信。它是一个用 Go 语言编写的可扩展 DNS 服务器,旨在取代传统的 DNS 服务器并提供更灵活、可配置的解析方案。

安装配置

一个极简的Corefile配置如下

1
2
3
4
.:PORT {
whoami
log
}

DNS服务默认端口为53。本机测试期间,选择使用 1053 端口。

首先创建名为 Corefile1 的配置文件,内容如下:

1
2
3
4
.:1053 {
whoami
log
}

启动 coredns 服务:

1
2
3
4
% coredns -conf ./Corefile1
.:1053
CoreDNS-1.11.1
darwin/arm64, go1.21.0,

使用hosts插件

在某个项目中,我要用CoreDNS来 为特定域名指定hosts。这时用到了 hosts 插件。

例如:要实现把 a.example.com 指向 192.168.1.2。

创建名为 Corefile2 的配置文件,内容如下:

1
2
3
4
5
6
7
8
.:1053 {
whoami
hosts {
192.168.1.2 a.example.com
fallthrough
}
log
}

启动 coredns服务:

1
% coredns -conf ./Corefile2

查询一下 a.example.com 对应的IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dig @127.0.0.1 -p 1053 a.example.com

; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 1053 a.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64095
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.example.com. IN A

;; ANSWER SECTION:
a.example.com. 3600 IN A 192.168.1.2

;; Query time: 3 msec
;; SERVER: 127.0.0.1#1053(127.0.0.1)
;; WHEN: Thu Nov 23 10:58:16 CST 2023
;; MSG SIZE rcvd: 71

可以看到 a.example.com. 3600 IN A 192.168.1.2,符合预期。

使用template插件

要用CoreDNS来实现泛域名或具有特定规则的域名指定hosts,需要 template 插件。

例如:要实现把 *.example.com 指向 192.168.1.1。
创建名为 Corefile3 的配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.:1053 {
whoami
hosts {
192.168.1.2 a.example.com
fallthrough
}
template IN A example.com {
match .*\.example\.com
answer "{{ .Name }} 60 IN A 192.168.1.1"
fallthrough
}
log
}

启动 coredns服务:

1
% coredns -conf ./Corefile3

查询一下 a.example.com 对应的IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dig @127.0.0.1 -p 1053 b.example.com

; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 1053 b.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49105
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;b.example.com. IN A

;; ANSWER SECTION:
b.example.com. 60 IN A 192.168.1.1

;; Query time: 1 msec
;; SERVER: 127.0.0.1#1053(127.0.0.1)
;; WHEN: Thu Nov 23 11:11:36 CST 2023
;; MSG SIZE rcvd: 71

可以看到 b.example.com. 60 IN A 192.168.1.1,符合预期。

同时使用 hosts 和 template 插件

在使用 Corefile3 时,如果查询 a.example.com 的解析,就会发现一个奇怪的现象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dig @127.0.0.1 -p 1053 a.example.com

; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 1053 a.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28857
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.example.com. IN A

;; ANSWER SECTION:
a.example.com. 60 IN A 192.168.1.1

;; Query time: 0 msec
;; SERVER: 127.0.0.1#1053(127.0.0.1)
;; WHEN: Thu Nov 23 11:16:16 CST 2023
;; MSG SIZE rcvd: 71

从直观看,a.example.com设置了hosts,应该是优先级更高才对,应该返回 192.168.1.2。但实际返回了templeat插件里的结果 192.168.1.1。

那么是不是插件顺序的问题呢?因为template插件在后面,覆盖了hosts插件的结果呢?实验一下。

创建 Corefile4,颠倒一下template和hosts的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
.:1053 {
whoami
template IN A example.com {
match .*\.example\.com
answer "{{ .Name }} 60 IN A 192.168.1.1"
fallthrough
}
hosts {
192.168.1.2 a.example.com
fallthrough
}
log
}

重新启动coredns

1
coredns -conf ./Corefile4

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dig @127.0.0.1 -p 1053 a.example.com

; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 1053 a.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4163
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.example.com. IN A

;; ANSWER SECTION:
a.example.com. 60 IN A 192.168.1.1

;; Query time: 0 msec
;; SERVER: 127.0.0.1#1053(127.0.0.1)
;; WHEN: Thu Nov 23 11:21:59 CST 2023
;; MSG SIZE rcvd: 71

发现结果没有变化。

这是因为:template和hosts插件同时使用时,template的优先级更高,执行的顺序是先执行hosts 插件,后执行template 插件。源码:plugin.cfg

注意注释:

1
2
3
4
5
6
7
8
# Directives are registered in the order they should be executed.
#
# Ordering is VERY important. Every plugin will feel the effects of all other
# plugin below (after) them during a request, but they must not care what plugin
# above them are doing.

指令按照它们应该执行的顺序进行注册。
顺序非常重要。在一个请求期间,每个插件都会感受到所有其它在它们之后(下方)的插件的影响,但是它们不必关心在上面的插件正在做什么。

翻译一下就是:hosts插件不能关注到template插件所做的变更,但template插件能够改变hosts插件所做的改变。

如何解决

第1种方法是改变coredns插件的顺序,这个需要自己更改代码并编译coredns,一般不建议。

第2种方法是新起一个端口来提供服务。
创建 Corefile5 ,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.:1053 {
whoami
hosts {
192.168.1.2 a.example.com
fallthrough
}
forward . 127.0.0.1:2053
log
}

.:2053 {
whoami
template IN A example.com {
match .*\.example\.com
answer "{{ .Name }} 60 IN A 192.168.1.1"
fallthrough
}
log
}

启动coredns

1
2
3
4
5
coredns -conf ./Corefile5
.:1053
.:2053
CoreDNS-1.11.1
darwin/arm64, go1.21.0,

测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dig @127.0.0.1 -p 1053 a.example.com

; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 1053 a.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60952
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.example.com. IN A

;; ANSWER SECTION:
a.example.com. 3600 IN A 192.168.1.2

;; Query time: 3 msec
;; SERVER: 127.0.0.1#1053(127.0.0.1)
;; WHEN: Thu Nov 23 11:51:35 CST 2023
;; MSG SIZE rcvd: 71

发现解析地址已经变为 a.example.com. 3600 IN A 192.168.1.2,符合预期了。

这种方法的弊端是要多发起一次请求,性能有所下降。

有没有其它更好的方法?有的,使用file插件。

使用 file 插件

fiel 插件允许使用一个 zone 文件来解析泛域名和指定域名。

首先创建 example.db 的配置文件:

1
2
3
4
5
6
7
8
9
10
11
$TTL    3600
$ORIGIN example.com.
@ IN SOA ns.example.com. contact.example.com. (
2023112301 ; serial
1d ; refresh
2h ; retry
4w ; expire
1h ; nxdomain ttl
)
a.example.com. IN A 192.168.1.2
*.example.com. IN A 192.168.1.1

创建 Corefile6,内容如下:

1
2
3
4
5
.:1053 {
whoami
file ./example.db
log
}

启动coredns

1
coredns -conf ./Corefile6

然后查一下 a.example.com 和 b.example.com 的解析:

1
2
3
4
5
6
7
8
9
10
11
dig @127.0.0.1 -p 1053 a.example.com
......
;; ANSWER SECTION:
a.example.com. 3600 IN A 192.168.1.2
......


dig @127.0.0.1 -p 1053 b.example.com
......
;; ANSWER SECTION:
b.example.com. 3600 IN A 192.168.1.1

可以看到是符合预期的。

作者

David

发布于

2023-11-23

更新于

2023-11-25

许可协议

# 相关文章
  1.DNS 基础知识
评论

:D 一言句子获取中...