サイトブロッキングが話題なのでDNSブロッキングを実現するための方法を検証してみた
本日、NTTコミュニケーションズ、NTTドコモ、NTTぷららの3社はサイトブロッキングを実施するとの方針を発表しましたね。
www.ntt.com https://www.asahi.com/articles/ASL4R4Q81L4RULFA01G.htmlwww.asahi.com
技術的にはどのように実現すればよいのか興味があるので検証してみました。
サイトブロッキングを実現するための方法の一つとして、「DNSブロッキング」という手法があるそうです。ISPがユーザに対して提供しているDNSキャッシュサーバでブロックしたいサイトの名前解決をできないようにする手法です。ただこの手法を用いても、ユーザがISPの管理外の 1.1.1.1, 1.0.0.1, 8.8.8.8, 8.8.4.4 のようなpublic DNS serverを使えば回避できてしまうのであまり意味はありません。
DNSブロッキングに対応したDNSサーバを構築する
今回はOSとしてubuntu16.04の上でDNSキャッシュリゾルバであるunboundを構築して設定していきます。
まずはふつうのDNSフルリゾルバを構築する
まずはユーザに提供するようのDNSフルリゾルバを作成します。 aptコマンドを使ってunboundをインストールします。
ubuntu@dns-resolver01:~$ sudo apt install unbound ubuntu@dns-resolver01:~$ sudo service unbound status ● unbound.service Loaded: loaded (/etc/init.d/unbound; bad; vendor preset: enabled) Drop-In: /run/systemd/generator/unbound.service.d └─50-insserv.conf-$named.conf, 50-unbound-$named.conf Active: active (running) since Mon 2018-04-23 06:57:24 UTC; 17min ago Docs: man:systemd-sysv-generator(8) CGroup: /system.slice/unbound.service └─2297 /usr/sbin/unbound
インストールコマンドを1行打つだけでunboundがインストールされて起動されていることがわかりますね。この状態だと外部からのアクセスに応答しないようになっているので、private IP アドレスからの問い合わせには応答するようにしてみましょう。
/etc/unbound/unbound.conf.d/dns-cache.conf
というファイルを作成し、以下の内容を記述します。
server: interface: 0.0.0.0 access-control: 10.0.0.0/8 allow access-control: 172.16.0.0/12 allow access-control: 192.168.0.0/16 allow access-control: 127.0.0.1/32 allow
完了したら、以下のコマンドで再起動をします。
ubuntu@dns-resolver01:~$ sudo service unbound restart
これで別のホストからのアクセスにも応答できるはずです。別ホストからDNSサーバとして参照してみた時の結果が以下です。 10.55.48.99
というのは今回構築したサーバのIPアドレスです。
ubuntu@ubuntu01:~$ dig +short google.com @10.55.48.99 216.58.197.174
DNSによるサイトブロッキングを実現する
ここからが本題です。特定のサイトへアクセスできないようにするにはどうすればよいのでしょうか。サイトブロッキングの対象とされている anitube.se
にアクセスできないようにしてみましょう。まずは特に設定を入れない状態で anitube.se
の名前解決をしてみます。
ubuntu@ubuntu01:~$ dig +short anitube.se 104.20.203.27 104.20.202.27
2つのIPアドレスが返ってきましたね。名前解決ができています。これを解決できないようにしたいということです。
Unboundのpython拡張
Unboundにはpythonスクリプトで拡張をする機能があります。ドキュメントを参考にして実装しました。 https://unbound.net/documentation/pythonmod/examples/example0.html
def filter_domain(qstate, id): domain = qstate.qinfo.qname_str.rstrip('.') if domain in block_domains: qstate.return_rcode = RCODE_NXDOMAIN qstate.ext_state[id] = MODULE_FINISHED else: qstate.ext_state[id] = MODULE_WAIT_MODULE
filter_domainという箇所でクエリで問い合わせられているドメインがブラックリストに入っていれば名前解決を続行せずに NXDOMAIN
を即答するようになっています。
このスクリプトを /etc/unbound/unbound/domain_filter.py
に設置します。
Unboundの設定
UnboundのPython拡張をインストールします。
ubuntu@dns-resolver01:~$ sudo apt install python-unbound
/etc/unbound/unbound.conf.d/dns-cache.conf
を以下のように書き換えます。
server: interface: 0.0.0.0 access-control: 10.0.0.0/8 allow access-control: 172.16.0.0/12 allow access-control: 192.168.0.0/16 allow access-control: 127.0.0.1/32 allow module-config: "python validator iterator" python: python-script: "/etc/unbound/domain_filter.py"
ドメインのフィルタ対象の一覧ファイルを /etc/unbound/block_domains.txt
に作成します。1行1ドメインで列挙していきます。
anitube.se
unboundを再起動します。
ubuntu@dns-resolver01:~$ sudo service unbound restart
動作確認
ubuntu@ubuntu01:~$ dig anitube.se @10.55.48.99 ; <<>> DiG 9.10.3-P4-Ubuntu <<>> anitube.se @10.55.48.99 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 17521 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;anitube.se. IN A ;; Query time: 0 msec ;; SERVER: 10.55.48.99#53(10.55.48.99) ;; WHEN: Mon Apr 23 10:01:15 UTC 2018 ;; MSG SIZE rcvd: 39
anitube.se
を名前解決しようとしてもレコードが返ってこなくなりました。
ログを見るかぎり、結果はキャッシュされているようなので毎回実行されるわけではなさそうです。
追記
BINDだとRPZという機能を使えばDNSブロッキングができるらしい。職場の方に教えてもらいました。