BIND9詳解
ISC的bind一直以來基本上都是DNS的工業標准,不過BIND一直是漏洞不斷,直到出了BIND9,isc的開發人員對bind9進行了重寫,才相對好了一點。
BIND9的安裝就不用多說了,這里使用最新版本9.2.3,說白了也就是需要named這個可執行文件就可以了,其他的配置文件完全可以自己來寫。如果需要進行服務的控制的話,則需要rndc這個文件了。named大約有4M多,strip一下也就1M多點,再裁減裁減完全可以做到400K的,做嵌入式的朋友也不妨考慮考慮這個了。
服務的啟動與停止可以完全自己來寫一個腳本來控制,啟動的話先判斷是否已經啟動,pidof named
,如果已經啟動,則提示已經啟動,否則執行named –c /etc/named.conf
,停止的時候先判斷是否已經啟動,是的話則killproc named
,否的話提示沒有啟動,具體可在網上查找。
下面重點來說說BIND9的新功能.
name.conf
named.conf
是bind9
的最先讀取的一個文件,named
支持如下語句:
- Acl
- Controls
- Include
- Key
- Logging
- Lwres
- Options
- Server
- Trusted-keys
- View
- Zone
其中主要的是 acl
,controls
,include
,logging
,key
,options
,view
,zone
其他的很少用到我們就來詳細的對這些進行解釋一下.
acl
acl 用來對bind的訪問進行限制,是一個全局的設置,前面配置的acl
在整個bind
中都適用,和路由器里面的access-list
有同工之處,語法是
acl acl-name {
address_match_list
};
其中的address_match_list
是一個地址列表,如192.168.0.0/24;
,記住最后一定得有分號,有多個的話中間用分號格開,如192.168.0.0/32;192.168.1.0/24;
bind內置了4個acl分別是:
any
:對應所有的,也就是0.0.0.0/0.none
:對應為空.localhost
:對應本地機器.localnets
:對應本地網絡.
controls
controls主要用於對bind進行控制,如:
key "rndc-key" {
algorithm hmac-md5;
secret "VkMaNHXfOiPQqcMVYJRyjQ==";
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
設置rndc
控制的端口以及端口,keys
用來設置控制的密鑰
include
include是一個非常有用的選項,如果需要寫程序來讀寫bind的配置文件,這個將會用到,因為bind的配置文件很不規則,但是用了include后,就可以變的很規則,就和數據庫一樣了,功用和c語言里面的include
一樣。
用於導入拆分的配置文件。
options
options是用於設置bind的一些選項,我們將重點介紹,BING9支持的選項如下:
options {
additional-from-auth boolean;
additional-from-cache boolean;
// *allow-recursion允許遞歸查詢的地址列表(allow-recursion):設置允許進行遞歸查詢的ip地址列表,缺省值是允許所有地址進行查詢,需要注意的是當設置了不允許遞歸查詢后,如果仍然能夠查詢部分外部的域名,那是因為dns的緩存在起作用,將緩存清除以后就可以了。
allow-recursion { address_match_element; };
allow-v6-synthesis { address_match_element; };
// *allow-query 允許普通查詢的地址列表(allow-query):設置允許進行普通查詢的ip地址列表,在域中的設置將覆蓋全局設置,默認情況下是允許所有的地址進行普通查詢。
allow-query { address_match_element; };
// *allow-transfer允許服務器進行區域傳輸的地址列表(Allow-transfer):(注意的是視區和域中的設置將覆蓋全局設置)
allow-transfer { address_match_element; ... };
allow-update-forwarding { address_match_element; ... };
// *allow-notify 允許更新通知的地址列表(allow-notify),當服務器作為輔助服務器的時候,設置這個可以對收到的更新通知進行判斷,只是接收該列表的更新通知.默認情況下,只是接收來自主服務器的更新通知。對於其他服務器的更新通知,會忽略掉.
allow-notify { address_match_element; ... };
// *auth-nxdomain 是否做為權威服務器回答域不存在(Auth-nxdomain)
如果設置為'yes',則允許服務器以權威性(authoritatively)的方式返回NXDOMAIN(該域不存在)的回答,否則就不會作權威性的回答,缺省值為”是”.
auth-nxdomain boolean; // default changed
// *blockhole 定義服務器不對查詢進行反應的地址列表,也就是”黑名單”,比如說3721的ip段:218.244.44.0/24,當設置了黑名單后,對於這個段的請求查詢,服務器將不會作出反應.
blackhole { address_match_element; };
coresize size;
datasize size;
deallocate-on-exit boolean; // obsolete
// *directory 設置bind的數據文件的存放位置:如 directory “/var/named”.
directory quoted_string;
// *dump-file 設置當執行rndc dumpdb命令后的導出文件存放絕對路徑,如果沒有指定的話,缺省文件為named_dump.db,放在directory指定的目錄下面.
dump-file quoted_string;
fake-iquery boolean; // obsolete
files size;
has-old-clients boolean; // obsolete
heartbeat-interval integer;
host-statistics boolean; // not implemented
// *interface-interval 設置bind檢查網卡變化的周期.
interface-interval integer;
// *listen-on 設置bind的綁定ip和端口,如listen-on 53 {192.168.0.1;};
listen-on [ port integer ] { address_match_element; ... };
listen-on-v6 [ port integer ] { address_match_element; ... };
match-mapped-addresses boolean;
memstatistics-file quoted_string; // not implemented
multiple-cnames boolean; // obsolete
named-xfer quoted_string; // obsolete
// *pid-file 設置bind的進程號pid文件.
pid-file quoted_string;
port integer;
random-device quoted_string;
recursive-clients integer;
rrset-order { [ class string ] [ type string ] [ name
quoted_string ] string string; ... }; // not implemented
serial-queries integer; // obsolete
serial-query-rate integer;
stacksize size;
statistics-file quoted_string;
statistics-interval integer; // not yet implemented
tcp-clients integer;
tkey-dhkey quoted_string integer;
tkey-gssapi-credential quoted_string;
tkey-domain quoted_string;
transfers-per-ns integer;
transfers-in integer;
transfers-out integer;
treat-cr-as-space boolean; // obsolete
use-id-pool boolean; // obsolete
use-ixfr boolean;
// *version 設置客戶查詢DNS版本好的返回信息,如果不想讓客戶探測到當前的版本好,就用這個好了,如version mydns1.0;
version quoted_string;
sortlist { address_match_element; ... };
topology { address_match_element; ... }; // not implemented
minimal-responses boolean;
// *recursion 是否允許遞規查詢(recursion)如果設置為”yes”,則允許服務器采用遞歸的方式進行查詢,也就是當要查詢的地址不在服務器的數據庫列表中時,服務器將一級一級的查詢,直到查到為止(一般對局域網都打開)。設置為”no”,並不意味着服務器對於請求的遞歸查詢不給予回答,而是對於請求的遞歸查詢,不再向上級服務器請求,也不緩存,如果不對請求的遞歸查詢回答,可以清空緩存,然后設置為“NO”。
recursion boolean;
provide-ixfr boolean;
request-ixfr boolean;
fetch-glue boolean; // obsolete
rfc2308-type1 boolean; // not yet implemented
query-source querysource4;
query-source-v6 querysource6;
cleaning-interval integer;
min-roots integer; // not implemented
lame-ttl integer;
max-ncache-ttl integer;
max-cache-ttl integer;
transfer-format ( many-answers | one-answer );
// *max-cache-size 設置最大緩存的大小,如max-cache-size 5M
max-cache-size size_no_default;
check-names string string; // not implemented
cache-file quoted_string;
// *notify 在主服務器更新時是否通知輔助服務器(notify)
如果設置為”yes”,則在主服務器區域數據發生變化時,就會向在域的”域名服務器“中列出的服務器和“亦通知”中列出的服務器發送更新通知。這些服務器接受到更新通知后,就會向主服務器發送請求傳輸的消息,然后區域文件得以更新。
notify notifytype;
notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
// *also-notify 更新時亦通知下列地址(also-notify),設置發送更新通知的時候,不僅是域名服務器中列出的地址,亦通知此地址列表中的地址。
also-notify [ port integer ] { ( ipv4_address | ipv6_address ) [ port integer ]; };
dialup dialuptype;
// *forward 值有first和only兩項, first則首先轉發到"forwarders"中的服務器,然后自己查詢,only則僅轉發到 "轉發服務器列表"中的服務器,不再自己查詢
forward ( first | only );
// *forwarders設置轉發服務器地址列表,語法同acl中的語法.
forwarders [ port integer ] { ( ipv4_address | ipv6_address ) [ port integer ]; };
maintain-ixfr-base boolean; // obsolete
max-ixfr-log-size size; // obsolete
transfer-source ( ipv4_address | * ) [ port ( integer | * ) ];
transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
max-transfer-time-in integer;
max-transfer-time-out integer;
max-transfer-idle-in integer;
max-transfer-idle-out integer;
max-retry-time integer;
min-retry-time integer;
max-refresh-time integer;
min-refresh-time integer;
sig-validity-interval integer;
zone-statistics boolean;
};
obsolete
是已經過時的選項,這里不用考慮,not yet implemented
是尚未完成的選項,這里也不用考慮,下面詳細介紹這里面的有用選項
注意,前面打*
的為選項
view
view(視)是bind9中提出的一個新概念,在這里可以理解為”從不同的眼光來看dns”,在這里view
這個詞可真是取的經典呀,具體而已,就是根據不同的源地址,目的地址,解析請求來判斷該給客戶提供什么樣的解析.其語法如下:
view string optional_class {
match-clients { address_match_element; ... };
match-destinations { address_match_element; ... };
match-recursive-only boolean;
key string {
algorithm string;
secret string;
};
zone string optional_class {
type ( master | slave | stub | hint | forward );
allow-update { address_match_element; };
file quoted_string;
ixfr-base quoted_string; // obsolete
ixfr-tmp-file quoted_string; // obsolete
masters [ port integer ] { ( ipv4_address |
ipv6_address ) [ port integer ] [ key string ]; };
pubkey integer integer integer quoted_string; // obsolete
update-policy { ( grant | deny ) string ( name |
subdomain | wildcard | self ) string rrtypelist; };
database string;
check-names string; // not implemented
allow-query { address_match_element; ... };
allow-transfer { address_match_element; ... };
allow-update-forwarding { address_match_element; ... };
allow-notify { address_match_element; ... };
notify notifytype;
notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
also-notify [ port integer ] { ( ipv4_address | ipv6_address )
[ port integer ]; };
dialup dialuptype;
forward ( first | only );
forwarders [ port integer ] { ( ipv4_address |
ipv6_address ) [ port integer ]; ... };
maintain-ixfr-base boolean; // obsolete
max-ixfr-log-size size; // obsolete
transfer-source ( ipv4_address | * ) [ port ( integer | * ) ];
transfer-source-v6 ( ipv6_address | * ) [ port (integer | * ) ];
max-transfer-time-in integer;
max-transfer-time-out integer;
max-transfer-idle-in integer;
max-transfer-idle-out integer;
max-retry-time integer;
min-retry-time integer;
max-refresh-time integer;
min-refresh-time integer;
sig-validity-interval integer;
zone-statistics boolean;
};
server {
bogus boolean;
provide-ixfr boolean;
request-ixfr boolean;
support-ixfr boolean; // obsolete
transfers integer;
transfer-format ( many-answers | one-answer );
keys server_key;
edns boolean;
};
trusted-keys { string integer integer integer
quoted_string; };
allow-recursion { address_match_element; ... };
allow-v6-synthesis { address_match_element; ... };
sortlist { address_match_element; ... };
topology { address_match_element; ... }; // not implemented
auth-nxdomain boolean; // default changed
minimal-responses boolean;
recursion boolean;
provide-ixfr boolean;
request-ixfr boolean;
fetch-glue boolean; // obsolete
rfc2308-type1 boolean; // not yet implemented
additional-from-auth boolean;
additional-from-cache boolean;
query-source querysource4;
query-source-v6 querysource6;
cleaning-interval integer;
min-roots integer; // not implemented
lame-ttl integer;
max-ncache-ttl integer;
max-cache-ttl integer;
transfer-format ( many-answers | one-answer );
max-cache-size size_no_default;
check-names string string; // not implemented
cache-file quoted_string;
allow-query { address_match_element; ... };
allow-transfer { address_match_element; ... };
allow-update-forwarding { address_match_element; ... };
allow-notify { address_match_element; ... };
notify notifytype;
notify-source ( ipv4_address | * ) [ port ( integer | * ) ];
notify-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
also-notify [ port integer ] { ( ipv4_address | ipv6_address
) [ port integer ]; ... };
dialup dialuptype;
forward ( first | only );
forwarders [ port integer ] { ( ipv4_address | ipv6_address )
[ port integer ]; ... };
maintain-ixfr-base boolean; // obsolete
max-ixfr-log-size size; // obsolete
transfer-source ( ipv4_address | * ) [ port ( integer | * ) ];
transfer-source-v6 ( ipv6_address | * ) [ port ( integer | * ) ];
max-transfer-time-in integer;
max-transfer-time-out integer;
max-transfer-idle-in integer;
max-transfer-idle-out integer;
max-retry-time integer;
min-retry-time integer;
max-refresh-time integer;
min-refresh-time integer;
sig-validity-interval integer;
zone-statistics boolean;
};
其中:
match-clients
,指的是view對應的源地址,match-destinations
指的是view對應的目的地址,match-recursive-only
指的是view對應是否僅僅是遞歸請求。
BIND在收到DNS的解析請求后,會首先判斷該請求包的源地址和目標地址,然后根據視區里面的match-clients
和match-destinations
和match-recursive-only
,判斷是否屬於第一個視區,符合的話就用第一個視區來進行解析,否則就判斷下一個視區。然后再進行解析。如果所有的視區都不能對應,則DNS將返回Query refused
的消息。
這樣在防火牆的情況下,就有一個很好的解決辦法了,比如一個典型的網絡結構下,DMZ區全部在防火牆外網口上做的地址映射(DNAT),當DMZ區要訪問本地網絡的時候,單純用傳統的域名解析的話,是無法達到要求的,因為防火牆無法同時又做SNAT和DNAT,比如DMZ地址192.168.0.14
映射到外部地址202.196.160.14
,而域名服務器解析www.yourdomain.com
到202.196.160.14
,則192.168.0.0/24
的網絡將無法訪問www.yourdomain.com
,但是當用了VIEW后,你可以對來自該網絡的解析請求將www.yourdomain.com
直接解析到192.168.0.14
,這樣就可以訪問了。
view里面可以包含zone
,優先級是zoneviewoptions
,zone
里面的選項好多和options
里面一樣,不過它只是對本zone
一樣,同樣view里面的選項也只是對本view有效。
zone
是bind的一個重要選項,不過關於zone
網上的文章很多,在這里只是補充幾點小技巧:
如何將域名直接解析為www服務器的地址,比如像freshmeat.net
那樣直接解析freshmeat.net
為www.freshmeat.net
,這里可以在域的數據文件里面增加一個這樣的地址記錄:
@ IN A 202.196.160.14
這樣的主機記錄就可以實現了,202.196.160.14
為www
服務器的ip地址。
常見故障釋疑
- 在用nslookup查詢域的時候出現如下錯誤:
Can't find server name for address *.*.*.*: Non-existent domain
,這種情況是沒有對域名服務器本身做反向地址解析造成的,給域名服務器增加一條反向地址解析就可以了。 - 在用nslookup時出現如下錯誤:
DNS request timed out.timeout was 2 seconds.DNS request timed out.
這種情況一般是在DNS進行遞歸查詢的時候,超時造成的,可能是由於網絡速度問題,也可能是路由等其他問題,或者對方域名服務器沒有響應造成的. - 在用nslookup時出現如下錯誤:
xxx dns.cbchen.com can't find www.ite.com: Non-existent domain
,這種情況一般是域中沒有該地址記錄或沒有別名記錄. - 在用nslookup時出現如下錯誤:
***.server failed
一般是配置問題,請檢測配置,或者是輔助域無法從主域中得到數據,再請求輔助域的時候會出現這種故障.
BIND的有用的網站:
強烈推薦BIND9解壓目錄下的/doc/arm管理員手冊
其他第三方DNS服務器軟件:
- MaraDNS,安全的嵌入式DNS. http://www.maradns.org/
- OakDNS 用python寫的,和bind的區域文件和cache兼容,地址: http://www.digitallumber.com/oak
- PowerDNS 一個僅支持認證的DNS,http://www.powerdns.org/
- MYDNS以mysql作為后台的認證DNS,http://mydns.bboy.net/