Powerdns の pipebackend で遊んでみる

pdns-mrubybackendをリリースするまでは気にしていなかったのですが、ドキュメントを読んでいるうちに
Powerdnsのpipebackendが次第に気になってきました。

ドキュメント曰く、

The PipeBackend allows for easy dynamic resolution based on a ‘Coprocess’ which can be written in any programming language that can read a question on standard input and answer on standard output.

ざっくり言うと、PipeBackendを使うと好きな言語で簡単にバックエンドが作れるよ。という事ですね。
名前解決要求を標準入力で受け取り、標準出力へ回答を返せばよいようです。

ドキュメントには丁寧にperlのサンプルが載っています。
これを参考にrubyで雑なバックエンドを書いてみます。
もっとマシな書き方があるとは思いますが pdns-mrubybackend の examples/pdns-backend.rb に
近い感じで書いてます。

pipebackend.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/bin/env ruby

def lookup

$records.each{|rec|
if( rec["name"] == $domain && ($type == "ANY" || rec["type"] == $type) )
if( rec.has_key?("code") )
rec["content"] = Kernel.eval(rec["code"]).to_s
end
$answer.push( rec )
end
}

end

$records = [
{"name"=>"example.jp","type"=>"SOA","content"=>"ns.example.jp. hostmaster.example.jp. 1 1800 900 604800 3600",},
{"name"=>"example.jp","type"=>"NS" ,"content"=>"ns.example.jp",},
{"name"=>"example.jp","type"=>"TXT","content"=>"v=spf1 +ip4:172.17.43.25 +ip4:172.17.44.25 ~all",},
{"name"=>"example.jp","type"=>"A" ,"content"=>"172.17.43.80",},
{"name"=>"www.example.jp","type"=>"A","content"=>"172.17.43.80",},
{"name"=>"mail.example.jp","type"=>"A","content"=>"172.17.25.25",},
{"name"=>"example.jp","type"=>"MX","content"=>"mail.example.jp",},
{"name"=>"blog.example.jp","type"=>"A","content"=>"172.17.43.80",},
{"name"=>"now.example.jp","type"=>"TXT","code"=>'"Hi! #{Time.now.to_s}"' ,},
]

line = STDIN.gets

if line.chomp != "HELO\t1"
print "FAIL\n"
exit
end
print "OK\n"
STDOUT.flush

$answer = Array.new
$domain = ""
$type = ""
$remote_addr = ""

while line = STDIN.gets

parts = line.chomp.split /\t/
if parts.length < 6
print "LOG\tPowerDNS sent unparseable line\n"
print "FAIL\n"
STDOUT.flush
next
end

#$type,$qname,$qclass,$qtype,$id,$ip

$answer.clear
$domain = parts[1].dup
$type = parts[3].dup
$remote_addr = parts[5].dup

lookup

$answer.each{|rec|
if rec["type"] == "MX"
content = "0\t"+rec["content"]
else
content = rec["content"]
end
printf "DATA\t%s\tIN\t%s\t%d\t-1\t%s\n",rec["name"],rec["type"],60,content
}
print "END\n"
STDOUT.flush

end

そして、powerdns側のconfは以下のように。

pdns.conf
1
2
3
4
5
6
7
8
9
10
11
12
distributor-threads=4
receiver-threads=24

launch=pipe
load-modules=pipe

pipe-command=./pdns-pbackend.rb

query-cache-ttl=0
cache-ttl=0
loglevel=3
log-dns-details=no

そして、今回もresperfでベンチマークをとってみました。

$ /usr/local/nom/bin/resperf -s 172.19.100.113 -d largequeries.txt -m 300000
DNS Resolution Performance Testing Tool
Nominum Version 2.0.0.0

[Status] Command line: resperf -s 172.19.100.113 -d largequeries.txt -m 300000
[Status] Sending
[Status] Reached 65536 outstanding queries
[Status] Waiting for more responses
[Status] Testing complete

Statistics:

Queries sent: 77125
Queries completed: 77125
Queries lost: 0
Run time (s): 100.000000
Maximum throughput: 6240.000000 qps
Lost at that point: 0.16%

うーん。思いの外性能が出ませんね。
内心 pdns-mrubybackend よりも良い性能が出たらどうしよう、と不安でした(笑)

とは言え、言語を選ばないところは大きな魅力です。

興味のある方は是非お好きな言語で、pipebackendを書いてみてください。