2012年8月9日 星期四

從 Java 動態更新 DNS

延續上一篇「在 Java 上使用 dnsjava 查詢 DNS
這篇一樣是用 dnsjava,目標是實作更新 DNS 的程式。

在更新之前,必須先把 DNS Server 的動態更新功能打開,否則一般狀況 DNS Server 是不允許被更改內容的
我這邊測試是架了一台 Windows 2008 R2,在上面加上 DNS 角色。
設定動態更新的地方如圖所示,紅圈圈的位置就是設定動態更新的地方:


由上圖可以看出,這裡假設 DNS Server 管理的網域是 example.com.tw,IP 範圍是 10.0.1.*。

接著就是 Java 的程式碼了。
其實程式碼很簡單 XD,跟 dnsjava 的內建範例幾乎一模一樣!
String DNS_DOMAIN = "10.0.1.1"; // DNS Server
try {
  Name zone = Name.fromString("example.com.tw."); // domain name
  Name host = Name.fromString("test", zone); // host name

  Update update = new Update(zone);
  update.add(host, Type.A, 60, "10.0.1.2");
  Resolver res = new SimpleResolver(DNS_DOMAIN);
  res.setTCP(true);

  Message response = res.send(update);
} catch (Exception e) {
  e.printStackTrace();
}

第 3 行指定的是 FQDN 裡面的 domain,第 4 行指定的則是 FQDN 的 host-name
兩個串起來就是 test.example.com.tw.,也就是這次要更新的目標域名。
要注意的是 example.com.tw. 最後面那個 . 一定要加
否則會被判定為不是 absolute name 而丟出 RelativeNameException。

6~9 行是設定要更新的內容,第 6 行指定要更新的 domain 是 example.com.tw.
第 7 行就指定這次要更新的內容,要修改(或加入) tesy.example.com.tw. 這個域名
DNS 種類為 A、TTL 為 60、IP 位址為 10.0.1.2。

如果 DNS Server 是在 Linux 上架設的,有可能會設定需要加密驗證才能拿到修改的權限
這時在 Resolver 那裡就要額外設定加密的方法
例如:
Resolver res = new SimpleResolver(DNS_DOMAIN);
res.setTSIGKey(TSIG.HMAC_MD5, "test", "ZaGKmHwKUqdXvqDOx/NaNWaAXW8PLACbHBn69xepTFo="));
res.setTCP(true);

其中 setTSIGKey() 的那行就是設定加密驗證的方法
第一個參數是 DNS Server 設定的加密方法,預設是 HMAC_MD5
第二個參數是 DNS Server 驗證使用的名稱,這可以在 Linux 產生的 key 檔上看出來
第三個參數是 DNS Server 加密後用來驗證的字串
例如 Linux 產生的 key 檔的內容可能是這樣:
test. IN KEY 512 3 157 ZaGKmHwKUqdXvqDOx/NaNWaAXW8PLACbHBn69xepTFo=
那麼名稱就是第一個值 test,而最後一個值 ZaGKmHwKUqdXvqDOx/NaNWaAXW8PLACbHBn69xepTFo= 就是加密字串。

DNS update query 送出之後,可以從回傳的 Message 的 Header 看到 query 的結果
Message response = res.send(update);
System.out.println(response.getHeader().toString());
上述的程式碼,可能回傳的結果是:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 65035
status 那裡就是結果了,可能比較常看到的狀態如下
  • NOERROR:命令執行成功
  • NOTAUTH:無權限
  • REFUSED:命令被拒絕
以我測試的狀況來說,如果我的 DNS Server 有設定加密驗證
但送 DNS query 時沒有送 TSIGKey,DNS Server 會回應 REFUSED。
而如果有送 TSIGKey,但給的驗證名稱或密文或演算法是錯的,則 DNS Server 會回應 NOTAUTH。

補充:要得到結果可以直接透過 RCode(Response Code)來判斷
Message response = res.send(update);
int status = response.getHeader().getRcode();
RCode 的種類可以參考 [1],0 即表示 NOERROR。

參考資料:
1、DNS Message Header and Question Section Format

沒有留言: