用 Raspberry Pi 架設加密 DNS 客戶端

dig through DNS-over-HTTPS

Cloudflare 宣佈使用 1.1.1.1 做爲 DNS,而且強調隱私保護。因爲 Cloudflare DNS 支持 DNS-over-TLS 和 DNS-over-HTTPS,這使得加密 DNS 成爲了熱門話題linux

由於操做系統每每不支持加密 DNS,因此要使用加密 DNS 必須使用一個加密 DNS 的客戶端,而後這個客戶端同時做爲一個明文 DNS 服務器向操做系統提供正常的 DNS 服務。我能夠選擇在每一臺我使用的設備上安裝一個加密 DNS 客戶端(對於 iOS 來講則是 NetworkExtension),我也能夠選擇在家裏假設一個加密 DNS 客戶端而後把路由器 DNS 指向過去,以後家裏全部設備的 DNS 都會跟着變。我選擇了後者,由於這樣作比較方便,也爲我提供了一個折騰 Raspberry Pi 的藉口——我須要把加密 DNS 客戶端部署到 Raspberry Pi 上讓它長期爲家裏的局域網提供 DNS 服務。git

(爲何不用 OpenWRT 呢?由於我家裏已經在用 Eero 來作路由器了,它能夠經過 mesh Wi-Fi 來提供更好的覆蓋。若是我要多買一個 OpenWRT 路由放在 Eero 前面,那我還不如買個 Raspberry Pi 來玩玩呢。)github

Raspberry Pi

我買了這個 Raspberry Pi 套裝,由於它自帶盒子和電源。電源不重要,我家已經有不少 USB 電源,可是我總不能一塊電路板隨便一放吧,因此必須買個盒子。而後我還買了張 64GB 的 microSD。由於我全部 microSD 都是 64GB 的,因此我只買 64GB 的方便有須要時隨意替換。安全

收到 Raspberry Pi 以後,我就按照官方 NOOBS 的指引下載和準備安裝。然而 NOOBS 複製到 SD 卡後不管如何 Raspberry Pi 都沒法正常啓動,只亮紅燈沒有視頻輸出。搜索以後發現綠燈不亮就是沒有讀取 SD 卡進行啓動。我開頭懷疑是我下載的 NOOBS 有問題,因而換成 NOOBS Lite 和 Raspbian,但都是不行。我也懷疑過是否是下載的 zip 數據有問題,但 sha256 checksum 正確。服務器

實在找不到問題了,我就開始搜索到底 Raspberry Pi 是如何進行引導的,發現它必須從 FAT 分區進行引導。Raspberry Pi 本身的官方文檔教你們使用一個叫作 SD Association’s Formatting Tool 的軟件來格式化 SD 卡,但這個軟件在面對超過 32GB 的卡時就會傻傻地使用 exFAT 來進行格式化。其實使用 Mac 內置的 Disk Utility 不就好咯,就算是超過 32GB 的 SD 卡也能夠選擇格式化爲 FAT。網絡

把 SD 格爲 FAT 後,全部問題都解決了。NOOBS 可以正常啓動,接着 Raspbian 也可以順利裝上。Raspberry Pi 安裝好以後我嘗試啓用 VNC 以便我用 Mac 遠程控制,結果那上面裝的 VNC 和 Mac 自帶的 Screen Sharing 客戶端不兼容,我只好降級到用 SSH,不過也能完成絕大多數操做了。架構

啓用 SSH 後 Raspbian 會提醒你改默認密碼,沒有改的話記得改掉,不然太不安全了。由於 Raspbian 連 dig 這麼基本的命令都沒有,須要經過 apt-get 來安裝,因此咱們須要先更新一下而後把 dig 裝上:測試

sudo apt-get update
sudo apt-get install dnsutils

DNS-over-HTTPS

我基本上就是按照 Cloudflare 的 DNS-over-HTTPS 指引 來作的。一開始我以爲 Raspbian 既然是 Debian 系的就下載了 Debian 的安裝包,結果發現安裝不上去。接着嘗試用 Linuxbrew 來裝 homebrew 的版本,結果裝上後發現不能執行。看到「exec format error」而且搜索後才忽然明白到,Raspberry Pi 不是基於 x86/x64 架構的,而是基於 ARM 架構的。那到底 Raspberry Pi 是 32 位仍是 64 位的呢?理論上 Raspberry Pi 3 B+ 是 64 位的 CPU,但在 Raspbian 上執行 uname -a 的話會顯示:網站

Linux raspberrypi 4.9.80-v7+ #1098 SMP Fri Mar 9 19:11:42 GMT 2018 armv7l GNU/Linux

因此其實不是 64 位的,若是要選正確的版本那必須選 32 位的 ARM。只要選擇正確的版本,Cloudflared 和 Dnscrypt-Proxy 都是能夠用的。我兩個都裝了,都能在 localhost:53 上跑起來,最後選擇了 Dnscrypt-Proxy 是由於配置方便。(Dnscrypt-Proxy 有配置文件模板,改改就能夠用了,不須要對着文檔寫一個新的。)加密

Dnscrypt-Proxy 的安裝跟着官方指引作就能夠了,選擇 Linux 版本 來下載。記得下載 Linux ARM 的版本,不要用 Android 或者 ARM64 的版本。(儘管 Dnscrypt-Proxy 是能夠安裝在 Pi-Hole 上面的,但我不想安裝 Pi-Hole 來過濾廣告因此選擇了非 Pi-Hole 的版本。)儘管官方指引叫你檢查一下是否有別的 DNS 服務正在使用 53 端口,但新裝的 Raspbian 應該是不會有任何服務佔用 53 端口的因此這一步能夠略過。

Dnscrypt-Proxy 下載和解壓好以後就能夠開始配置了。假設咱們已經在 Dnscrypt-Proxy 解壓好的目錄裏:

cp example-dnscrypt-proxy.toml dnscrypt-proxy.toml
sudo ./dnscrypt-proxy

這時候 Dnscrypt-Proxy 應該可以跑起來,在 Raspberry Pi 上用 dig 驗證一下就知道了:

dig +short @127.0.0.1 cloudflare.com AAAA

這個驗證必須在 Raspberry Pi 上作,由於 Dnscrypt-Proxy 的默認配置只監聽 localhost:53 端口,從另一臺機器連上來 53 端口是不行的。若是 Dnscrypt-Proxy 正常工做了,咱們就能夠開始改配置了。打開 dnscrypt-proxy.toml,而後把 server_nameslisten_addresses 改掉。(在 SSH 上面,用 nanovi 均可以編輯 dnscrypt-proxy.toml。)

首先找到 server_names,把前面註釋這一行的 # 刪掉,而後把後面的內容改成你想要的服務。由於 Cloudflare 和 Google 都支持 DNS-over-HTTPS,並且都是可靠的大公司,因此我在這兩家之間選。由於 Google 不強調隱私,有可能記錄數據,因此我只用 Cloudflare 的,按照 Cloudflare 的文檔把這一行改成這樣子:

server_names = ['cloudflare', 'cloudflare-ipv6']

接着找到 listen_addresses,你會發現它只監聽 IPv4 和 IPv6 的 localhost,因此其餘機器不能用 Raspberry Pi 來作 DNS。這時候你要想辦法把 Raspberry Pi 的 IP 綁上去。個人作法是這樣子的:由於我家裏路由器的 IP 是 192.168.0.1,而後 DHCP 範圍是 192.168.0.10–192.168.0.199,因此 192.168.0.2–192.168.0.9 是不會被動態分配出去的。我把 Raspberry Pi 的有線網 IP 寫死爲 192.168.0.2,而後把它加到監聽地址端口列表上:

listen_addresses = ['127.0.0.1:53', '[::1]:53', '192.168.0.2:53']

搞掂以後,能夠再啓動一下 Dnscrypt-Proxy:

sudo ./dnscrypt-proxy

而後從另一臺機器使用 dig 測試一下:

dig +short @192.168.0.2 cloudflare.com AAAA

若是沒有問題的話,就能夠把 Dnscrypt-Proxy 當裝系統服務啓動了:

sudo ./dnscrypt-proxy -service install
sudo ./dnscrypt-proxy -service start
sudo systemctl enable dnscrypt-proxy

以後登陸到路由器,把路由器的 DNS 改成 192.168.0.2 就能夠了,家裏全部設備的 DNS 都會通過 Raspberry Pi 上的 Dnscrypt-Proxy 走 DNS-over-HTTPS 鏈接 Cloudflare 服務器。儘管 Dnscrypt-Proxy 的官方指引還說要把 Linux 上的 DNS 客戶端指向 localhost,但由於我暫時不在 Raspberry Pi 上作別的事情因此不在乎 Raspberry Pi 自己發出的 DNS 請求是否加密。只要它做爲 DNS 服務器服務好我家裏的其餘設備就行。

已知問題

上述作法是有一些已知問題的。首先,若是咱們請求使用 SNI 的 HTTPS 服務的話,咱們仍是會明文傳輸域名的,就算 DNS 加密了仍是會存在域名泄漏的狀況。若是多個不一樣證書的 HTTPS 域名要在一個 IP 上共處,那必須使用 SNI 不然 SSL 握手時沒法決定用哪一個證書的密鑰。所以 SNI 常見於跑在雲平臺上的服務,由於雲平臺每每在多個服務之間共享 IP,但每個服務來自不一樣的客戶有不一樣的證書。對於大型網站來講這不常見,由於不管一個大型網站旗下有多少域名,它均可以選擇把全部域名放在同一個證書裏面。

其次,我沒有作 IPv6 的配置,只讓 Dnscrypt-Proxy 綁定了一個 IPv4 地址。這時候若是 IPv6 分配了不同的 DNS,那使用 IPv6 DNS 查詢時仍是會走明文的。若是你所處的網絡徹底不使用 IPv6,那是沒問題的。我知道 Comcast 是會分配 IPv6 地址和 IPv6 DNS 的,因此若是不在路由器上設置 IPv6 DNS(或者是不能設置)的話,那 IPv6 DNS 就有多是 Comcast 分配下來的,也就是明文 DNS。(其餘 ISP 也同樣。)

最後,若是你喜歡個人文章,歡迎經過郵件訂閱個人博客。

相關文章
相關標籤/搜索