DNS over Tor
はじめに
DNS over Torが持つメリットとリスクについて書きます。大体ポエムです。
読むのが面倒な方向けに先に結論(持論)を書いておくと、DNS over TorはDNS Leakに対しては有効ですが、名前解決自体は出口ノード依存です。つまり、出口ノードの参照先フルサービスリゾルバがDNSブロッキングを実施していたり、出口ノード自身がMaliciousな場合は本来とは異なる名前解決結果を得る可能性があります。現実でそのようなケースを引き当てることは多くはないですが(全出口ノードのおよそ40%はGoogle Public DNSを参照している)*1、リスクとして把握しておく必要はあります。
DNS over Tor
DNS over TorはTorネットワークを介して名前解決を得るための仕組みです。0.2.0.1-alpha以前*2のTorでは、Polipo(Privoxy)のようなサードパーティのプロキシを用いて実現していましたが、0.2.0.1-alpha以降はTor本体にリゾルバ(TorDNS)が実装されました。そのため、現在では下記のいずれかの方法でTorDNSを使用するのが一般的のようです。
dnsmasqのようなローカルキャッシュDNSサーバとTorDNSを併用する
TorDNS単体で使う
- torrcのDNSPortを53にしてTorを起動
また、FirefoxやChromeのような一般的なブラウザでDNS over Tor および、Tor経由の通信を実現するためには、ブラウザの設定でSOCKS5プロキシをTorのSocks Port(9050)に向け、SOCKS5のリモートDNS機能を有効にするだけです(この場合、DNS over SOCKS5 over Torというような構成になります。DNS over SOCKS5というと語弊がありますが、これについては後述します)。Tor Browser Bundleは既に初めからそのような設定・構成がされているので、DNS Leakを気にする必要はありません。しかし、名前解決が出口ノード依存という点に変わりはありません。ちなみに、tor-resolveコマンドではTor Browser Bundle同様SOCKSを用いた名前解決を行います。
なお、TorはUDPに対応していないため、TorDNS(DNS over Tor)であっても、SOCKSを用いた名前解決(DNS over SOCKS5 over Tor)であっても、実際のDNSのUDPパケットを投げているわけではありません。TCPを用いた擬似的な名前解決を行っています。
DNS over TorはA/AAAAレコードにのみ対応しており、TXTやMX、SOAといったレコードには対応していないようです。Tor 0.3.2.10の src/or/dnsserv.c
96行目付近は下記のようになっています。
[tor/src/or/dnsserv.c]
for (i = 0; i < req->nquestions; ++i) { if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET) continue; switch (req->questions[i]->type) { case EVDNS_TYPE_A: case EVDNS_TYPE_AAAA: case EVDNS_TYPE_PTR: /* We always pick the first one of these questions, if there is one. */ if (! supported_q) supported_q = req->questions[i]; break; default: break; } }
TorDNSを使ってみる
ここではTorDNS単体で使う方法で設定を行い、実際にTorDNSを用いて名前解決が行われることを確認してみます。
$ sudo lsof -i:53 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME tor 3956 debian-tor 7u IPv4 39295 0t0 UDP localhost:domain
$ dig torproject.org | grep -e "torproject.org." -e " Query time" ;torproject.org. IN A torproject.org. 300 IN A 154.35.132.71 ;; Query time: 531 msec
名前解決時間(Query time)は531ミリ秒でした。当たり前ではありますが、Torを介しているため通常の名前解決より遅いです。この時のlocalhost:53の様子を確認してみます。 (GuardノードのIPアドレスが含まれる部分を *
で隠しています)
$ sudo tcpdump -i lo port 53 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 00:28:58.356075 IP localhost.32932 > localhost.domain: 33784+ [1au] A? torproject.org. (43) 00:28:58.357530 IP localhost.59343 > localhost.domain: 32736+ PTR? *.*.*.*.in-addr.arpa. (45) 00:28:58.357684 IP localhost.domain > localhost.59343: 32736 1/0/0 PTR *.ip-*-*-*.eu. (115) 00:28:58.358021 IP localhost.47104 > localhost.domain: 19011+ PTR? 10.0.168.192.in-addr.arpa. (43) 00:28:58.358144 IP localhost.domain > localhost.47104: 19011 NXDomain 0/0/0 (43) 00:28:58.887745 IP localhost.domain > localhost.32932: 33784 1/0/0 A 154.35.132.71 (48)
次に、この名前解決要求を受けてTorが実際にGuradノードのORPort(443)に接続している様子を確認してみます。 (GuardノードのIPアドレスが含まれる部分を *
で隠しています)
$ sudo tcpdump -i wlp3s0 port 443 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on wlp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes 00:28:58.356395 IP 192.168.0.10.38530 > *.*.*.*.https: Flags [P.], seq 1633253232:1633253775, ack 1193388446, win 1444, options [nop,nop,TS val 3583398 ecr 3185613847], length 543 00:28:58.641147 IP *.*.*.*.https > 192.168.0.10.38530: Flags [.], ack 543, win 1452, options [nop,nop,TS val 3185634151 ecr 3583398], length 0 00:28:58.887383 IP *.*.*.*.https > 192.168.0.10.38530: Flags [P.], seq 1:544, ack 543, win 1452, options [nop,nop,TS val 3185634398 ecr 3583398], length 543 00:28:58.887498 IP 192.168.0.10.38530 > *.*.*.*.https: Flags [.], ack 544, win 1440, options [nop,nop,TS val 3583531 ecr 3185634398], length 0
DNSブロッキングの検証
ここでは実際にDNSブロッキングを行う出口ノードを構築して検証します。とはいえ、実際のTorネットワークで検証するのはtor projectのポリシーに反するので*3、ここではprivateなTorネットワークを構築し、その中で検証します。
今回は合計7ノードからなるTorネットワークを構築しました。うち5ノードは出口ノードの役割を果たします。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 80f4bf39f34e antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 80/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_hs_1 9b8680f38efb antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 7000/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_exit_1 0b0b242adf15 antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 7000/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_relay_1 2bed3aa7b897 antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 9001/tcp, 9030/tcp, 0.0.0.0:9050-9051->9050-9051/tcp private-tor-network_client_1 ff78de4d068d nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 80/tcp private-tor-network_web_1 8910c7f6a786 antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 7000/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_da2_1 01fd20bbf316 antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 7000/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_da1_1 5e9709373409 antitree/private-tor "docker-entrypoint..." 2 hours ago Up 2 hours 7000/tcp, 9001/tcp, 9030/tcp, 9051/tcp private-tor-network_da3_1
これらの全ての出口ノードはブロッキングを行うフルサービスリゾルバ(dockerコンテナとは別に構築したunbound)を参照します。ブロッキングの内容についてはtorproject.org
のAレコードに対して0.0.0.0
を返す仕様とします。
[unbound.conf]
server: verbosity: 1 interface: 0.0.0.0 access-control: 172.18.0.0/24 allow access-control: 192.168.122.0/24 allow access-control: 127.0.0.1/32 allow do-daemonize: no chroot: "" username: "" directory: "" logfile: "" pidfile: "unbound.pid" local-data: "torproject.org. IN A 0.0.0.0"
クライアントからtor-resolveコマンドを実行し、torproject.org
の名前解決を行うと0.0.0.0
が表示されることが確認できます。
$ sudo lsof -i:9050 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME docker-pr 29174 root 4u IPv6 382567 0t0 TCP *:9050 (LISTEN) $ tor-resolve torproject.org 0.0.0.0
実験用Torネットワークを構築する方法として、他にもネットワークシミュレータを使用する方法があり、例えばShadowがあります。Shadowは離散事象(discrete-event)ネットワークシミュレータの一種です。TorやBitocinといった実際のアプリケーションのシミュレーションに適しており、単一のマシン上で、実際のTorネットワークに近い構成で実験・検証を行うことができます。ただし、Shadowはアプリケーションごとにプラグインを作成する必要があり、Torに関してもshadow-plugin-torを導入する必要があります。Tor自体の開発においてネットワークの動作検証がしたい、という場合はこちらを使うと良いと思われます。
Bad Exit
不正なフルサービスリゾルバを参照している出口ノードや出口ノード自身がMaliciousな場合はBad Exitフラグが付加されるのでサーキットのパス選択時に弾かれるのではないか*4、と考えた方もいるかと思います。確かにその通りで、実際OpenDNSをフルサービスリゾルバにしている出口ノードがBad Exitとして弾かれるケースが多いようです*5。ただし、Bad Exitのラベル付加はDirectory Authorityのオペレータや彼らにボランティアとして協力する人々によって運営されているので、ネットワーク上で自動検出が行われるわけではありません。ちなみにBad Exitを自動検出するresearch projectとして、spoiled onions*6があります。このresearch projectで開発されたプロダクトであるexitmapについては以前記事を書きました。
リスクに対する対策
「名前解決に必ずTorを用いる」と前提した上でのリスクに対する対策を考えてみました。
torrcのExcludeNodesとExcludeExitNodesを適当に調整する。
torrcのExitNodesで信頼できる出口ノードを指定する。
- あまりやらない方が良さそう。
3つ目の方法については未検証ですが、redsocksのようなプロキシと組み合わせることで実現できるものと思われます。未検証なのでまた別の機会に検証します。
参考
*1:We also find that a set of exit relays, at times comprising 40% of Tor’s exit bandwidth, uses Google’s public DNS servers - https://nymity.ch/tor-dns
*2:0.2.0.1-alphaは2012年頃のリリースバージョンであり、0.2.0.xのTorは現在のTorネットワーク上では動作しない https://blog.torproject.org/end-life-tor-020x-branch
*3:Should I snoop on the plaintext traffic that exits through my Tor relay? - No - https://www.torproject.org/eff/tor-legal-faq.html.en
*4:Bad Exitは全Directory Authorityのうち、半分以上が承認する必要がある [2.2.1. Choosing an exit] - https://gitweb.torproject.org/torspec.git/tree/path-spec.txt?id=426e9ac1069ee843000aaeed9260ba4c9733af00#n184
*5:OpenDNSはユーザ保護の目的で異なるDNSレコードを返す場合があるらしい - [What specifically causes an Exit to get a Bad Exit flag?] https://tor.stackexchange.com/questions/253/what-specifically-causes-an-exit-to-get-a-bad-exit-flag/254?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
*6:spoiled onions - https://www.cs.kau.se/philwint/spoiled_onions