Twistedを利用してお手軽にDNSサーバーを構築する

これはなんだろう？
===========

Twistedを使えばDNSサーバの構築が簡単にできる、その事実を知るまで、/etc/hostsによる天国を築いていた。
肥大化した/etc/hostsを何とかするため、僕は調べた。そういえばTwistedを利用すれば、あのネットワークのなんたらが色々詰まったあのライブラリ、Twistedを利用すればいいのではないだろうか？と思ったのだった。
で、調べてみたらTwistedをインストールした後に入るtwistdコマンド(Python script)で、引数にdnsを渡せば後は簡単なzoneファイルを記述するだけで終わるということがわかった。

ということでTwistedを利用したDNSサーバーの構築(簡単)についてメモを記述する。

環境整備から構築までの簡易な流れ
====================

- Python 2.7.3 の環境を用意する
    - Version 12.3.0なら、[Python 3.3でもライブラリがサポートされていたり(一部を除く)する](http://twistedmatrix.com/trac/browser/trunk/admin/_twistedpython3.py)けど、運用の面から2.x系の最新Stable versionを選択することにした。

- Twistedをおもむろにインストールします。
    - 環境を汚したくないので、easy_install & pip & virtualenvで動作環境を整備する

- zoneファイルを用意する
    - pyzone という形式で、リスト内にNSやらCNAMEなどのレコードを書いて、設定ファイルを用意する。
    - BIND9 形式もサポートしているようだけど、pyzone形式のほうが手軽。

- twistd コマンドでサーバーを起動する
    - サーバーを起動する、という表現が合っているかわからないけど、dnsというパラメータを渡して起動する。

動作検証を行ったマシン
==============

- Retina MBP 13inch (Retina)
- Mac OS X 10.8.2
- Python 2.7.3
    - home brew を利用

環境整備〜起動までの詳細手順とか
=====================

Twistedが使える環境を整えるまで
----------------------------

``` plain
> easy_install-2.7 pip
> pip install virtualenv
> rehash
> mkdir -p ~/TwisedDNS/
> cd ~/TwistedDNS
> virtualenv python 
> source python/bin/activate
(python)> rehash
(python)> pip install twisted
```

zoneファイルの記述
----------------

- unko.zoneとする。

``` python:unko.zone
zone = [
    SOA(
        'unko.com',
        mname = 'ns1.unko.com',
        serial = 2013011901,
        refresh = '1H',
        retry = '1H',
        expire = '1H',
        minimum = '1H' 
    ),
   
    # NS Record 
    NS('unko.com', 'ns1.unko.com'),

    # A Record
    A('unko.com', '10.0.0.10'),
    A('blog.unko.com', '10.0.1.10'),

    # CNAME Record
    CNAME('www.unko.com', 'unko.com') 
]
```

サーバの起動
-----------

- twistd コマンドを利用し、サーバを起動。

```
> sudo twistd -n dns --recursive --cache --pyzone unko.zone
# -n は --nodaemonオプションで、これをつけるとdaemonではなくシェル上のプロセスとして起動。今回はテストなので有効にしてる。
# --recurcive で再帰的に外部のネームサーバに問い合わせを行う感じ。
# --cache は、ドメインキャッシュを有効にする。
# --pyzone は、zoneファイルの指定に利用する。
```

digコマンドで早速問い合わせ
------------------------

- digコマンドを利用し問い合わせを行う。

``` plain
> dig @127.0.0.1 unko.com 

; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 unko.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47522
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;unko.com.INA

;; ANSWER SECTION:
unko.com.3600INA10.0.0.10
```

``` plain
> dig @127.0.0.1 blog.unko.com 

; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 blog.unko.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6450
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;blog.unko.com.INA

;; ANSWER SECTION:
blog.unko.com.3600INA10.0.1.10

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jan 19 15:48:31 2013
;; MSG SIZE rcvd: 47
```

``` plain
> dig @127.0.0.1 www.unko.com 

; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 www.unko.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10221
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.unko.com.INA

;; ANSWER SECTION:
www.unko.com.3600INCNAMEunko.com.
unko.com.3600INA10.0.0.10

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jan 19 15:48:36 2013
;; MSG SIZE rcvd: 60
```

管理をしていないドメインへの問い合わせもしてみる。

``` plain
> dig @127.0.0.1 yahoo.co.jp 

; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 yahoo.co.jp
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37453
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;yahoo.co.jp.INA

;; ANSWER SECTION:
yahoo.co.jp.224INA124.83.187.140
yahoo.co.jp.224INA203.216.243.240

;; Query time: 13 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jan 19 15:54:20 2013
;; MSG SIZE rcvd: 61
```

バッチリ問い合わせを行うことができました。
daemonプロセスとして動かしたい場合は、-n (--nodaemon) オプションを取れば大丈夫。
コマンドを起動したディレクトリ内にtwistd.pidファイルと、twistd.logファイルが作成されていると思うので、適宜使えばいいと思う。。
[unbound](http://unbound.net/)や、[nsd](http://www.nlnetlabs.nl/projects/nsd/)や、それこそ[BIND](https://www.isc.org/software/bind)やらを使わずに、特定のサービス内、それこそ内部ネットワークで利用するならこの程度で充分では。

以上です。

参考
----

[Creating and working with a names (DNS) server](http://twistedmatrix.com/documents/12.3.0/names/howto/names.html)