Skip to content

riaqn/china-dns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A DNS proxy preventing poisoning and CDN-friendly

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:

LinuxMacOSWindows
x86_64
x86n/a
ARMv7hn/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

Overview

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:

  1. On receiving a request, check if the request is for a foreign domain(--world_name). yes: go to 2; no: go to 3;
  2. Forward the request to foreign DNS and wait for the result.
  3. 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;
  4. wait for response from foreign DNS
  5. 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.

Configuration

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

Running

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.