断片

です・ます調が記事によって違ったりするブログ

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を併用する

    • torrcのDNSPortを9053にしてTorを起動
    • ローカルキャッシュDNSサーバの上流DNSをTorDNS(localhost:9053)に向ける
  • TorDNS単体で使う

    • torrcのDNSPortを53にしてTorを起動

また、FirefoxChromeのような一般的なブラウザで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)であっても、実際のDNSUDPパケットを投げているわけではありません。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ネットワークを構築し、その中で検証します。

github.com

今回は合計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自体の開発においてネットワークの動作検証がしたい、という場合はこちらを使うと良いと思われます。

shadow.github.io

github.com

Bad Exit

不正なフルサービスリゾルバを参照している出口ノードや出口ノード自身がMaliciousな場合はBad Exitフラグが付加されるのでサーキットのパス選択時に弾かれるのではないか*4、と考えた方もいるかと思います。確かにその通りで、実際OpenDNSをフルサービスリゾルバにしている出口ノードがBad Exitとして弾かれるケースが多いようです*5。ただし、Bad Exitのラベル付加はDirectory Authorityのオペレータや彼らにボランティアとして協力する人々によって運営されているので、ネットワーク上で自動検出が行われるわけではありません。ちなみにBad Exitを自動検出するresearch projectとして、spoiled onions*6があります。このresearch projectで開発されたプロダクトであるexitmapについては以前記事を書きました。

epcnt19.hatenablog.com

リスクに対する対策

「名前解決に必ずTorを用いる」と前提した上でのリスクに対する対策を考えてみました。

  • torrcのExcludeNodesとExcludeExitNodesを適当に調整する。

  • torrcのExitNodesで信頼できる出口ノードを指定する。

    • あまりやらない方が良さそう。
  • DNS over TLSを使う

    • 出口ノードに名前解決を依存させないかつ、UDPでない(=TCP)な方法がDNS over TLS over SOCKS5 over Torとなる。TLSにするのは同時にMaliciousな出口ノードによるDNSレコード改竄と盗聴を防げるため。TCPに対応したローカルキャッシュサーバとSOCKS5にリダイレクトするProxyを手元に設置すれば良さそう(未検証)

3つ目の方法については未検証ですが、redsocksのようなプロキシと組み合わせることで実現できるものと思われます。未検証なのでまた別の機会に検証します。

github.com

参考

tor.stackexchange.com

tor.stackexchange.com

*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