搭建一个可用的DNS
我发现即便是用ShadowsocksNX全局打开的话,在console下面也不能正常访问一些网站。我想到了有可能这是DNS被污染的原因。
想要验证DNS被污染了其实也非常简单,最好有个WireShark. 先将DNS修改成为8.8.8.8, 然后请求一个被墙的地址比如data.castbox.fm. `dig data.castbox.fm`
可以看到首先返回了两个A分别是66.*** 和 199.***,这两个IP如果查询地理位置的话发现都是facebook.com的IP,而第三个CNAME才是正确的内容.
解决DNS被污染的问题,我突然想到了可以使用ss. 因为之前看ss的代码里面记得有个 `asyncdns.py` 这个文件,专门用于DNS解析的。所以就不加思索地直接试了一把(比如ss在本地62221上) `dig @127.0.0.1 -p 62221 data.castbox.fm` (@是可以指定dns服务器,-p可以使用dns端口)。但是ss有下面这样的错误日志
2017-12-12 22:01:22 WARNING udprelay.py:349 drop a message since frag is not 0 2017-12-12 22:01:27 WARNING udprelay.py:349 drop a message since frag is not 0 2017-12-12 22:02:47 WARNING udprelay.py:349 drop a message since frag is not 0
我大概明白了,ss暴露的62221是支持socks5的tcp/udp端口,不能直接应用于dns. 必须在前面用个组件比如 `dns2socks` 或者是 `ss-tunnel` 。
dns2socks这个软件是C编写的,我希望有个python编写的(这样就不要编译并且可以很容易地在其他地方部署了),所以找到了 `ss-tunnel`. 在我的印象中(阅读ss代码的时候),ss是没有ss-tunnel这个功能的。网上搜索了一下也是在 `shadowsocks-libev` 这个项目下面才有,而这个项目也是C + libev来写的。不过很有趣的是,在shadowsocks的python实现上,有位同学提交了一个python的ss-tunnel实现 https://github.com/shadowsocks/shadowsocks/pull/759 并且已经被合并到了master上面。
使用 `ss-tunnel` 这个需要同时升级client/server才行,并且中间不能走kcptunnel(kcp使用的是tcp协议,而DNS是udp协议)。当然可以在dig里面指定使用tcp来进行解析 `+tcp` 。解析正确了,ss-tunnel运行在65353端口上面。接下来的工作就是结合dnsmasq来做DNS转发了。
➜ ~ dig @127.0.0.1 -p 65353 data.castbox.fm ; <<>> DiG 9.9.7-P3 <<>> @127.0.0.1 -p 65353 data.castbox.fm ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13971 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;data.castbox.fm. IN A ;; ANSWER SECTION: data.castbox.fm. 299 IN CNAME casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. 4 IN A 52.197.248.46 casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. 4 IN A 52.69.132.23 ;; Query time: 81 msec ;; SERVER: 127.0.0.1#65353(127.0.0.1) ;; WHEN: Wed Dec 13 21:30:04 CST 2017 ;; MSG SIZE rcvd: 144
下面在用 `+tcp` 来试试·。ss默认地是同时开启tcp/udprelay功能的。
➜ ~ dig @127.0.0.1 -p 65353 data.castbox.fm +tcp ; <<>> DiG 9.9.7-P3 <<>> @127.0.0.1 -p 65353 data.castbox.fm +tcp ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2132 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;data.castbox.fm. IN A ;; ANSWER SECTION: data.castbox.fm. 299 IN CNAME casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. 59 IN A 52.69.132.23 casbox-elb-1612116034.ap-northeast-1.elb.amazonaws.com. 59 IN A 52.197.248.46 ;; Query time: 186 msec ;; SERVER: 127.0.0.1#65353(127.0.0.1) ;; WHEN: Wed Dec 13 21:34:22 CST 2017 ;; MSG SIZE rcvd: 144
在找到dnsmasq之前,在网上看到了很多dns的软件比如pdnsd, unbound这些。dnsmasq的确不是特别符合我的预期,因为它不支持按照tcp去转发dns请求(这样就没有办法用kcptun做relay了),不过因为我只是打算实验以下,所以就没有继续研究pdnsd, unbound这些软件了。如果要做一个reliable dns的话,支持tcp请求应该是必须的。
按照这个 https://blog.netsh.org/posts/mac-os-x-dnsmasq_1762.netsh.html 来配置dnsmasq, 然后找到了一个项目 https://github.com/cokebar/gfwlist2dnsmasq 可以从gfwlist里面拉取到当前封锁域名然后生成dnsmasq格式。dnsmasq有个缺点就是只能使用UDP请求来解析,看到有一些其他软件比如pdnsd或者是unbound可以使用tcp,不过感觉配置起来有点繁琐。
网上有很多配置,这里也放一下我的配置,供参考。
➜ ~ cat /usr/local/etc/dnsmasq.conf resolv-file=/usr/local/etc/dnsmasq.resolv.conf strict-order no-hosts cache-size=32768 listen-address=127.0.0.1 conf-dir=/usr/local/etc/dnsmasq.d ➜ ~ cat /usr/local/etc/dnsmasq.resolv.conf nameserver 8.8.8.8 nameserver 8.8.4.4 ➜ ~ head /usr/local/etc/dnsmasq.d/dnsmasq_gfwlist.conf # dnsmasq rules generated by gfwlist # Last Updated on 2017-12-13 15:48:46 # server=/030buy.com/127.0.0.1#65353 server=/0rz.tw/127.0.0.1#65353 server=/1-apple.com.tw/127.0.0.1#65353 server=/1000giri.net/127.0.0.1#65353 server=/100ke.org/127.0.0.1#65353 server=/10conditionsoflove.com/127.0.0.1#65353 server=/10musume.com/127.0.0.1#65353
在mac上面为了方便重启,在shell profile里面增加了两个指令
reload_dnsmasq() { sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist sudo launchctl stop homebrew.mxcl.dnsmasq sudo launchctl start homebrew.mxcl.dnsmasq sudo killall -HUP mDNSResponder } unload_dnsmasq() { sudo launchctl stop homebrew.mxcl.dnsmasq sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist }
如果希望全局可以自动分流的话,不仅仅DNS需要自动分流,其他流量(应用流量)也需要分流,这个就需要比如ss-redir/iptables这类软件来支持,配置起来内容就比较多了。如果仅仅是单纯地想得到一个正确的,纯净的dns的话,那么ss + ss-tunnel + dnsmasq就可以完成了。