使用公共 DNS 服務可以避免運營商的 DNS 劫持,但除了這個外在兲朝還存在着 DNS 緩存污染的問題,以前使用 GoAgent 等工具時沒有注意到這個,一直在運行着的 dnsmasq 也只用來作簡單的緩存服務,最近開始長時間掛着 VPN 有時卻打不開 Twitter,才發現是這個問題在作怪。
分析
在中國大陸,對於所有經過防火長城的在UDP的53埠上的域名查詢進行IDS入侵檢測,一經發現與黑名單關鍵詞相匹配的域名查詢請求,其會馬上偽裝成標的域名的解析伺服器給查詢者返回虛假結果。由於通常的域名查詢沒有任何認證機制,而且域名查詢通常基於的UDP協議是無連線不可靠的協議,查詢者只能接受最先到達的格式正確結果,並丟棄之後的結果。
也就是說就算使用的是牆外的 DNS 服務器也仍然會被污染。像我的情況,因爲使用了本地的 DNS 緩存服務和 chnroutes 的原因,不是所有的 DNS 記錄都是使用 VPN 通道的 DNS 服務器查詢的,所以出現了掛着 VPN 卻打不開 Twitter 的情況,DNS 查詢到的是錯誤的 ip。
思路
- 連接 VPN 後重啓 DNS 緩存服務,只對於像我這樣使用 VPN 且本地有緩存服務的,只需要在之前設置的連接腳本裏加上重啓服務的命令就行(當然還需要把緩存服務的上遊 DNS 設成牆外的服務器)
- 使用 tcp 方式查詢,tcp 的 DNS 請求會出現被 reset 的情況
- 把 DNS 服務轉發到非標準端口,這個需要自己有牆外的服務器資源
- 使用提供非標準端口服務的 DNS,只有很少的服務器支持
因爲提供非標準端口服務的 DNS 太少,而且在我這兒速度都不快,權衡來看,可以優先使用不算太穩定的 tcp 方式查詢,把非標準端口的 upd 查詢作爲 fallback,對於 linux 來說可以通過設置防火牆規則定義 DNS 存取方式,不過還是推介配置本地的 DNS 轉發服務更爲簡單方便。
因爲之前一直用的 dnsmasq 不支持 tcp 方式查詢,Google 發現了 pdnsd 後就立即換了上來,相對於 dnsmasq 來說功能單一,但更爲強大,單就作 DNS 緩存來說 dnsmasq 就不能修改 TTL。
操作
對於 Arch 來說直接 yaourt -S pdnsd
安裝就好,然後創建配置文件
sudo cp /etc/pdnsd.conf.sample /etc/pdnsd.conf
修改配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
|
全局配置中 query_method
可以設爲 tcp_only,我設置成 tcp_udp 優先使用 tcp 方式查詢所以還得設置 tcp_qtimeout
,tcp 方式查詢超時就放棄。
我把 ISP 或者國內的 DNS 服務器放到了最前面,只查詢指定的域名,解決某些國內網站因爲是國外 DNS 請求而返回了過慢的 CDN 線路的 ip,網站列表來源於 http://felixc.at/Dnsmasq ,之後先放上提供非標準端口服務的 DNS 服務器,在 tcp 無法查詢轉而使用 udp 方式時使用非標準端口避免 DNS 污染,最後放上我常用的中華電信和 Google 的 DNS,都支持 tcp 方式查詢。
啓動服務
sudo systemctl start pdnsd.service
設爲開機啓動
sudo systemctl enable pdnsd.service
測試
使用本地的轉發服務查詢 twitter.com 返回正確 ip,說明在服務器最前列的國內的 DNS 的確沒查詢列表外的域名。
疑難解答
系統啓動時不可用
因爲 pdnsd 服務啓動時網絡還沒連接上,服務器無法通過檢測被忽略,導致無服務器可進行查詢,請將至少將一組服務器中的 uptest
設爲 none,並設置 preset
爲 on,讓服務器初始爲可用。
後記
從之後的測試來看上面的方案並不可靠,原本優先使用 tcp 的原因是希望有更好的速度,但爲了預防查詢失敗仍然不得不把支持非標準端口查詢但在我這兒速度較慢的服務器放在前列,這樣還不如直接用非標準端口的 udp 方式從這些服務器查詢,而且在 tcp_udp 模式下,tcp 查詢超時就會轉而使用 udp 方式,但 tcp 請求被重置,會被當作 negative 結果返回,這樣的話就要把 neg_domain_pol
設爲 off,不緩存 negative 結果,要不很長一段時間都無法訪問這域名,但所有的 negative 結果都不緩存的話,會增加不必要的查詢請求,耗費資源。
總之,現階段最好的方案是直接使用非標準端口的 udp 查詢,把 query_method
設成 udp_only,刪去不支持非標準端口查詢的服務器,要是自已有境外的服務器資源的話,可以把自己要用的 DNS 服務器轉發到非標準端口來用。