Posted at

VPS+DoH+Pi-holeで広告ブロックする


はじめに

VPS+VPN+Pi-holeで広告ブロックするというのをやったことを知人に話したところ、次のような話が出ました。


  • DoH(DNS over HTTPS)で認証はできるんだろうか

  • 仮にできなくても(実際できなさそう)、HTTPSならば内容は暗号化されるんだからそこに認可情報を埋め込めばよいのでは

HTTPSでは例えばURLのパスは暗号化されているので、推測困難なパスでDoHサービスを提供すれば、そのパスを知っている者はDoHを使えるという認可が実現できます。つまり、パスがパスワー……共有鍵ということですね。


環境


  • サーバ Ubuntu xenial

  • クライアント Android Pie


DoHサーバを立てる


独自ドメインを取得する

DoHはHTTPSなので、証明書がなければなりません。これをLet's Encryptで取得しようとした場合、独自ドメインであるほうが面倒がないと思われます。

こちらの記事を参照して無料ドメインを取得しました。


証明書を取得する

Let's Encryptですね。Certbotにより証明書を取得します。ここで特にHTTPサーバを立てていなくても取得できますが、証明書の自動更新のことを考えるとApache httpdかnginxあたりを立てておくと良いと思います。


DoHプロキシを立てる

DoHプロキシはDoHサーバとして振る舞い、リクエストを受けるとDNSクエリをDNSキャッシュサーバに転送して解決し、応答するものです。実装は色々ありますが僕はrustによる実装を使いました。趣味です。

cargo install doh-proxyで入れられるはずですが、僕が試したときはコンパイルエラーで入れられなかったので最新版をgithubからcloneしcargo installで入れました。


Pi-holeを立てる

前の僕の記事と同様にPi-holeを立てます。


DoHサービスを提供する

DoHをグローバルに公開するわけですが、2つの方法があります。

証明書取得時HTTPサーバを立てていた場合は、doh-proxy -u ${Pi-holeのlisten address}:53とすれば127.0.0.1:3000, /dns-queryで上がってくるので、HTTPサーバのリバースプロキシ機能で/randomstringからhttp://127.0.0.1:3000/dns-queryへのマッピングを行えばよいです。

doh-proxy自体をグローバルに公開する場合は、予めcargo install doh-proxy --features=tlsとしてdoh-proxyがHTTPSを喋れるようにしておきます。そして証明書と秘密鍵を読ませるのですが、これはPKCS#12形式である必要があります。README.mdを参考にしてp12ファイルを作成しておいてください。証明書はfullchain.pemを使います。

用意ができたらdoh-proxy -u ${Pi-holeのlisten address}:53 -l 0.0.0.0:443 -p /randomstring -i ${p12ファイルへのパス} -I ${p12ファイルデコードのパスワード}とします。

これでhttps://your.domain.name/randomstringでDoHサービスが提供されます。


DoHサービスを利用する

IntraでDoHが使えます。起動時はgoogle DNSサービスが使われますが、設定から好きなサーバを使えるので、https://your.domain.name/randomstringを入れます。

うまく設定できていれば広告がブロックされるはずです。


おわりに

VPNを使うのとどっちがいいかですが、クライアントとしてはDoHのほうが設定が楽だし、負荷が低いような感じがあります。

一方でHTTPSだからといってパスを認可情報に使うというのは一般的ではないため、パスをセキュアに扱うというのも特別なケアが要ると思います。例えばリバースプロキシのログには普通パスが残りますし、doh-proxyのコマンドライン引数で与えたときはヒストリに残ります。