CentOS 7.5 x86_64にpowerdnsでxip.ioクローンを自前で立てる方法

## xip.ioって知ってますか？
xip.ioチョー便利　ひゃっほい。って言う方は読み飛ばしてください。
xip.ioあるあるの問題によく直面ので、この記事を書きました。

xip.ioって知っていますか？
試験用のVMやバーチャルホストを立ち上げて試験を行うためだけに、
DNSサーバーを毎回構築して使用していました。

社内などで、開発環境用に*.daresore-dev.localのようなワイルドカードドメインを配給してくれる所も
あるようですが、IPを変更したりする度にゾーンファイルを編集するなど、煩雑な作業が必要でした。

xip.ioは公開されているDNSサービスで、場所を問わず、`{IPaddress}.xip.io`で名前を問い合わせると、`{IPaddress}`で指定したIPアドレスをaレコードで返却してくれます。

OpenShift Originなど、DNSを必要とするシステムを導入テストしたりする際には大変有用です。

### 公開サービス・無償サービスがゆえの壁
xip.ioが落ちている時があります。
アプリケーションをデプロイしてあったものをよーし使うぞ。という段になったら、名前解決できないという悲劇に
何度も見舞われてたりします。

```
このサイトにアクセスできません。

xip.ioのサーバーのDNSアドレスが見つかりませんでした

xip.ioをGoogleで検索してください。

ERR_NAME_NOT_RESOLVED
```

### どうやらnip.ioというのもあるらしい
[NIP.IO - wildcard DNS for any IP Address](http://nip.io)
こちらは同じ問題でgoogle検索した時に[コチラ：約束の地 - ワイルドカードDNSは nip.io が良い](https://obel.hatenablog.jp/entry/20170825/1503658628)で教えていただきました。ありがとうございます。

### でもどうせなら自分でも作れないかな。
ということでpowerdnsのプラグインを書いてみようと鼻息を荒くしていたのですが、
プラグインの下調べをする前に、google先生にgitレポジトリを教えてもらいました。

[PowerDNS pipe backend adapter powering xip.io http://xip.io/](https://github.com/basecamp/xip-pdns)

この環境を構築することで、オフラインな環境でもxip.ioと同じように動的な名前解決ができるようになります！（感謝

## インストール
### OS
|名前|項目|
|:--|:--|
|OS|CentOS 7.4|
|vCPU|2core|
|vMem|2GB|

### 必要パッケージのインストール

良い子のお約束のアップデート

```bash
$ sudo yum update
```

gitコマンドを入れる

```bash
$ sudo yum install git
```

digコマンドを使いたいのでbind-utilsを入れる

```bash
$ sudo yum install bind-utils
```

netstatコマンドを使いたいのでnet-toolsを入れる

```bash
$ sudo yum install bind-utils
```

epelのインストール

```bash
$ sudo yum install epel-release
```

firewalldにまだ慣れないのでiptablesに変えてしまう(firewalld使える人はスキップ）

```bash
$ sudo yum install iptables-services
$ sudo systemctl disable firewalld.service
$ sudo systecmtl enable iptables.service
$ sudo systemctl start iptables.service
```



### iptables設定

まずは設定内容の確認。
ルール行を指定したいので、line-numbersをつけて表示する

```bash
$ sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
5    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
```

UDP/TCP Port:53を追加する
DNSもTCP/53使うの？！というのは、長いレコードをUDPで聞いたあとTCPにセッションが切り替わる仕組みがあるので、
明けておく。(512Byteを超えるDNSパケット対策)
iptablesコマンドは実行直後に即時反映される。

```bash
$ sudo iptables -I INPUT 5 -p udp -m udp --dport 53 -j ACCEPT
$ sudo iptables -I INPUT 6 -p tcp -m tcp --dport 53 -j ACCEPT
```

再起動後に実行したiptables結果が再利用できるように保存する

```bash
$ sudo iptables-save > /etc/sysconfig/iptables
```

```bash
$ sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
5    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:53
6    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
7    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
```

再起動

```bash
$ sudo systemctl reboot
```

### PowerDNSのインストール 
pdns-backend-pipeを忘れずにインストール。

```bash
$ curl -o /etc/yum.repos.d/powerdns-auth-master.repo https://repo.powerdns.com/repo-files/centos-auth-master.repo
$ sudo yum install pdns pdns-backend-pipe
```

### xip.ioクローンのインストール

インストール、と言ってもスクリプトをcloneして終わり。

```bash
$ cd /usr/local/
$ sudo git clone https://github.com/basecamp/xip-pdns.git
```

設定ファイルの作成。

```bash
$ cd xip-pdns/etc
$ sudo cp xip-pdns.conf.example xip-pdns.conf
$ sudo vi xip-pdns.conf
```

|設定項目名|説明|
|:--|:--|
|XIP_TIMESTAMP|DNSの最初のSerial値|
|XIP_DOMAIN|例) 127.0.0.1.ip となるxip.ioクローンのFQDN|
|XIP_ROOT_ADDRESSES|トップレベルドメインで返却するIP(例)@.ip = 192.168.200.152|
|XIP_NS_ADDRESSES|ドメインのNSレコード、冗長化する場合はスペース区切りで複数指定可能|
|XIP_TTL|TTL値|

```xip-pdns.conf
# Increment this timestamp when the contents of the file change.
XIP_TIMESTAMP="2018052700"

# The top-level domain for which the name server is authoritative.
XIP_DOMAIN="ip"

# The public IP addresses (e.g. for the web site) of the top-level domain.
# `A` queries for the top-level domain will return this list of addresses.
XIP_ROOT_ADDRESSES=( "192.168.200.152" )

# The public IP addresses on which this xip-pdns server will run.
# `NS` queries for the top-level domain will return this list of addresses.
# Each entry maps to a 1-based subdomain of the format `ns-1`, `ns-2`, etc.
# `A` queries for these subdomains map to the corresponding addresses here.
XIP_NS_ADDRESSES=( "192.168.200.152" )

# How long responses should be cached, in seconds.
XIP_TTL=300
```

pdns本体にプラグインを有効化する

```bash
$ cd /etc/pdns
$ sudo cp -p pdns.conf pdns.conf.bak.`date +%Y%m%d`
$ sudo vi pdns.conf
```

```/etc/pdns/pdns.conf(ファイル最後に追記)
#################################
# xip.io clone
launch=pipe
pipe-command=/usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
```

pdnsの起動

```bash
$ sudo systemctl start pdns
$ sudo systemctl status pdns
$ sudo systemctl status pdns
● pdns.service - PowerDNS Authoritative Server
   Loaded: loaded (/usr/lib/systemd/system/pdns.service; disabled; vendor preset: disabled)
   Active: active (running) since 日 2018-05-27 10:20:34 JST; 1min 4s ago
  Process: 2136 ExecStart=/usr/sbin/pdns_server --daemon (code=exited, status=0/SUCCESS)
 Main PID: 2137 (pdns_server)
   CGroup: /system.slice/pdns.service
           tq2137 /usr/sbin/pdns_server --daemon
           tq2139 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           tq2144 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           tq2146 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           mq2148 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf

 5月 27 10:20:34 infra-test01 pdns[2137]: PowerDNS Authoritative Server 3.4.11 (jenkins@autotest.powerdns.com) (C) 2001-2016 PowerDNS.COM BV
 5月 27 10:20:34 infra-test01 pdns[2137]: Using 64-bits mode. Built on 20180201163352 by mockbuild@buildhw-08.phx2.fedoraproject.org, gcc 4.8.5 20150623 (Red Hat 4.8.5-16).
 5月 27 10:20:34 infra-test01 pdns[2137]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of t...L version 2.
 5月 27 10:20:34 infra-test01 pdns[2137]: Creating backend connection for TCP
 5月 27 10:20:34 infra-test01 pdns[2137]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:20:34 infra-test01 pdns[2137]: About to create 3 backend threads for UDP
 5月 27 10:20:34 infra-test01 pdns[2137]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:20:34 infra-test01 pdns[2137]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:20:34 infra-test01 pdns[2137]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:20:34 infra-test01 pdns[2137]: Done launching threads, ready to distribute questions
Hint: Some lines were ellipsized, use -l to show in full.
```

### pdnsを自動起動にする
```bash
$ sudo systemctl enable pdns
```

### pdnsのテスト
```bash
$ dig @localhost 192.168.200.112.ip

; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> @localhost 192.168.200.112.ip
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44823
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1680
;; QUESTION SECTION:
;192.168.200.112.ip.            IN      A

;; ANSWER SECTION:
192.168.200.112.ip.     300     IN      A       192.168.200.112

;; Query time: 7 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 日  5月 27 10:22:24 JST 2018
;; MSG SIZE  rcvd: 63

$ dig @localhost test.192.168.200.112.ip

; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> @localhost test.192.168.200.112.ip
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56844
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1680
;; QUESTION SECTION:
;test.192.168.200.112.ip.       IN      A

;; ANSWER SECTION:
test.192.168.200.112.ip. 300    IN      A       192.168.200.112

;; Query time: 7 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 日  5月 27 10:31:49 JST 2018
;; MSG SIZE  rcvd: 68

```
### 外部への問い合わせ
```bash
$ dig @localhost qiita.com

; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> @localhost qiita.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 39694
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1680
;; QUESTION SECTION:
;qiita.com.                     IN      A

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 日  5月 27 10:32:32 JST 2018
;; MSG SIZE  rcvd: 38
```
このままでは、.ipだけの名前解決なら良いのですが、不便ですね。

## 外部DNS キャッシュとして動作させる場合
PowerDNSは、pdnsサービス自体はDNSコンテンツサーバとして稼働しますが、
再帰問い合わせを行うキャッシュDNS機能が分離されプロセスが全く異なります。

今回はキャッシュDNSサーバを立ててQuad9のDNSサービスを利用します。
「Quad9」は、IBM Security、PCH、GCAなどが共同で提供する無償のDNSサービスで不正な行為を行うWebサイトなどの危険から保護してくれます。

![image from https://www.quad9.net/](https://qiita-image-store.s3.amazonaws.com/0/126158/888b1cec-c886-2bf8-b388-665b7c432138.png)
https://www.quad9.net/ から転載

### 目指す構成
pdns-recursorがキャッシュDNSとして機能しListnerポートを持つプロセスとして起動します。
{IPaddress}.ipのFQDNの場合のみpdnsのコンテンツDNS部分に転送して名前解決を行うという仕組みです。

![pdns-xip.png](https://qiita-image-store.s3.amazonaws.com/0/126158/c924cea1-6777-3c0f-c17e-ccdccb4cd0b5.png)

### PowerDNS Recursorのインストール
pdns-recursorというrpmパッケージを導入します。

```bash
$ sudo yum install pdns-recursor
```
設定ファイルのバックアップと編集

```bash
$ cd /etc/pdns-recursor/
$ sudo cp -p recursor.conf recursor.conf.bak.`date +%Y%m%d`
$ sudo vi recursor.conf
```
以下差分になるように編集を行います。
`forward-zones=ip=127.0.0.1:8053`に注目です。
`ip`と書かれた部分がゾーン名で`127.0.0.1:8053`が問い合わせ先のDNSサーバー情報です。


```bash
$ diff recursor.conf recursor.conf.bak.`date +%Y%m%d`
148d147
< forward-zones=ip=127.0.0.1:8053
179d177
< local-address=0.0.0.0
$ sudo systemctl stop pdns
```

PowerDNS Recursorの起動

```bash
$ sudo systemctl start pdns-recursor
```

PowerDNS Recursorのステータス確認

```bash
$ sudo systemctl status pdns-recursor
● pdns-recursor.service - PowerDNS recursing nameserver
   Loaded: loaded (/usr/lib/systemd/system/pdns-recursor.service; disabled; vendor preset: disabled)
   Active: active (running) since 日 2018-05-27 10:49:12 JST; 4s ago
     Docs: man:pdns_recursor(1)
           man:rec_control(1)
  Process: 2735 ExecStart=/usr/sbin/pdns_recursor --daemon (code=exited, status=0/SUCCESS)
 Main PID: 2736 (pdns_recursor)
   CGroup: /system.slice/pdns-recursor.service
           mq2736 /usr/sbin/pdns_recursor --daemon

 5月 27 10:49:12 infra-test01 systemd[1]: Started PowerDNS recursing nameserver.
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Set effective user id to 996
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Launching 3 threads
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Done priming cache with root hints
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Done priming cache with root hints
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Done priming cache with root hints
 5月 27 10:49:12 infra-test01 pdns_recursor[2736]: Enabled 'epoll' multiplexer
 5月 27 10:49:13 infra-test01 pdns_recursor[2736]: Refreshed . records
 5月 27 10:49:13 infra-test01 pdns_recursor[2736]: Refreshed . records
 5月 27 10:49:13 infra-test01 pdns_recursor[2736]: Refreshed . records
```

PowerDNSにrecursorを対応させる設定。
以下差分になるように編集を行う

```bash
$ sudo cp -p pdns.conf pdns.conf.bak.`date +%Y%m%d`-02
$ sudo vi pdns.conf
$ sudo diff pdns.conf pdns.conf.bak.`date +%Y%m%d`-02
24d23
< allow-recursion=127.0.0.1,192.168.0.0/16
80d78
< daemon=yes
211d208
< guardian=yes
232d228
< local-address=127.0.0.1
253d248
< local-port=8053
394d388
< recursor=9.9.9.9
551,554c545
```
PowerDNSの起動

```bash
$ sudo systemctl start pdns
```

```bash
$ sudo systemctl status pdns
● pdns.service - PowerDNS Authoritative Server
   Loaded: loaded (/usr/lib/systemd/system/pdns.service; disabled; vendor preset: disabled)
   Active: active (running) since 日 2018-05-27 10:51:17 JST; 4s ago
  Process: 2786 ExecStart=/usr/sbin/pdns_server --daemon (code=exited, status=0/SUCCESS)
 Main PID: 2787 (pdns_server)
   CGroup: /system.slice/pdns.service
           tq2787 /usr/sbin/pdns_server --daemon
           tq2789 /usr/sbin/pdns_server-instance --daemon
           tq2792 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           tq2797 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           tq2799 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf
           mq2801 bash /usr/local/xip-pdns/bin/xip-pdns /usr/local/xip-pdns/etc/xip-pdns.conf

 5月 27 10:51:17 infra-test01 pdns[2789]: Using 64-bits mode. Built on 20180201163352 by mockbuild@buildhw-08.phx2.fedoraproject.org, gcc 4.8.5 20150623 (Red Hat 4.8.5-16).
 5月 27 10:51:17 infra-test01 pdns[2789]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of t...L version 2.
 5月 27 10:51:17 infra-test01 pdns[2789]: DNS Proxy launched, local port 49003, remote 9.9.9.9:53
 5月 27 10:51:17 infra-test01 pdns[2789]: Creating backend connection for TCP
 5月 27 10:51:17 infra-test01 pdns[2789]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:51:17 infra-test01 pdns[2789]: About to create 3 backend threads for UDP
 5月 27 10:51:17 infra-test01 pdns[2789]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:51:17 infra-test01 pdns[2789]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:51:17 infra-test01 pdns[2789]: Backend launched with banner: OK        xip.io PowerDNS pipe backend (protocol version 1)
 5月 27 10:51:17 infra-test01 pdns[2789]: Done launching threads, ready to distribute questions
Hint: Some lines were ellipsized, use -l to show in full.
```

### 外部問い合わせをもう一度試す
```bash
$ dig @localhost qiita.com

; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> @localhost qiita.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41017
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;qiita.com.                     IN      A

;; ANSWER SECTION:
qiita.com.              60      IN      A       54.64.239.23
qiita.com.              60      IN      A       54.178.207.39

;; Query time: 735 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 日  5月 27 10:54:42 JST 2018
;; MSG SIZE  rcvd: 59

```
できた！！！　　

### pdnsを自動起動にする
```bash
$ sudo systemctl enable pdns-recursor
```

## セカンダリは？
xip.ioクローンのゾーンはゾーン転送せず、そのまま同じ設定をすればセカンダリとなる。

## まとめ
オフラインで隔離されたような環境でも、xip.ioクローンとして利用できるのはすごい便利！
今回はquad9を利用しましたが、Google Public DNSでも問題ありません。