それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

PowerDNSでDNSサーバーを作る。

PowerDNS 通称 pdns が便利。

pdns が便利そう。なので使ってみてる。

Power DNS で出来ること

PowerDNSはDNSで出来ることが一通り全てできる。

  • 権威サーバー
  • ミラーサーバー
  • キャッシュサーバー

これらをちゃんと実装している。

さらに、コンテンツサーバーについては、ゾーンとレコードをSQLバックエンドに放り込むことが出来る。

SQLでバックエンドに放り込めるだけでもすごいのに

  • bind
  • mydns
  • tinydns

これらのファイル形式に対応してて、レコードを様々な形で持つことが出来る。いいな、これ。

あと、LDAPに格納したレコードも使えるらしい。無敵か。

さらにHTTP機能がある。

WEBサーバー機能があって、PowerDNSのモニタリングができて、HTTP APIまでもがついてくる。

インストールして使ってみる。

インストールに必要なものと、インストールした環境

こんかいはCentOSを引っ張り出してきた。

準備 : 1

DNS を扱うのでDNSを扱うのに必要な dig コマンドを用意しておく

sudo yum install bind-utils

dig いれたら準備段階として dig の結果とネットワーク疎通を見ておく

dig +short t.co

その他に bash-completion nmap vim-enhanced などを入れた

準備 : mysql をインストール

mysql サーバーにDNSレコードを作ることにするので、MySQLを準備してくる

sudo yum install mysql-community-server

mysql のroot の基本設定をしておく

sudo mysql_secure_installation

MySQLにユーザーとデータベースとテーブルを準備する。

MySQLをインストールしたので、ユーザーを作る

create user 'pdns'@'%' identified by 'password'; 

MySQL に pdns のデータベースを作る。

もう管理が面倒くさいのでユーザー名と同じにした。

create database pdns;

pdns ユーザーにデータベースの権限をGRANTする

grant all on pdns.* to 'pdns'@'%'

一通りがおわったら、flush しておく

flush privileges;

pdns ユーザーでログインしてみる

mysql -u pdns -p 

ログインできたら権限をチェックしておく

use pdns

データベースにテーブルを作る

CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(6) NOT NULL,
  notified_serial       INT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX name_index ON domains(name);


CREATE TABLE records (
  id                    INT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  change_date           INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);

テーブル構造の詳細は公式ドキュメントにある。今回は、domains/zonesさえアレば動くので、これだけ持ってきておいた。

っていうか。テーブル構造は全然うるさくない。自分で適当なテーブルで作ってもいいし、名前をマッピングしておけばちゃんと動くらしい。好きなカラム追加しても良い。緩さがいいよな。使いやすい。

MySQL以外にSQLitePostgreSQLを使う時もほぼ同じだと思う。

pdns のインストール

準備が終わったので、pdnsをインストールすることにする。

sudo yum install pdns

さらに、mysql をバックエンドに使うので mysql-backend をインストールしておく。

sudo yum install pdns-backend-mysql

pdns の設定: mysql

mysql を使うように設定するので

launch=gmysql
gmysql-host=127.0.0.1
gmysql-user=pdns
gmysql-dbname=pdns
gmysql-password=XXXXXXXXXXX

これを書いた。

その後

service pdns restart

接続の確認

nmap localhost 

53 番が空くことを確認

dig example.com @127.0.0.1

とりあえず接続して応答は返ってくることを確認。もちろんレコードは何もない。

レコードの追加

サーバーが起動したのでレコードを追加する。

mysql のデータベースにDNSゾーンとDNSレコードとしてテーブルにレコードを追加する。

mysql -p -u pdns pdns 

接続できたら、SQLで流し込む。

INSERT INTO domains (name, type) values ('example.com', 'NATIVE');
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'example.com','localhost ahu@ds9a.nl 1','SOA',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'example.com','dns-us1.powerdns.net','NS',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'example.com','dns-eu1.powerdns.net','NS',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'www.example.com','192.0.2.10','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'mail.example.com','192.0.2.12','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'localhost.example.com','127.0.0.1','A',120,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
                      VALUES (1,'example.com','mail.example.com','MX',120,25);

これで、example.com のNSにwwwを登録することが出来た。

問合せてみる

これで完成なので、早速問合せてみる。

 dig example.com any  @127.0.0.1

; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> example.com any @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36246
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 2
;; WARNING: recursion requested but not available

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

;; ANSWER SECTION:
example.com.        120 IN  MX  25 mail.example.com.
example.com.        86400   IN  NS  dns-eu1.powerdns.net.
example.com.        86400   IN  SOA localhost. ahu.ds9a.nl. 1 10800 3600 604800 3600
example.com.        86400   IN  NS  dns-us1.powerdns.net.

;; ADDITIONAL SECTION:
mail.example.com.   120 IN  A   192.0.2.12

;; Query time: 6 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Jul 14 20:15:11 JST 2016
;; MSG SIZE  rcvd: 189

うん、ちゃんと応答する。

HTTP のAPIを準備する。

ちゃんと応答したので、手軽に更新するために curl から叩いたら便利だよね。

MySQLをレコード使えば更新できるので、RailsMySQL更新するAPIを作っても良いんだけど、最初からあるなら、ソレ使ったほうが楽だよね。

HTTPのAPIを準備する。

webserver=yes
webserver-address=127.0.0.1
webserver-port=80

##
experimental-json-interface=yes
experimental-api-key=changeme
experimental-logfile=/var/log/pdns.log

とりあえず、WEBSERVERをつけたら、状態をモニタリング出来るようになってる。

json-interfaceをオンにしたら、WEB-APIが解放される。楽ね。

API を叩いてみる。

curl -H 'X-API-Key: changeme' http://127.0.0.1:80/servers/localhost/zones 

これだけ!あーカンタン。幸せ。

APIはなんでもできるから管理をしっかりしないといけない。

まとめ

最近、ダイナミックDNSが軒並みシンドイ事になってきた。

ダイナミックDNSスパマーがIPをコロコロ変えるのに利用されたり、クラウドの普及で需要が減ったりしてる。そのため何処も収益化に必死になってきた。

たいへん不自由なので、自分でDNSサーバを作ったほうが良いと判断しました。

DNSの管理は大変だし、乗っ取られたら大変なので注意が必要だし、いろいろと考えることが多い。

でもDNSを自分で管理できるととても便利だし、クラウドが手軽に使えるのにDNSを自由に使えない。結局は、DNSが使い勝手や手軽さのボトルネックになってしまう。

お名前.com のようにTTLが長すぎて変更に時間がかかったり value-domain のように変な挙動する dns だったり。もうね。

GoogleAmazonのサービスはちゃんとDNSが基本セットに入ってるんだよ。DNS手軽に使えないのものをクラウドと読んでほしくないというか。

参考資料

https://doc.powerdns.com/3/httpapi/README/#powerdns-api

https://doc.powerdns.com/3/authoritative/installation/

http://www.slideshare.net/mzdakr/powerdns