I’m looking for statically compiled binary for every platform. If you’re willing to contribute, please contact me at zhina dash dns at riaqn dot org
Available binary versions so far:
Linux | MacOS | Windows | |
---|---|---|---|
x86_64 | ✓ | ✓ | |
x86 | n/a | ||
ARMv7h | ✓ | n/a | |
… |
Please see the Release page for downloads.
I’m developing this project because the existing ChinaDNS occasionally behaves wierd, so I would rather write one by myself. I’m using Haskell because of:
- high concurrency
- static type safety
- efficient development
This program assumes:
- access to the TCP port 53 on the foreign DNS is proxy-ed(ss-redir, VPN, etc.), or you will still be poisoned.
- this proxy has to be the same host you use to proxy other traffic (http, etc.), otherwise we couldn’t guarantee a CDN-optimal result.
The built-in resolution strategy:
- On receiving a request, check if the request is for a foreign
domain(
--world_name
). yes: go to 2; no: go to 3; - Forward the request to foreign DNS and wait for the result.
- Forward the request to Chinese and foreign DNS at the same time.
Check if the response from Chinese DNS contains foreign
IP(
--china_ip
). yes: go to 4; no: go to 5; - wait for response from foreign DNS
- return Chinese result immediately.
Note: only TCP is used for foreign DNS.
If you have any thoughts about the resolution strategy, please feel free to share it on the issue page.
Usage: zhina-dns [--host HOST] [--port PORT] [--zhina_host HOST] [--zhina_port PORT] [--world_host HOST] [--world_port PORT] [--zhina_timeout MICROSEC] [--world_timeout MICROSEC] [--log_level SPEC] --zhina_ip PATH --world_name PATH a DNS proxy for people in Zhina Available options: -h,--help Show this help text --host HOST hostname to bind (default: Nothing) --port PORT port number to bind (default: "5300") --zhina_host HOST upstream Chinese server host (default: "114.114.114.114") --zhina_port PORT upstream Chinese server port (default: "53") --world_host HOST upstream foreign server host (default: "8.8.8.8") --world_port PORT upstream foreign server port (default: "53") --zhina_timeout MICROSEC timeout for Chinese upstream, UDP and TCP combined (default: 1000000) --world_timeout MICROSEC timeout for foreign upstream, UDP and TCP combined (default: 5000000) --log_level SPEC spec for logging (default: [("",INFO)]) --zhina_ip PATH file containing Chinese IP ranges --world_name PATH file containing foreign domain names
Please fork this repository for more fine-grained modifications; feel free to drop a pull request if you think your modifications may be also useful to others.
- for modifications of upstream servers/local servers, see src/Main.hs
- for modifications of the resolution strategy, see src/ZhinaDNS.hs
This program needs a list of Chinese IP ranges and a list of foreign domain names on startup. The formats of both are similar and is as follows:
# this is allowed # this is also allowed #^ empty line (with or without spaces) is allowed #v ip range prefixed or suffixed with spaces is allowed 1.0.1.0/24 #v single ip address is also allowed 127.0.0.1
Both files are shipped with the project already: check out china.txt
and world.txt. However, if you prefer generating these files yourself,
please check out china.awk (for china.txt
) and
https://github.com/cokebar/gfwlist2dnsmasq (for world.txt
).
And we are free to go:
./zhina-dns --zhina_ip china.txt --world_name world.txt
Since every request to zhina-dns
involves a request to the foreign
DNS(if it’s a foreign website), the latency may be quite high(as
high as 300ms), it’s thus strongly recommended to wrap a layer of
pdnsd
or unbound
as DNS cache. I had some problems with pdnsd
, so
unbound
maybe better. An example of unbound.conf
:
server:
verbosity: 3
interface: 127.0.0.1
use-syslog: yes
username: "unbound"
directory: "/etc/unbound"
do-not-query-localhost: no
forward-zone:
name: "."
forward-addr: 127.0.0.1@5300
do-not-query-localhost: no
overrides the restriction of unbound
that
local servers can’t be used as upstream server.