BIND(Berkeley Internet Name Domain)是全世界最廣泛用來提供DNS服務的軟體,能夠將網域名稱與IP相互對應,提供了「named」和能用來遠端管理named的「rndc」工具。



安裝BIND

要在Ubuntu Server上安裝BIND,可以直接在終端機中執行以下指令:

sudo apt install bind9

ubuntu-server-18-04-dns

DNS預設使用的TCP和UDP連接埠為53,可以使用以下指令來查看BIND是否有確實安裝成功。

sudo netstat -tulnp | grep named

netstat指令可以顯示出網路連線、路由表、介面統計、偽裝連線和多播成員的資訊。-l參數可以只顯示正在監聽中的連線。若使用netstat指令時都沒給任何參數的話,會忽略掉監聽中的連線。-t參數可以只顯示TCP連線。-u參數可以只顯示UDP連線。-t參數和-u參數一起用時就表示可以只顯示TCP和UDP連線。-n參數可以讓IP可以直接被輸出,而不需透過DNS反查其對應的網域名稱。-p參數可以顯示佔用連線的行程。

ubuntu-server-18-04-dns

如上圖,如果有看到TCP和UDP都有在監聽連接埠53的話,就表示BIND安裝成功了!另外您可能還會注意到TCP的連接埠953也正在被程式監聽,這個是「rndc」會使用到的連接埠,本文稍候會提到。

named

named是BIND提供的守護行程(daemon),用來接收並處理使用者發送的網域名稱或是IP查詢的請求,使用者通常會先將查詢請求發送到我們DNS的UDP連接埠,因為速度比較快。如果使用者請求失敗,才會將查詢請求發送到我們DNS的TCP連接埠53。

named的主要設定檔─named.conf

named.conf是named的主要設定檔,在不同的Linux發行版會有不同的儲存目錄,且也會以不同的分類方式將設定檔拆成很多小設定檔。

Ubuntu Server的named.conf存在於/etc/bind/named.conf。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

從上圖可以看到,named.conf設定檔內又用了include命令去連結到其它存在於/etc/bind目樹下的設定檔。

named.conf.options

顧名思義,這個設定檔是專門用來存放options區塊(options { ... })的檔案。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

directory "/var/cache/bind";

directory命令可以指定一個目錄,作為DNS資料庫來使用,這個目錄預設是在/var/cache/bind

forwarders {          
    0.0.0.0;             
};

forwarders命令可以指定多個IP,以分號;區隔。可以讓使用者的查詢請求在我們的DNS無法回答時,被轉遞給其它的DNS來回答。

forward only;

雖然在預設的設定檔中並沒有forward命令的身影,但是它經常會與forwarders命令一同使用。當forward被設為only時,使用者的查詢請求就只能透過forwarders命令列出的IP所連結到的DNS來回答。

dnssec-validation auto;

dnssec-validation命令可以使用auto來做設定,如此一來就能直接讓我們的DNS擁有DNSSEC(Domain Name System Security Extensions)的支援,運行起來就更安全了!

listen-on-v6 { any; };

listen-on-v6命令可以用來設定要監聽的IPv6範圍。

另外還有一個很常用的命令就是allow-query,它可以用來指定允許向這個DNS查詢的網路,預設是全都允許。

named.conf.local

這個設定檔是專門用來存放本地和使用者自訂的zone區塊(zone ... { ... })。zone可以針對每個網域名稱和IP來作正解(用網域名稱查IP)、反解(用IP查網域名稱)的設定。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

從預設的檔案內容中,我們可以看到註解建議我們,如果沒有有特殊的需求的話,應該要將zone.rfc1918這個檔案也include進來。

ubuntu-server-18-04-dns

zone.rfc1918

RFC 1918定義了私有IPv4的區段,zone.rfc1918這個檔案的使用目的就是要區分出私有IPv4的區段。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

IPv4的私有區段範圍是:10.0.0.0 ~ 10.255.255.255、172.16.0.0 ~ 172.31.255.255、192.168.0.0 ~ 192.168.255.255。

zone區塊的IPv4反解寫法如下:

zone "將要反解的IPv4以8位元為一組倒過來寫.in-addr.arpa"  {
    ...
};

zone區塊的IPv6反解寫法如下:

zone "將要反解的IPv6以4位元為一組倒過來寫.ip6.arpa"  {
    ...
};

用以下這個實例來解釋:

zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

16.172表示要對應172.16.*.*這個IPv4區段。

zone區塊中的file命令,可以指定一個存有DNS資源記錄的檔案來給該zone區塊所對應到的網域或是IP來使用。/etc/bind/db.empty是BIND內建的設定檔,它預設的模樣長成這樣:

ubuntu-server-18-04-dns

這個檔案的構造稍候會進行比較詳細的講解。簡單來說,就是當named接收到使用者的查詢請求之後,會去對應使用者要查詢的網域或是IP是否在本機端所定義的zone區塊,如果有的話,file命令所指派的DNS資源記錄(RR)檔案就是該查詢的解答了。

zone區塊中的type命令,可以有以下幾種設定值:

  • master表示此zone區塊是主從架構的DNS中的「主要主機」。主從架構的DNS在文章之後會提到。
  • slave表示此zone區塊是主從架構的DNS中的「從屬主機」。主從架構的DNS在文章之後會提到。
  • hint用於對應.的時候。.表示「根域名」(root name)。這個在文章之後會再提到。

接著繼續談談剛才的DNS資源記錄檔案吧!

$TTL    86400

$TTL這個命令可以設定此DNS資源記錄作為解答的快取時間,單位是秒。設為86400就表示這個DNS查詢請求只要問過DNS一次,客戶端得到的解答就可以持續用一整天,期間內不需要再去向DNS詢問新的解答。$TTL通常會存在,但若不存在,則會以SOA記錄所設定的最小TTL作為TTL值,設定方式稍候會說明。

@   IN  SOA localhost. root.localhost. (                                                   
                  1     ; Serial      
             604800     ; Refresh     
              86400     ; Retry       
            2419200     ; Expire      
              86400 )   ; Negative Cache TTL

以上,@所在的這個欄位表示此筆DNS資源記錄要影響哪個網域(或是說是屬於哪個網域的)。@這個值表示要讓使用這個DNS資源記錄檔案的zone區塊所指定的名稱去取代這個@。換句話說使用@的話,相同的DNS資源記錄檔案,就可以適用於不同的zone區塊中。但是,如果DNS資源記錄檔中有$ORIGIN這個命令存在,就會被用來取代@,而不會去使用zone區塊所指定的名稱。如果這個欄位是空格的話,表示要沿用前一筆DNS資源記錄的這個欄位。

IN所在的這個欄位表示這筆DNS記錄的類別。IN這個值表示這筆DNS記錄是用於網際網路的。雖然還有其它值可以用,但我們幾乎用不到,詳細資訊可以參考RFC 1035。在這個欄位之前也可以插入一個TTL欄位,來針對這筆DNS記錄做TTL的控制,而不是去使用$TTL命令所指定的值或是SOA記錄所指定的最小TTL值。

SOA所在的這個欄位表示這筆DNS記錄的類型,同時也決定了下一個欄位,也就是這筆DNS記錄值的格式。SOA這個值必須用在整個zone區塊的DNS資源記錄的第一筆,用來指定這個使用主從架構的zone區塊的一些資訊。DNS的主從架構就是,使用兩台以上的DNS,將其中一台作為「主要主機」,其它的都作為「從屬主機」,管理員只需要維護「主要主機」的DNS資源記錄,就可以讓「從屬主機」也跟著同步資料。當使用者要使用DNS來查詢網域名稱或IP時,主從架構中只要有一台DNS還活著,使用者就可以查詢到資料。

關於SOA記錄的值,格式如下:

「主要主機」的網域名稱 電子信箱 ( 版本序號 「從屬主機」的更新時間 重試的時間間隔 逾時時間 最小的TTL值 )

注意寫在DNS記錄值的網域名稱,最好都使用完整網域名稱(FQDN, Fully Qualified Domain Name),也就是將一般的網域名稱在結尾處,加上半形句號.,以示結尾。例如localhost就寫成localhost.。否則,DNS會自動在網域名稱之後再串接上.@.,其中的@的作用如同剛才所提到的那樣,會根據DNS資源記錄檔中有沒有$ORIGIN這個命令存在,來決定要使用$ORIGIN的值還是zone區塊所指定的名稱。

電子郵件信箱正常的表示方式會使用@來區隔使用者名稱和主機名稱。但因為@在DNS記錄中有特殊的意義,因此需要被替換為.。也就是說,如果您的電子郵件信箱為root@localhost,就要寫成root.localhost.

SOA記錄的版本序號是指其所屬DNS資源記錄檔案的更動版本號,應為32位元的正整數,主從架構中屬於「從屬主機」的DNS會根據「主要主機」的DNS所傳來的SOA記錄的版本號,來決定是否要更新其所同步到的DNS資源記錄檔案。愈新的資料,版本號的值會愈大。

重試的時間間隔為主從架構中屬於「從屬主機」的DNS向「主要主機」的DNS獲取最新的DNS資源記錄的錯誤重試時間間隔,單位是秒。

逾時時間為主從架構中屬於「從屬主機」的DNS向「主要主機」的DNS獲取到的DNS資源記錄的有效時間,單位是秒,如果超過這個時間,「從屬主機」的DNS所儲存的該DNS資源記錄就會被刪除。

最小的TTL值即為這整個zone區塊中的DNS資源記錄所能指定的最小TTL值。

接著再來看看下一筆DNS資源記錄吧!

@   IN  NS  localhost. 

這是一筆NS記錄,可以在DNS記錄值中指定下一級的DNS的網域名稱,也就是要把使用者的問題再交給哪台DNS做解答的意思。由於這是私有IP的DNS資源記錄的實例,因此將下一級的DNS指定給localhost.,就是再交還給使用者本地端的DNS來負責域名或是IP的對應啦!

整理一下常用的DNS資源記錄類型,如下:

  • SOA指定這個使用主從架構的zone區塊的一些資訊。全名為Start Of Authority。
  • NS指定下一級的DNS的網域名稱。
  • A指定網域名稱所對應的IPv4。正解用。
  • AAAA指定網域名稱所對應的IPv6。正解用。
  • PTR指定IP所對應的網域名稱。反解用。
  • CNAME指定別名。正解用。使用者收到網域名稱的別名之後會再使用這個別名進行DNS的查詢。這種DNS記錄可以擴展其它正解用記錄的網域名稱,反過來說就是可以使用不同的網域名稱來查詢到相同的記錄。
  • MX用於指定電子郵件交換器的主機名稱。
  • TXT指定網域名稱對應某筆字串資料,通常用於驗證網域所有權。
named.conf.default-zones

這個設定檔是專門用來存放預設的zone區塊。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

zone "." {
    type hint;
    file "/etc/bind/db.root";
};

對應.(根域名)的時候,zone區塊的類型需使用hint。其file命令所指定的檔案是BIND內建的/etc/bind/db.root,這個DNS資源記錄檔的資料來源為InterNIC,定義了網際網路通用的Root DNS。

接下來的幾個zone區塊用來處理本地端網域名稱和IP。

zone "localhost" {
    type master;
    file "/etc/bind/db.local";
};

zone "127.in-addr.arpa" {
    type master;
    file "/etc/bind/db.127";
};
 
zone "0.in-addr.arpa" {
    type master;
    file "/etc/bind/db.0";
};
 
zone "255.in-addr.arpa" {
    type master;
    file "/etc/bind/db.255";
};

ubuntu-server-18-04-dns

ubuntu-server-18-04-dns

ubuntu-server-18-04-dns

ubuntu-server-18-04-dns

加入我們自己的zone區塊

我們可以依照自己的Linux發行版所預設的BIND設定架構來加入自己的zone區塊。以Ubuntu Server來說,根據/etc/named.conf的註解,我們應該要將自己的zone區塊寫進/etc/named.conf.local中,所以就在/etc/bind目錄中添加一個新的zone區塊設定檔(在此取名為zones.inner.magiclen.org),並在該設定檔內撰寫我們的zone區塊設定,接著再在/etc/bind/named.conf.local中,使用include命令將剛才建立的zone區塊設定檔給引用進來。

設定檔的內容如下:

zone "inner.magiclen.org" {                                                             
    type master;
    file "/etc/bind/db.inner.magiclen.org";
};
$TTL    86400                                                                                                 
@      IN  SOA ns1.inner.magiclen.org. admin.magiclen.org. (
                  1     ; Serial
              86400     ; Refresh
               3600     ; Retry
            2419200     ; Expire
              84600 )   ; Negative Cache TTL
       IN  A      192.168.56.2
       IN  NS     ns1.inner.magiclen.org.
 
ns1    IN  A      192.168.56.103
 
host1  IN  CNAME  inner.magiclen.org.
host2  IN  A      192.168.56.3
nas    IN  CNAME  host2.inner.magiclen.org.

記得每次更改db.inner.magiclen.org這個檔案時,版本序號的欄位都要遞增。

設定好後必須讓named重新載入設定檔,可以使用以下指令:

sudo systemctl reload bind9

除了用這個方式重新啟動named之外,還可以使用kill指令來傳送SIGHUP信號給named的行程。

使用以下指令來檢查named的設定檔是否都有載入成功:

sudo systemctl status bind9

接著直接在DNS上使用dig指令來做測試,指令如下:

dig inner.magiclen.org

在此補充一點,如果要用dig指令來反解IP位址的網域名稱(PTR記錄),需要加上-x參數。

ubuntu-server-18-04-dns

然後會發現dig指令查不到我們所設定的結果,因為此時的Linux作業系統環境所使用的DNS還不是我們所架設的DNS,所以dig指令預設不會去使用到。要讓dig指令使用我們在本機內架設的DNS,可以加上@127.0.0.1這樣的參數。完整的指令如下:

dig @127.0.0.1 inner.magiclen.org

ubuntu-server-18-04-dns

這樣我們的DNS就架設成功啦!再查一個試試,指令如下:

dig @127.0.0.1 nas.inner.magiclen.org

ubuntu-server-18-04-dns

手動指定Linux作業系統環境所使用的DNS

手動指定Linux作業系統環境所使用的DNS的方式有很多種。以Ubuntu或是其衍生的Linux發行版本來說的話,可以使用以下指令來查看不同網路介面所使用的DNS:

systemd-resolve --status

ubuntu-server-18-04-dns

如果要手動指定DNS的話,可以在netplan這套網路管理程式的設定檔進行設定。設定檔位於/etc/netplan目錄中,可在網路介面的名稱下增加nameservers欄位來指定要用的DNS。如下圖:

ubuntu-server-18-04-dns

接著使用以下指令來套用設定。

sudo netplan generate && sudo netplan apply

然後再次使用以下指令來檢查網路介面的DNS是否有設定完成:

systemd-resolve --status

ubuntu-server-18-04-dns

最後使用dig指令來驗證DNS能否正常查詢。指令如下:

dig inner.magiclen.org

ubuntu-server-18-04-dns

增加從屬主機

前面雖然有提到DNS的主從架構,可以將解答同一個zone區塊的DNS分為「主要主機」和「從屬主機」,但是我們都只有用到「主要主機」。接下來就談談怎麼設定「從屬主機」吧!

從屬主機和主要主機的DNS安裝方式相同,只有有使用主從架構的「zone」區塊會有所變化。「從屬主機」的zone區塊,需使用type命令,將值指定為slave,而不是master。且必須要另外使用masters命令來指定「主要主機」的IP位址。繼續以剛才設定的inner.magiclen.org網域來作為例子吧!

同樣地,我們需要將自己的zone區塊寫進/etc/named.conf.local中,所以就在/etc/bind目錄中添加一個新的zone區塊設定檔(在此取名為zones.inner.magiclen.org),並在該設定檔內撰寫我們的zone區塊設定,接著再在/etc/bind/named.conf.local中,使用include命令將剛才建立的zone區塊設定檔給引用進來。

設定檔撰寫方式如下:

zone "inner.magiclen.org" {
    type slave;
    masters {192.168.56.103;};
};

設定好後必須讓named重新載入設定檔,可以使用以下指令:

sudo systemctl reload bind9

一樣使用dig指令做測試,指令如下:

dig @127.0.0.1 inner.magiclen.org

ubuntu-server-18-04-dns

「從屬」DNS若成功運作的話,會把從「主要主機」拿到的資料快取至記憶體中。如果想要快取至檔案的話,需要在「從屬主機」的zone區塊中加上file命令。如下:

zone "inner.magiclen.org" {
    type slave;
    masters {192.168.56.103;};
    file "db.inner.magiclen.org";
};

注意這邊的file命令是使用相對路徑,如此一來就可以去使用options區塊中directory命令所指定的目錄作為DNS資料庫來使用。換句話說,這個「從屬主機」的zone區塊,就會把從「主要主機」拿到的資料快取至/var/cache/bind/db.inner.magiclen.org檔案中。如果要放到更下層的子目錄或是另外的目錄的話,必須事先將該目錄建立好,並且把目錄的使用者和群組都設定為bind,否則快取檔案是不會被建立出來的。

如果要限制「主要主機」所能夠擁有的「從屬主機」的話(即不允許陌生的「從屬主機」),需要在「主要主機」的zone區塊中加上allow-transfer命令。建議使用acl區塊來建立一個有名稱的網路,讓包含在這個網路的節點都可以成為這台DNS的「從屬主機」。如下:

acl "my_slave_servers" {
    192.168.56.104;
};

zone "inner.magiclen.org" {                                                             
    type master;
    file "/etc/bind/db.inner.magiclen.org";
    allow-transfer {
        my_slave_servers;
    };
};

至此,一台「從屬主機」就設定完成了,如法再炮製,即可建立出更多台「從屬主機」。全都設定完成之後,就會有好幾台IP不同的DNS,在設定給客戶端使用的時候直接把所有DNS的IP都設定進去就行了。DNS的查詢是先搶先贏的機制,每個DNS都會有機會被用到,沒有順序和優先權的問題。

主動通知從屬主機更新

從屬主機除了能每隔一段時間就去向主要主機要求最新的DNS資源記錄外,也可以由主要主機主動通知從屬主機來進行更新。我們只需要在「主要主機」的zone區塊中,利用notify yes;命令來啟用通知功能。一旦「主要主機」的zone區塊有任何DNS資源記錄的更新,就會去主動通知相同區塊下,除了SOA記錄所指定「主要主機」的網域名稱之外,其它用NS記錄所指定的DNS。

改寫「主要主機」的zone區塊後,檔案內容如下:

zone "inner.magiclen.org" {                                                             
    type master;
    file "/etc/bind/db.inner.magiclen.org";
    notify yes;
};

notify命令還可以用explicit這個值來設定。如果是用explicit的話,就會去通知options區塊中以also-notify命令定義的IP位址所對應的DNS。

named-checkconf指令檢查named的設定檔是否有誤

named-checkconf指令可以檢查named的設定檔是否有誤,不需要重啟或是重新載入設定檔。注意這個指令並不會檢查zone區塊的DNS資源記錄檔。

ubuntu-server-18-04-dns

named-checkzone指令檢查named的DNS資源記錄檔是否有誤

named-checkzone指令可以檢查named的資源記錄檔是否有誤,不需要重啟或是重新載入設定檔。

用法如下:

named-checkzone 「zone」區塊對應的名稱 DNS資源記錄檔路徑

ubuntu-server-18-04-dns

rndc

rndc可以管理本地端或是遠端的named。在使用rndc前必須要先有個rndc的金鑰,Ubuntu Server已經將它包含在BIND裡面,設定檔的路徑為/etc/bind/rndc.key。它預設的模樣長成這樣:

ubuntu-server-18-04-dns

那個secret命令所指定的金鑰是BIND隨機產生出來的,如果想要手動產生新的金鑰,並且讓named能夠與rndc搭配使用的話,可以使用以下指令:

rndc-confgen

ubuntu-server-18-04-dns

這邊要注意的是,每次執行rndc-confgen指令時出現的金鑰都會不一樣,此外它還會告訴我們named的設定檔應該要怎麼寫,照它講的方式做就好了。

首先覆蓋原本的rndc.key檔案中定義的key區塊。這個檔案其實就是rndc客戶端所使用的金鑰檔。

ubuntu-server-18-04-dns

接著把rndc-confgen指令提示要加進named.conf檔案的內容加進去。加進去後的結果會像以下這樣:

ubuntu-server-18-04-dns

named.conf檔案中所設定的rndc金鑰是rndc伺服器端的金鑰。rndc客戶端和rndc伺服器端若要成功連線,它們持有的金鑰必須要相同才行。

設定好後必須讓named重新載入設定檔,可以使用以下指令:

sudo systemctl reload bind9

再來就可以使用rndc指令來管理本機的DNS了!

rndc指令的第一個參數為其的子命令,常用的有:

  • reload:重新載入named的設定檔。可以全部重新載入,或是在下一個參數指定一個要重新載入的zone區塊。
  • stats:將DNS的統計輸出成檔案
  • dumpdb:將目前快取的DNS資源記錄輸出成檔案
  • flush:清空DNS快取。
  • status:顯示目前DNS的狀態。

例如:

sudo rndc status

ubuntu-server-18-04-dns

遠端管理DNS

rndc指令可以加上-s參數來指定要管理的DNS的IP或是網域名稱。當然,管理端不一定要安裝完整的BIND來架設DNS,只需要安裝部份工具即可。以Debian或是其衍生的Linux發行版為例,使用以下指令即可安裝「rndc」。

sudo apt install bind9utils

然後要建立一個與遠端rndc伺服器相同的/etc/bind/rndc.key金鑰檔。/etc/bind這個目錄不一定會存在,可能需要手動建立。

rndc伺服器端,也就是DNS端的named.conf也需要做一些修改,建議使用acl區塊來建立一個有名稱的網路,讓包含在這個網路的節點都可以管理這台DNS。監聽的IP(inet命令的第一個參數)也需要改成星號*

修改後的named.conf檔案如下:

ubuntu-server-18-04-dns

設定好後必須讓named重新載入設定檔,可以使用以下指令:

sudo systemctl reload bind9

之後在管理DNS網路內的節點就可以透過rndc指令來遠端管理DNS了!

ubuntu-server-18-04-dns