Intro
放假回家之后,感觉家里的网络状况实在令人堪忧。好在我还是可以科学上网,直到前几天突然连不上了github,which means 无法用 ssh 连上 github。无法用git push
连接远程仓库,也无法ping
通github。使用nslookup
命令查询github.com地址,得到的是错误的地址。因此怀疑是 DNS 污染的问题。
不过急着想 push 上去,为了连上远程仓库,找到了两个解决方法:
使用
https
连接远程仓库:1
2
3
4首先移除ssh连接的远程仓库
git remote remove origin
再连上https
git remote add origin https://github.com/<user_name>/<repo_name>ssh via proxy
使用 ssh 自带的Proxycommand
就可以使用http
代理连接 ssh
首先使用homebrew
安装corkscrew
1
brew install corkscrew
然后配置 ssh
1
vim ~/.ssh/config
在配置中写入
1
2Host *
ProxyCommand corkscrew 127.0.0.1 1079 %h %p
后面的代理地址和端口根据自己情况修改即可。
防止DNS污染
接着就进入正文了,如何防止 DNS 污染。本来我对这些是没有’洁癖’的,我的科学上网需求也仅仅是 Google 和 Youtube 。然而这次 ISP 做得实在过分。于是下定决心清理一下。
DNSmasq
DNSmasq
是一个小巧且方便地用于配置 DNS 和 DHCP 的工具,适用于小型网络,它提供了 DNS 功能和可选择的 DHCP 功能。使用它主要是为了让国内的网址使用国内的 DNS 解析,这样会使速度快很多。目前还不需要它的 DHCP 功能,不过默认也是关闭的,不需要担心。
安装和配置
在 mac 下的安装很方便
1 | brew install dnsmasq |
接着修改配置文件,其实只要打开几个注释,设定一下监听端口即可:
1 | # 不读取有关解析的配置文件,默认使用/etc/revolve.conf中的上游服务器地址进行解析 |
dnsmasq-china-list
的配置文件在这个项目里,它维护了一份中国地区大部分网站的地址。这个列表来可以帮助DNSMasq判断应该把DNS请求发向哪里。
可以直接运行这个命令来下载到配置文件夹:
1 | wget -4 --no-check-certificate -O /usr/local/etc/dnsmasq.d/accelerated-domains.china.conf https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf |
这样,DNSmasq 就配置完成了。
DNScrypt
DNScrypt
是 OpenDNS 出品的一个可以加密 DNS 请求的工具,让你的 DNS 请求能够像使用 ssl 一样加密地请求服务器,这样便从根本上杜绝了 DNS 污染问题。
安装和配置
同样使用 homebrew安装:
1 | brew install dnscrypt-proxy |
然后修改配置文件:
1 | vim /usr/local/etc/dnscrypt-proxy.conf |
这个配置文件改起来很简单,首先(跃入眼帘的是),ProviderName
这一项。
OpenDNS 已经为我们准备好了公共 DNS,我们可以选择一个ping
值比较小的,提供的 DNS 列表在:
1 | cd /usr/local/opt/dnscrypt-proxy/share/dnscrypt-proxy |
然后打开dnscrypt-resolvers.csv
,选择一个 DNS server 然后将第一列的名字属性填到配置文件处即可。
接着需要修改的就是配置文件中的 LocalAddress
,根据在 DNSmasq
中配置的 server端口,改成相同的即可。比如在这个例子中,应该改为:
1 | LocalAddress 127.0.0.1:5353 |
另外,你或许需要将这一行修改为 yes
:
1 | Daemonize yes |
运行 DNSmasq 和 DNScrypt
配置结束之后就可以愉快地使用了。
1 | sudo brew services start dnscrypt-proxy |
记得一定要加上sudo
!之前改配置之后没有加sudo
就 start stop 出现了各种配置没用的情况。
还有最后一步就完成了:
在网络的高级选项中将系统的 DNS 地址改成 127.0.0.1
。当然,你也可以使用命令行直接设置:
1 | sudo networksetup -setdnsservers "Wi-Fi" 127.0.0.1 |
如果你不放心,可以先看一下DNSmasq 和 DNScrypt有没有在工作:
1 | # 查看 dnsmasq |
自建 DNS 服务器
不知道为什么,我在本地搭建好环境,使用远程DNS之后,还是会出现被污染的情况。我猜测可能是因为 OpenDNS 的目标太大了,提供的 DNS 服务器或许会成为 GFW 的目标。当然也有一个可能,是我当时没用 sudo
运行导致了一些奇怪的问题。不过当时实在烦躁的不行,因此直接在 VPS 上自建了一个。
DNScrypt-wrapper —— DNScrypt的服务端
虽然 dnscrypt-proxy 是官方开源的,但是 server 端并没有开源出来,好在有大神 Cofyc 参照 client 写了一个开源的版的 server , dnscrypt-wrapper。
所以我们只需要把它部署在 VPS 上,然后本地的 DNScrypt 配置文件改成连到自己的 VPS 上即可。
DNScrypt-wrapper 的安装
这个安装和之前比起来要麻烦一些,因为它需要依赖 libsodium
和 libevent2
。我的 VPS 的环境是 Ubuntu16.04。以下是我安装的一些包:(其实按照报错来按需安装即可)
1 | apt-get update && apt-get upgrade |
安装 DNScrypt-wrapper
:
1 | git clone --recursive git://github.com/Cofyc/dnscrypt-wrapper.git |
DNScrypt-wrapper 的使用
新建一个文件夹用于保存证书和密钥对,同时还需要产生一个临时的密钥来运行。
1 | cd ~ |
<yourdomain>
就是可以随意取了,比如 2.dnscrypt-cert.ex.com,然后 <external server ip>
填 VPS 的 IP 地址。
接着就会产生一个指纹信息,这个信息就是客户端配置时候需要的 provider_public_key
然后,我们使用命令生成有时限的加密密钥对以及生成预签名证书:
1 | dnscrypt-wrapper --gen-crypt-keypair --crypt-secretkey-file=1.key |
使用命令来运行 dnscrypt-wrapper,用“-VV”来显示比较详细的 debug 信息:
1 | dnscrypt-wrapper --resolver-address=8.8.8.8:53 --listen-address=<external server ip> \ |
我在这里选择是 Google 的 公共 DNS,你可以使用其它的。使用 -d
即可在后台运行。
修改本地 DNScrypt 的配置
打开配置文件,然后将 ResolverName
一栏注释掉,在配置文件中加入:
1 | ProviderName 2.dnscrypt-cert.ex.com |
修改完之后重启 DNScrypt 即可。
1 | sudo brew services restart dnscrypt-proxy |
新的变化
在学校里突然发现也存在DNS污染的问题,于是重新启用 DNScrypt,但是用 homebrew 更新了一下,然后发现配置文件和以前不太一样了,server端也有了更方便的配置方法。因此也做了一下记录。
DNScrypt 2
新的文档在这里。
Server端
Server端已经方便了非常多,文档也讲的相当详细。只要在VPS上安装 docker,然后运行以下命令:
1 | docker run --name=dnscrypt-server -p 443:443/udp -p 443:443/tcp --net=host \ |
不要忘了将上面命令中的ip改为自己的VPS ip地址。还记得要记录运行之后打印出来的 stamp,在配置客户端的时候需要用到。
然后便可以运行以下命令使得 server 端运行并开机自启动。
1 | docker start dnscrypt-server |
客户端
用 homebrew 安装的话,配置文件的路径是/usr/local/etc
,打开dnscrypt-proxy.toml
,与之前相同,将端口改为 dnsmasq 的监听端口,可以把 ipv6 的地址删掉(一般不会用到,可以按需添加。
接着将拉到文件的最底部,修改[static]字段,名字可以随便取,stamp 为之前在 server 端得到的 stamp。
1 | [static.'your_name'] |
之后将最上面的server_names
字段里的值改为你自己刚刚取的名字。最后重启一下服务就 ok 了。