23.6. 域名系统 (DNS)

Contributed by Chern Lee.

23.6.1. 纵览

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/ 维护。

23.6.2. 术语

要理解这份文档, 需要首先了解一些相关的 DNS 术语。

术语 定义
正向 DNS (Forward DNS) 将域名映射到 IP 地址
原点 (Origin) 表示特定域文件所在的域
named, BIND, 域名服务器(name server) 在 FreeBSD 中 BIND 域名服务器软件包的常见叫法
解析器 (Resolver) 计算机用以向域名服务器查询域名信息的一个系统进程
反向 DNS (Reverse DNS) 与正向 DNS 相对; 将 IP 地址映射为主机名
根域 Internet 域层次的起点。 所有的域都在根域之下, 类似文件系统中, 文件都在根目录之下那样。
域 (Zone) 独立的域, 子域, 或者由同一机构管理的 DNS 的一部分。

域的例子:

如您所见, 域名中最细节的部分在它的左边。 举例来说, example.org. 要比 org. 更小, 就像 org. 要比根域更小一样。 主机名的格局和文件系统类似: /dev 目录在根目录中, 等等。

23.6.3. 运行域名服务器的理由

域名服务器通常会有两种形式: 权威域名服务器, 以及缓存域名服务器。

下列情况需要有权威域名服务器:

下列情况需要有缓存域名服务器:

当有人查询 www.FreeBSD.org 时,解析器通常会向上级 ISP 的域名服务器发出请求, 并获得回应。 如果有本地的缓存 DNS 服务器, 查询只有在第一次被缓存 DNS 服务器发到外部世界。 其他的查询不会发向局域网外, 因为它们已经有在本地的缓存了。

23.6.4. DNS 如何运作

在 FreeBSD 中, BIND 服务程序被称为 named, 其原因显而易见。

文件 描述
named BIND 服务程序
ndc 域名服务控制程序
/etc/namedb BIND 存放域名信息的位置
/etc/namedb/named.conf 域名服务配置文件

域文件通常被放在 /etc/namedb 目录中, 它们包含域名服务器所提供的 DNS 域的信息。

23.6.5. 启动 BIND

由于 BIND 会在默认情况下安装, 因此配置它相对而言很简单。

要确保 named 服务程序在引导时被自动启动, 把下面的行加到 /etc/rc.conf 中:

named_enable="YES"

要手工启动服务 (在完成配置之后):

# ndc start

23.6.6. 配置文件

23.6.6.1. 使用 make-localhost

一定要:

# cd /etc/namedb
# sh make-localhost

以便创建正确的本地 DNS 反向解析域文件 /etc/namedb/localhost.rev

23.6.6.2. /etc/namedb/named.conf

// $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";
};

在从域的例子中, 域的信息从该域的某个主服务器传送过来, 并保存在指定的文件中。 如果主服务器死掉了或不可达, 从域名服务器将使用这些传过来的域信息, 从而完成应答。

23.6.6.3. 域信息文件

以下是一个用于 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 记录:

SOA

域权威开始

NS

权威域名服务器

A

主机地址

CNAME

别名对应的正规名称

MX

邮件传递服务器

PTR

域名指针 (用于反向 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
example.org.

域名, 同时也是这个域信息文件的原点。

ns1.example.org.

该域的主/权威域名服务器。

admin.example.org.

此域的负责人的电子邮件地址, 其中 “@” 被换掉了。 ( 对应 admin.example.org)

5

文件的序号。 每次修改域文件时都必须增加这个数字。 现今, 许多管理员会考虑使用 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 地址到域名的映射关系。

23.6.7. 缓存域名服务器

缓存域名服务器是对任何域都不提供权威解析的域名服务器。 它自己简单地完成查询, 并记住这些查询以备后续使用。 要建立这样的服务器, 只需像平时一样配置一个域名服务器, 而不配置域就可以了。

23.6.8. 在沙盒中运行 named

要更安全地运行 named(8), 应该以非特权用户来运行它, 并配置为 chroot(8) 到一个沙盒目录中。 这使得 named 服务无法访问任何沙盒外面的东西。 假如 named 被攻破, 这将减少它所能带来的破坏。 默认情况下, FreeBSD 提供了名为 bind 的用户和组来完成这样的目的。

Note: 许多人建议不这样做, 而 named 配置为 chroot, 您应该在一个 jail(8) 中运行 named。 这一节并不涵盖这种情形。

由于 named 没有办法访问沙盒外面的任何东西 (例如共享库, 日志 socket 等等), 您需要做许多事情来让 named 正常工作。 下面的清单假定沙盒是 /etc/namedb 而您没有事先改过这个目录中的内容。 以 root 的身份完成下列步骤:

下一步是编辑 /etc/namedb/etc/named.confnamed 直到需要加载哪些域, 以及它们在磁盘上的位置。 您可以用注释掉的那个例子 (没有明确地注释掉的哪些和不在沙盒中运行 DNS 服务器时的配置无异):

options {
        directory "/";(1)
        named-xfer "/bin/named-xfer";(2)
        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";(3)
        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";(4)
};
(1)
directory 语句被指定为 /, 因为所有的 named 需要在这个文件中 (这相当于在 “普通” 模式下运行时的 /etc/namedb)。
(2)
指定到 named-xfer 执行文件的完整路径 (相对 named 的参照系)。 这是必须的步骤, 因为 named 在默认情况下会从 /usr/libexec 查找 named-xfer
(3)
指定文件名 (相对于前面的 directory 语句指定的目录), named 将在这里查找域信息文件。
(4)
指定文件名 (相对于前面的 directory 语句指定的目录), named 将在这里写入成功地从主服务器拿到的域信息文件副本。 这使为什么我们在前面的步骤中将 slave 的属主改为 bind 的原因。

完成这些配置之后, 您可以重新启动服务器, 或重启 syslogd(8) 服务并启动 named(8), 以确认 syslogd_flagsnamed_flags 的新值生效了。 现在您应该已经在沙盒中运行 named 了!

23.6.9. 安全

尽管 BIND 是最为常用的 DNS 实现, 但它总是有一些安全问题。 时常会有人发现一些可能的甚至可以利用的安全漏洞。

经常阅读 CERT 的安全公告并订阅 FreeBSD 安全问题通知邮件列表 会是一个帮助您时刻了解最新 Internet 和 FreeBSD 安全问题的好习惯。

Tip: 如果出现了问题, 将代码升级到最新版本并重新联编 named 不会带来任何麻烦。

23.6.10. 进一步阅读

BIND/named 联机手册: ndc(8) named(8) named.conf(5)