FreeBSD 在默认情况下使用一个版本的 BIND (Berkeley Internet Name Domain), 这是目前最为流行的 DNS 协议实现。 DNS 是一种协议, 可以通过它将域名同 IP 地址相互对应。 例如, 查询 www.FreeBSD.org 将得到 FreeBSD Project 的 web 服务器的 IP 地址, 而查询 ftp.FreeBSD.org 则将得到响应的 FTP 机器的 IP 地址。 类似地, 也可以做相反的事情。 查询 IP 地址可以得到其主机名。 当然, 完成 DNS 查询并不需要在系统中运行域名服务器。
DNS 在 Internet 上通过一组略显复杂的权威根域名服务器来组织, 它的其余部分则由较小规模的域名服务器组成, 这些服务器提供少量的域名解析服务, 并对域名信息进行缓存。
这份文档介绍了 BIND 8.x, 它是 FreeBSD 先前版本所采用的稳定版本。 BIND 9.x 可以通过 net/bind9 port 来安装到 FreeBSD 上, 而从 5.3-RELEASE 开始, 它成为了基本系统的一部分。
RFC1034 和 RFC1035 定义了 DNS 协议。
目前, BIND 由 Internet Software Consortium http://www.isc.org/ 维护。
要理解这份文档, 需要首先了解一些相关的 DNS 术语。
术语 | 定义 |
---|---|
正向 DNS (Forward DNS) | 将域名映射到 IP 地址 |
原点 (Origin) | 表示特定域文件所在的域 |
named, BIND, 域名服务器(name server) | 在 FreeBSD 中 BIND 域名服务器软件包的常见叫法 |
解析器 (Resolver) | 计算机用以向域名服务器查询域名信息的一个系统进程 |
反向 DNS (Reverse DNS) | 与正向 DNS 相对; 将 IP 地址映射为主机名 |
根域 | Internet 域层次的起点。 所有的域都在根域之下, 类似文件系统中, 文件都在根目录之下那样。 |
域 (Zone) | 独立的域, 子域, 或者由同一机构管理的 DNS 的一部分。 |
域的例子:
. 是根域。
org. 是一个根域下的域。
example.org 是 org. 域之下的域。
foo.example.org. 是 example.org. 域的子域。
1.2.3.in-addr.arpa 是用于表达 3.2.1.* IP 地址空间之下所有 IP 地址的域。
如您所见, 域名中最细节的部分在它的左边。 举例来说, example.org. 要比 org. 更小, 就像 org. 要比根域更小一样。 主机名的格局和文件系统类似: /dev 目录在根目录中, 等等。
域名服务器通常会有两种形式: 权威域名服务器, 以及缓存域名服务器。
下列情况需要有权威域名服务器:
想要向全世界提供 DNS 信息, 并对请求给出权威应答。
注册了类似 example.org 的域, 而需要将 IP 指定到其下的主机名上。
某个 IP 地址块需要反向 DNS 项 (IP 到主机名)。
需要备份服务器, 或常说的从 (slave) 服务器, 在主服务器出现问题或无法访问时来应答查询请求。
下列情况需要有缓存域名服务器:
本地的 DNS 服务器能够缓存, 并比直接向外界的域名服务器请求更快地得到应答。
减少所需的总体网络流量 (DNS 流量通常占全部 Internet 流量的 5% 或更多)。
当有人查询 www.FreeBSD.org 时,解析器通常会向上级 ISP 的域名服务器发出请求, 并获得回应。 如果有本地的缓存 DNS 服务器, 查询只有在第一次被缓存 DNS 服务器发到外部世界。 其他的查询不会发向局域网外, 因为它们已经有在本地的缓存了。
在 FreeBSD 中, BIND 服务程序被称为 named, 其原因显而易见。
域文件通常被放在 /etc/namedb 目录中, 它们包含域名服务器所提供的 DNS 域的信息。
由于 BIND 会在默认情况下安装, 因此配置它相对而言很简单。
要确保 named 服务程序在引导时被自动启动, 把下面的行加到 /etc/rc.conf 中:
named_enable="YES"
要手工启动服务 (在完成配置之后):
# ndc start
一定要:
# cd /etc/namedb # sh make-localhost
以便创建正确的本地 DNS 反向解析域文件 /etc/namedb/localhost.rev。
// $FreeBSD$ // // Refer to the named(8) manual page for details. If you are ever going // to setup a primary server, make sure you've understood the hairy // details of how DNS is working. Even with simple mistakes, you can // break connectivity for affected parties, or cause huge amount of // useless Internet traffic. options { directory "/etc/namedb"; // In addition to the "forwarders" clause, you can force your name // server to never initiate queries of its own, but always ask its // forwarders only, by enabling the following line: // // forward only; // If you've got a DNS server around at your upstream provider, enter // its IP address here, and enable the line below. This will make you // benefit from its cache, thus reduce overall DNS traffic in the Internet. /* forwarders { 127.0.0.1; }; */
如注视所说, 要从上级的缓存中受益, 可以在此处启用 forwarders。 在一般情况下, 域名服务器会逐级地查询 Internet 来找到特定的域名服务器, 直到得到答案为止。 启用这个将让它首先查询上级域名服务器 (或另外提供的域名服务器), 从而从它们的缓存中得到结果。 如果上级域名服务器的负载很重, 在更快的域名服务器上启用它将有助于改善服务品质。
Warning127.0.0.1 不会 正常工作。 一定要把地址改为您上级服务器的 IP 地址。
/* * If there is a firewall between you and name servers you want * to talk to, you might need to uncomment the query-source * directive below. Previous versions of BIND always asked * questions using port 53, but BIND 8.1 uses an unprivileged * port by default. */ // query-source address * port 53; /* * If running in a sandbox, you may have to specify a different * location for the dumpfile. */ // dump-file "s/named_dump.db"; }; // Note: the following will be supported in a future release. /* host { any; } { topology { 127.0.0.0/8; }; }; */ // Setting up secondaries is way easier and the rough picture for this // is explained below. // // If you enable a local name server, don't forget to enter 127.0.0.1 // into your /etc/resolv.conf so this server will be queried first. // Also, make sure to enable it in /etc/rc.conf. zone "." { type hint; file "named.root"; }; zone "0.0.127.IN-ADDR.ARPA" { type master; file "localhost.rev"; }; zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.INT" { type master; file "localhost.rev"; }; // NB: Do not use the IP addresses below, they are faked, and only // serve demonstration/documentation purposes! // // Example secondary config entries. It can be convenient to become // a secondary at least for the zone where your own domain is in. Ask // your network administrator for the IP address of the responsible // primary. // // Never forget to include the reverse lookup (IN-ADDR.ARPA) zone! // (This is the first bytes of the respective IP address, in reverse // order, with ".IN-ADDR.ARPA" appended.) // // Before starting to setup a primary zone, better make sure you fully // understand how DNS and BIND works, however. There are sometimes // unobvious pitfalls. Setting up a secondary is comparably simpler. // // NB: Don't blindly enable the examples below. :-) Use actual names // and addresses instead. // // NOTE!!! FreeBSD runs BIND in a sandbox (see named_flags in rc.conf). // The directory containing the secondary zones must be write accessible // to BIND. The following sequence is suggested: // // mkdir /etc/namedb/s // chown bind:bind /etc/namedb/s // chmod 750 /etc/namedb/s
For more information on running BIND in a sandbox, see Running named in a sandbox.
/* zone "example.com" { type slave; file "s/example.com.bak"; masters { 192.168.1.1; }; }; zone "0.168.192.in-addr.arpa" { type slave; file "s/0.168.192.in-addr.arpa.bak"; masters { 192.168.1.1; }; }; */
在 named.conf 中, 这是一些转发用的从域以及反向域的例子。
对于每一个新域, 域对应的项必须加到 named.conf 中。
例如, 最简单的用于 example.org 域的条目类似下面的样子:
zone "example.org" { type master; file "example.org"; };
这是一个主域, 它由 type 语句标识出来, 而信息则在 /etc/namedb/example.org 域文件中, 这是由 file 语句指定的。
zone "example.org" { type slave; file "example.org"; };
在从域的例子中, 域的信息从该域的某个主服务器传送过来, 并保存在指定的文件中。 如果主服务器死掉了或不可达, 从域名服务器将使用这些传过来的域信息, 从而完成应答。
以下是一个用于 example.org 域的主域文件 (保存为 /etc/namedb/example.org):
$TTL 3600 example.org. IN SOA ns1.example.org. admin.example.org. ( 5 ; Serial 10800 ; Refresh 3600 ; Retry 604800 ; Expire 86400 ) ; Minimum TTL ; DNS Servers @ IN NS ns1.example.org. @ IN NS ns2.example.org. ; Machine Names localhost IN A 127.0.0.1 ns1 IN A 3.2.1.2 ns2 IN A 3.2.1.3 mail IN A 3.2.1.10 @ IN A 3.2.1.30 ; Aliases www IN CNAME @ ; MX Record @ IN MX 10 mail.example.org.
请注意以 “.” 结尾的主机名是全称主机名, 而结尾没有 “.” 的则是相对于原点的主机名。 例如, www 将被转换为 www.原点. 在这个假想的域信息文件中, 我们的原点是 example.org., 因此 www 将被当作 www.example.org.。
域信息文件的格式如下:
记录名 IN 记录类型 值
最常用的 DNS 记录:
域权威开始
权威域名服务器
主机地址
别名对应的正规名称
邮件传递服务器
域名指针 (用于反向 DNS)
example.org. IN SOA ns1.example.org. admin.example.org. ( 5 ; Serial 10800 ; Refresh after 3 hours 3600 ; Retry after 1 hour 604800 ; Expire after 1 week 86400 ) ; Minimum TTL of 1 day
域名, 同时也是这个域信息文件的原点。
该域的主/权威域名服务器。
此域的负责人的电子邮件地址, 其中 “@” 被换掉了。 (<[email protected]>
对应 admin.example.org)
文件的序号。 每次修改域文件时都必须增加这个数字。 现今, 许多管理员会考虑使用 yyyymmddrr 这样的格式来表示序号。 2001041002 通常表示上次修改于 04/10/2001, 而后面的 02 则表示在那天的第几次修改。 序号非常重要, 它用于通知从域服务器更新数据。
@ IN NS ns1.example.org.
这是一个 NS 项。 每个准备提供权威应答的服务器都必须有一个对应项。 这里的 @ 表示 example.org.。 @ 会被理解为原点。
localhost IN A 127.0.0.1 ns1 IN A 3.2.1.2 ns2 IN A 3.2.1.3 mail IN A 3.2.1.10 @ IN A 3.2.1.30
A 记录代表及其名。 如上面看到的, ns1.example.org 将解析为 3.2.1.2。 在此再次使用了原点符, @, 它表示 example.org 应解析为 3.2.1.30。
www IN CNAME @
正规名记录通常用于对某台机器的别名给出对应的正式名字。 在这个例子中, www 是名字为原点, 或者说 example.org (3.2.1.30) 那台机器的别名。 CNAMEs 可以用来提供主机的别名, 或将同一名字在多台机器上作轮询。
@ IN MX 10 mail.example.org.
MX 记录表示哪个邮件服务器负责接收发到这个域的邮件。 mail.example.org 是邮件服务器的主机名, 而 10 则是它的优先级。
可以有多台邮件服务器, 其优先级分别是 3, 2, 1。 向 example.org 进行投递的邮件服务器首先会尝试优先级最高 (数字最小) 的 MX, 然后是较低优先级的, 等等, 直到成功地投递了邮件为止。
对于 in-addr.arpa 域名信息文件 (反向 DNS), 使用了同样的格式, 只是 PTR 项代替了 A 或 CNAME 的位置。
$TTL 3600 1.2.3.in-addr.arpa. IN SOA ns1.example.org. admin.example.org. ( 5 ; Serial 10800 ; Refresh 3600 ; Retry 604800 ; Expire 3600 ) ; Minimum @ IN NS ns1.example.org. @ IN NS ns2.example.org. 2 IN PTR ns1.example.org. 3 IN PTR ns2.example.org. 10 IN PTR mail.example.org. 30 IN PTR example.org.
这个文件给出了上述假想域中 IP 地址到域名的映射关系。
缓存域名服务器是对任何域都不提供权威解析的域名服务器。 它自己简单地完成查询, 并记住这些查询以备后续使用。 要建立这样的服务器, 只需像平时一样配置一个域名服务器, 而不配置域就可以了。
要更安全地运行 named(8), 应该以非特权用户来运行它, 并配置为 chroot(8) 到一个沙盒目录中。 这使得 named 服务无法访问任何沙盒外面的东西。 假如 named 被攻破, 这将减少它所能带来的破坏。 默认情况下, FreeBSD 提供了名为 bind 的用户和组来完成这样的目的。
Note: 许多人建议不这样做, 而 named 配置为 chroot, 您应该在一个 jail(8) 中运行 named。 这一节并不涵盖这种情形。
由于 named 没有办法访问沙盒外面的任何东西 (例如共享库, 日志 socket 等等), 您需要做许多事情来让 named 正常工作。 下面的清单假定沙盒是 /etc/namedb 而您没有事先改过这个目录中的内容。 以 root 的身份完成下列步骤:
创建 named 需要访问的所有目录:
# cd /etc/namedb # mkdir -p bin dev etc var/tmp var/run master slave # chown bind:bind slave var/*
重新组织基本的域和配置文件:
# cp /etc/localtime etc # mv named.conf etc && ln -sf etc/named.conf # mv named.root master # sh make-localhost && mv localhost.rev localhost-v6.rev master # cat > master/named.localhost $ORIGIN localhost. $TTL 6h @ IN SOA localhost. postmaster.localhost. ( 1 ; serial 3600 ; refresh 1800 ; retry 604800 ; expiration 3600 ) ; minimum IN NS localhost. IN A 127.0.0.1 ^D
如果您在运行 FreeBSD 在 4.9-RELEASE 之前的版本, 需要联编一个静态连接的 named-xfer, 并将其复制到沙盒中:
# cd /usr/src/lib/libisc # make cleandir && make cleandir && make depend && make all # cd /usr/src/lib/libbind # make cleandir && make cleandir && make depend && make all # cd /usr/src/libexec/named-xfer # make cleandir && make cleandir && make depend && make NOSHARED=yes all # cp named-xfer /etc/namedb/bin && chmod 555 /etc/namedb/bin/named-xfer
在把静态连接的 named-xfer 装好之后需要清理一下, 以免将过时的库或程序留在您的源代码副本中:
# cd /usr/src/lib/libisc # make cleandir # cd /usr/src/lib/libbind # make cleandir # cd /usr/src/libexec/named-xfer # make cleandir
如果您运行 FreeBSD 的 4.9-RELEASE 或更新的版本, 则默认情况下 /usr/libexec 中的 named-xfer 副本已经是静态连接的了。 您可以简单地把它用 cp(1) 复制到沙盒中。
做一个 named 能够看到并写入的 dev/null:
# cd /etc/namedb/dev && mknod null c 2 2 # chmod 666 null
将 /var/run/ndc 符号链接到 /etc/namedb/var/run/ndc:
# ln -sf /etc/namedb/var/run/ndc /var/run/ndc
Note: 这主要是避免每次都不得不指定 ndc(8) -c 的选项。 由于 /var/run 会在每次启动时删除, 如果您发现这是您在每次启动时都需要做的事情, 则可以在 root 的 crontab 中增加相应的条目, 并使用 @reboot 选项。 参见 crontab(5) 以了解更多细节。
配置 syslogd(8) 来创建一个 named 可以写的 log socket。 要完成它, 需要将 -l /etc/namedb/dev/log 加到 /etc/rc.conf 的 syslogd_flags 变量中。
启动 named 并让它自动地把自己 chroot 到沙盒中, 方法是把下面的内容加到 /etc/rc.conf:
named_enable="YES" named_flags="-u bind -g bind -t /etc/namedb /etc/named.conf"
Note: 请注意配置文件 /etc/named.conf 是以 相对于沙盒 的完整路径来指定的, 例如上面那一行, 文件所在的目录实际上是 /etc/namedb/etc/named.conf。
下一步是编辑 /etc/namedb/etc/named.conf 让 named 直到需要加载哪些域, 以及它们在磁盘上的位置。 您可以用注释掉的那个例子 (没有明确地注释掉的哪些和不在沙盒中运行 DNS 服务器时的配置无异):
options { directory "/"; named-xfer "/bin/named-xfer"; version ""; // Don't reveal BIND version query-source address * port 53; }; // ndc control socket controls { unix "/var/run/ndc" perm 0600 owner 0 group 0; }; // Zones follow: zone "localhost" IN { type master; file "master/named.localhost"; allow-transfer { localhost; }; notify no; }; zone "0.0.127.in-addr.arpa" IN { type master; file "master/localhost.rev"; allow-transfer { localhost; }; notify no; }; zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int" { type master; file "master/localhost-v6.rev"; allow-transfer { localhost; }; notify no; }; zone "." IN { type hint; file "master/named.root"; }; zone "private.example.net" in { type master; file "master/private.example.net.db"; allow-transfer { 192.168.10.0/24; }; }; zone "10.168.192.in-addr.arpa" in { type slave; masters { 192.168.10.2; }; file "slave/192.168.10.db"; };
完成这些配置之后, 您可以重新启动服务器, 或重启 syslogd(8) 服务并启动 named(8), 以确认 syslogd_flags 和 named_flags 的新值生效了。 现在您应该已经在沙盒中运行 named 了!
尽管 BIND 是最为常用的 DNS 实现, 但它总是有一些安全问题。 时常会有人发现一些可能的甚至可以利用的安全漏洞。
经常阅读 CERT 的安全公告并订阅 FreeBSD 安全问题通知邮件列表 会是一个帮助您时刻了解最新 Internet 和 FreeBSD 安全问题的好习惯。
Tip: 如果出现了问题, 将代码升级到最新版本并重新联编 named 不会带来任何麻烦。
BIND/named 联机手册: ndc(8) named(8) named.conf(5)