CentOS 7 自建 DNS over HTTPS Server

DNS over HTTPS (DoH) 是一個透過 HTTPS 加密傳輸來查詢網域名稱的協定,主要目的是為了改善使用者的隱私與安全,避免原始 DNS 協定中用戶的 DNS 解析請求被中間人竊聽或者竄改的問題,以達到保護用戶隱私的目的。Mozilla 官方部落格發表了一篇文章:「A cartoon intro to DNS over HTTPS」,裡面以簡單易懂的方式說明了 DoH 的需求原因及原理。

目前 DoH 已有由 IETF 發佈的 RFC 草案,其規範文件為 RFC8484,瀏覽器中 Firefox 及 Chrome 已支援 DoH 功能。

安裝基本套件

要安裝相關套件之前,我們先安裝 git 及 epel-release,其中 git 是用來安裝放在 github 的 doh 測試工具(不想安裝可以略過),而 epel-release 是為了安裝 certbot 的相關套件,來申請 Let’s Encrypt 的憑證。另外,為了讓 doh-proxy 能正常運作,它需要 python 3.5 以上版本,epel-release 裡面也包含了 python36 可供使用。

yum -y install git epel-release

安裝與設定 doh-proxy

在安裝 doh-proxy 之前,先安裝它運作時的需求相關套件:

yum -y install python36 python36-pip python36-devel

doh-proxy 套件包裝及上傳存放在 pypi 中,所以可以簡單地使用下列指令安裝它:

pip3.6 install doh-proxy

接下來建立 doh-proxy 運作需要的帳號及家目錄:

adduser -r doh-proxy \
-d /var/lib/doh-proxy \
-c 'DOH Proxy server' \
-s /sbin/nologin \
-U
mkdir /var/lib/doh-proxy \
&& chown doh-proxy.doh-proxy /var/lib/doh-proxy

製作 systemd 的 unit file,我們設定讓它監聽 8080 埠:

cat <<EOF > /usr/lib/systemd/system/doh-httpproxy.service
[Unit]
Description=DOH HTTP Proxy on 8080
After=syslog.target network.target
Before=nginx.target

[Service]
Type=simple
ExecStart=/usr/local/bin/doh-httpproxy --upstream-resolver ::1 --level DEBUG --listen-address=::1 --port 8080
Restart=always
User=doh-proxy
Group=doh-proxy

[Install]
WantedBy=multi-user.target

EOF

systemctl daemon-reload

設定開機時會自動啟動服務,並啟動它:

systemctl enable doh-httpproxy
systemctl start doh-httpproxy

以上,doh-proxy 就安裝並啟動完成,用 netstat -ntlp 應該可以看到正在監聽 8080 埠,啟動程式是 python3。

安裝與設定 named

接下來要安裝一個協助到外界代查 DNS 結果的解析伺服器,因為對 bind 比較熟,所以就安裝 named 囉:

yum -y install bind
systemctl enable named
systemctl start named

檢查一下 named 服務正常:

host www.google.com ::1

服務正常的話,應該會得到 IPv4 及 IPv6 的回應位址。

安裝與設定 nginx:

最後,我們安裝、設定 nginx,並安裝 certbot-nginx 以取得 Let’s Encrypt 的憑證:

yum -y install nginx certbot-nginx
systemctl enable nginx systemctl start nginx

開啟防火牆:

firewall-cmd --add-service=http --add-service=https --permanent
firewall-cmd --reload

接下來要使用 certbot 取得憑證,在這裡我用的是 doh.ishm.idv.tw 作為憑證申請的網址,先要確認自己想要申請的網址(FQDN)是正確且可連上。

certbot --nginx -n --redirect -d doh.ishm.idv.tw

現在,要設定的是啟動 HTTP2 協定,並設定 NGINX 將 doh-proxy 作為後端服務。

開啟 /etc/nginx/nginx.conf 並尋找下列兩行:

listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot

將它改成:

listen [::]:443 ssl http2 ipv6only=on; # managed by Certbot
listen 443 ssl http2; # managed by Certbot

設定 nginx 只允許 HEAD、GET 及、POST 的要求:

if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 501;
}

接下來,要設定 /dns-query 所取得的所有資訊,都送到後端的 doh-proxy。

在相同的 server { } 區段內 (也就是 443 的區段),找到下列子區段:

location / {
}

改成這樣:

location /dns-query {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://dohproxy_backend;
}

然後找到下列區段的開頭 (也就是 SSL 設定的 server { } 區段):

server {
server_name doh.ishm.idv.tw; # managed by Certbot

在區段的開頭「之前」,加入下列 doh-proxy 後端服務的監聽埠資訊:

upstream dohproxy_backend {
server [::1]:8080;
}
server {
server_name doh.ishm.idv.tw; # managed by Certbot
.............

存檔後重啟 NGINX:

systemctl restart nginx

設定 SELinux 開放 NGINX 連線到 doh-proxy 的限制:

setsebool -P httpd_can_network_connect=true

 

doh-client 指令測試

doh-proxy 安裝好後就有一個用戶端工具程式 doh-client 可供測試,預設是查詢 AAAA 的結果,如果想查詢不同的 TYPE,可以用 –qtype 選項來指定要查詢的 Query TYPE:

doh-client --domain doh.ishm.idv.tw --qname www.google.com

瀏覽器測試

Firefox 及 Chrome 已支援 DoH 的使用,Firefox 到選單-選項-網路設定裡做設定:

chorme 直接使用選項開啟連結,當然其中的參數改成自己建置的 DoH 網址:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --enable-features="dns-over-https<DoHTrial" --force-fieldtrials="DoHTrial/Group1" --force-fieldtrial-params="DoHTrial.Group1:server/https%3A%2F%2Fdoh.ishm.idv.tw%2Fdns-query/method/POST

Firefox 可以在網址列輸入「about:networking#dns」,即可看到是否透過 TRR 來查詢 DNS,TRR 是指可信賴的 DNS 遞迴解析伺服器(Trusted Recursive Resolver,TRR),也就是我們的 DoH Server。

curl 指令測試

DoH 有許多開放的伺服器可供使用,也有不少工具可應用,可參考這裡,其中 curl 算是比較熟悉的程式。curl 的維護者 Daniel Stenberg 於 2018 年 9 月宣佈 curl 將會支援 DNS over HTTPS,該版本 7.62.0 將於 2018 年 10 月釋出。CentOS 7 預載的 curl 用 curl -V 查看,是 7.29.0 版本,所以要用 curl 測試就要先升級,我們下載官網的 srouce code 來自行編譯。不過編譯前先準備好 compiler 的環境:

yum -y install openssl-devel gcc

然後去 curl 的官網下載 source code,我現在下載的是 7.66.0,您可能下載到更新的版本:

wget https://curl.haxx.se/download/curl-7.66.0.tar.gz
tar zxf curl-7.66.0.tar.gz
cd curl-7.66.0/
./configure
make
make install

如果覺得自行編譯很麻煩,另外有一個已經由 city-fan.org 編好的 curl 最新版本,因為它是已知的問題軟件庫安裝前請審慎評估。不過如果只是測試用,用完就虛擬機快照還原,那也不失為一個快速安裝來測試用的途徑:

rpm -Uvh http://www.city-fan.org/ftp/contrib/yum-repo/rhel7/x86_64/city-fan.org-release-2-1.rhel7.noarch.rpm
yum --enablerepo=city-fan.org install libcurl libcurl-devel

安裝好後,可用 curl -V 看一下版本,沒問題就可以用 –doh-url 選項來操作:

curl --doh-url https://doh.ishm.idv.tw/dns-query https://www.google.com

doh 指令測試

另有一個好用的工具 doh 可供使用,它是基於 curl 的工具,能透過 DoH 查詢 DNS 的結果,但要自己編譯:

git clone https://github.com/curl/doh.git
cd doh
make
make install
make clean

doh 的預設 TRR 是 https://dns.cloudflare.com/dns-query,如果要使用自建的 DoH,那就自己帶參數:

doh www.google.com https://doh.ishm.idv.tw/dns-query

DNS over HTTPS 目前還在實驗性階段,RFC8484 還是草案,目前就只能透過瀏覽器內建的 DoH 功能來執行查詢,沒有作業系統本身的支援。或許要等到 DoH 的外掛或代理程式出來,自建 DoH 的需求才會大。