├── chinadns ├── __init__.py └── dnsrelay.py ├── tests ├── twitter.com ├── google.com ├── facebook.com ├── www.facebook.com └── iplist.py ├── py2exe_make.bat ├── config.json ├── .gitignore ├── .travis.yml ├── CHANGES ├── setup.py ├── LICENSE ├── test.py ├── README.rst ├── README.md └── iplist.txt /chinadns/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | -------------------------------------------------------------------------------- /tests/twitter.com: -------------------------------------------------------------------------------- 1 | dig @127.0.0.1 any twitter.com -------------------------------------------------------------------------------- /tests/google.com: -------------------------------------------------------------------------------- 1 | dig @127.0.0.1 +tcp any google.com -------------------------------------------------------------------------------- /tests/facebook.com: -------------------------------------------------------------------------------- 1 | dig @127.0.0.1 any facebook.com 2 | -------------------------------------------------------------------------------- /tests/www.facebook.com: -------------------------------------------------------------------------------- 1 | dig @127.0.0.1 any www.facebook.com 2 | -------------------------------------------------------------------------------- /py2exe_make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | rd /s /q build 3 | rd /s /q dist 4 | python py2exe_setup.py py2exe 5 | rd /s /q build 6 | pause 7 | @echo on 8 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server":"my_server_ip", 3 | "server_port":8388, 4 | "local_address": "127.0.0.1", 5 | "local_port":53, 6 | "password":null, 7 | "method":"aes-256-cfb", 8 | "dns":"8.8.8.8" 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | 3 | # Packages 4 | *.egg 5 | *.egg-info 6 | dist 7 | build 8 | eggs 9 | parts 10 | bin 11 | var 12 | sdist 13 | develop-eggs 14 | .installed.cfg 15 | 16 | # Installer logs 17 | pip-log.txt 18 | 19 | # Unit test / coverage reports 20 | .coverage 21 | .tox 22 | 23 | #Translations 24 | *.mo 25 | 26 | #Mr Developer 27 | .mr.developer.cfg 28 | 29 | .DS_Store 30 | .idea 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 2.7 4 | - pypy 5 | before_install: 6 | - sudo apt-get update -qq 7 | - sudo apt-get install -qq dnsutils build-essential 8 | - pip install shadowsocks pep8 pyflakes 9 | script: 10 | - pep8 . 11 | - pyflakes . 12 | - python test.py -c tests/facebook.com 13 | - python test.py -c tests/google.com 14 | - python test.py -c tests/twitter.com 15 | - python test.py -c tests/www.facebook.com 16 | -------------------------------------------------------------------------------- /tests/iplist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from subprocess import Popen, PIPE 4 | 5 | if __name__ == '__main__': 6 | result = set() 7 | for i in range(400, 1400): 8 | p = Popen((('dig +short @114.114.114.114 a ' 9 | 'r%d-1.googlevideo.com') % i).split(), 10 | stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) 11 | output = p.stdout.read() 12 | if output: 13 | result.add(output.strip()) 14 | for r in result: 15 | print r 16 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 0.2.3 2 | - Update IP 3 | 4 | 0.2.2 5 | - Bump shadowsocks 6 | 7 | 0.2.1 8 | - Fix Windows 10048 9 | 10 | 0.2.0 11 | - Support addr:port 12 | 13 | 0.1.11 14 | - Fix dig txt youtube.com 15 | 16 | 0.1.10 17 | - Support multiple DNS 18 | 19 | 0.1.9 20 | - Support -p BIND_PORT 21 | 22 | 0.1.8 23 | - Support /etc/hosts 24 | 25 | 0.1.6 26 | - Fix ERRNO 10054 on Windows 27 | 28 | 0.1.5 29 | - Output error when port is used 30 | - Handle POLL_HUP 31 | 32 | 0.1.3 33 | - Support -b listen address 34 | - Support -s configure DNS server 35 | 36 | 0.1.2 2014-06-22 37 | - Some fixes 38 | 39 | 0.1 2014-06-22 40 | - Initial version 41 | 42 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | with open('README.rst') as f: 5 | long_description = f.read() 6 | 7 | setup( 8 | name="chinadns", 9 | version="0.2.3", 10 | license='MIT', 11 | description="A DNS forwarder that ignore incorrect responses", 12 | author='clowwindy', 13 | author_email='clowwindy42@gmail.com', 14 | url='https://github.com/clowwindy/ChinaDNS', 15 | packages=['chinadns'], 16 | package_data={ 17 | 'chinadns': ['README.rst', 'LICENSE', 'config.json'] 18 | }, 19 | install_requires=[ 20 | 'shadowsocks>=2.2' 21 | ], 22 | entry_points=""" 23 | [console_scripts] 24 | chinadns = chinadns.dnsrelay:main 25 | """, 26 | classifiers=[ 27 | 'License :: OSI Approved :: MIT License', 28 | 'Programming Language :: Python :: 2', 29 | 'Programming Language :: Python :: 2.7', 30 | 'Topic :: Internet :: Proxy Servers', 31 | ], 32 | long_description=long_description, 33 | ) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Shadowsocks 2 | 3 | Copyright (c) 2014 clowwindy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | sys.path.insert(0, 'shadowsocks') 6 | import os 7 | import signal 8 | import select 9 | from subprocess import Popen, PIPE 10 | 11 | with open(sys.argv[-1]) as f: 12 | dig_cmd = f.read() 13 | p1 = Popen(['sudo', sys.executable, 'chinadns/dnsrelay.py'], shell=False, 14 | bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) 15 | p2 = None 16 | 17 | try: 18 | local_ready = False 19 | server_ready = False 20 | fdset = [p1.stdout, p1.stderr] 21 | while True: 22 | r, w, e = select.select(fdset, [], fdset) 23 | if e: 24 | break 25 | 26 | for fd in r: 27 | line = fd.readline() 28 | sys.stdout.write(line) 29 | if line.find('starting dns') >= 0: 30 | local_ready = True 31 | 32 | if local_ready and p2 is None: 33 | p2 = Popen(dig_cmd.split(), shell=False, bufsize=0, close_fds=True) 34 | break 35 | 36 | if p2 is not None: 37 | r = p2.wait() 38 | if r == 0: 39 | print 'test passed' 40 | sys.exit(r) 41 | 42 | finally: 43 | for p in [p1, p2]: 44 | try: 45 | os.kill(p.pid, signal.SIGTERM) 46 | except OSError: 47 | pass 48 | 49 | sys.exit(-1) 50 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ChinaDNS 2 | ======== 3 | 4 | |PyPI version| |Build Status| 5 | 6 | A DNS forwarder that ignores incorrect(you know it) responses. 7 | 8 | Install 9 | ------- 10 | 11 | :: 12 | 13 | pip install chinadns 14 | 15 | or 16 | 17 | :: 18 | 19 | easy_intall chinadns 20 | 21 | Usage 22 | ----- 23 | 24 | Run ``sudo chinadns`` on your local machine. ChinaDNS creates a DNS 25 | server at ``127.0.0.1:53``. 26 | 27 | Set your DNS to 127.0.0.1 and you're done. 28 | 29 | :: 30 | 31 | $ nslookup www.youtube.com 32 | Server: 127.0.0.1 33 | Address: 127.0.0.1#53 34 | 35 | Non-authoritative answer: 36 | www.youtube.com canonical name = youtube-ui.l.google.com. 37 | youtube-ui.l.google.com canonical name = youtube-ui-china.l.google.com. 38 | Name: youtube-ui-china.l.google.com 39 | Address: 173.194.72.102 40 | Name: youtube-ui-china.l.google.com 41 | Address: 173.194.72.101 42 | Name: youtube-ui-china.l.google.com 43 | Address: 173.194.72.113 44 | Name: youtube-ui-china.l.google.com 45 | Address: 173.194.72.100 46 | Name: youtube-ui-china.l.google.com 47 | Address: 173.194.72.139 48 | Name: youtube-ui-china.l.google.com 49 | Address: 173.194.72.138 50 | 51 | Advanced 52 | -------- 53 | 54 | :: 55 | 56 | $ chinadns -h 57 | usage: chinadns [-h] [-b BIND_ADDR] [-s DNS] 58 | 59 | Forward DNS requests. 60 | 61 | optional arguments: 62 | -h, --help show this help message and exit 63 | -b BIND_ADDR, --local_address BIND_ADDR 64 | address that listens, default: 127.0.0.1 65 | -s DNS, --dns DNS DNS server to use, default: 8.8.8.8 66 | 67 | License 68 | ------- 69 | 70 | MIT 71 | 72 | Bugs and Issues 73 | --------------- 74 | 75 | Please visit `Issue 76 | Tracker `__ 77 | 78 | Mailing list: http://groups.google.com/group/shadowsocks 79 | 80 | .. |PyPI version| image:: https://img.shields.io/pypi/v/chinadns.svg?style=flat 81 | :target: https://pypi.python.org/pypi/chinadns 82 | .. |Build Status| image:: https://img.shields.io/travis/clowwindy/ChinaDNS/master.svg?style=flat 83 | :target: https://travis-ci.org/clowwindy/ChinaDNS 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ChinaDNS-Python 2 | =============== 3 | 4 | [![PyPI version]][PyPI] [![Build Status]][Travis CI] 5 | 6 | Fix [weird things] with DNS in China. 7 | 8 | [ChinaDNS-C] is more advanced and well maintained. Please use it instead. 9 | 10 | Actually, I'm not working on the Python version anymore. 11 | New maintainers are welcome. Just send several pull requests and let 12 | me know. You can begin with some features that have already 13 | been implemented in ChinaDNS-C. 14 | 15 | Install 16 | ------- 17 | 18 | * Linux / OS X 19 | 20 | * [ChinaDNS-C] 21 | 22 | * Windows 23 | 24 | * [Download] 25 | 26 | * OpenWRT 27 | 28 | * [ChinaDNS-C] 29 | 30 | Usage 31 | ----- 32 | 33 | Run `sudo chinadns` on your local machine. ChinaDNS creates a DNS server at 34 | `127.0.0.1:53`. 35 | 36 | Set your DNS to 127.0.0.1 and you're done. 37 | 38 | $ nslookup www.youtube.com 39 | Server: 127.0.0.1 40 | Address: 127.0.0.1#53 41 | 42 | Non-authoritative answer: 43 | www.youtube.com canonical name = youtube-ui.l.google.com. 44 | youtube-ui.l.google.com canonical name = youtube-ui-china.l.google.com. 45 | Name: youtube-ui-china.l.google.com 46 | Address: 173.194.72.102 47 | Name: youtube-ui-china.l.google.com 48 | Address: 173.194.72.101 49 | Name: youtube-ui-china.l.google.com 50 | Address: 173.194.72.113 51 | Name: youtube-ui-china.l.google.com 52 | Address: 173.194.72.100 53 | Name: youtube-ui-china.l.google.com 54 | Address: 173.194.72.139 55 | Name: youtube-ui-china.l.google.com 56 | Address: 173.194.72.138 57 | 58 | Advanced 59 | -------- 60 | 61 | usage: chinadns [-h] [-b BIND_ADDR] [-p BIND_PORT] [-s DNS] 62 | 63 | Forward DNS requests. 64 | 65 | optional arguments: 66 | -h, --help show this help message and exit 67 | -b BIND_ADDR, --local_address BIND_ADDR 68 | address that listens, default: 127.0.0.1 69 | -p BIND_PORT, --local_port BIND_PORT 70 | port that listens, default: 53 71 | -s DNS, --dns DNS DNS server to use, default: 72 | 114.114.114.114,208.67.222.222,8.8.8.8 73 | 74 | License 75 | ------- 76 | MIT 77 | 78 | Bugs and Issues 79 | ---------------- 80 | Please visit [Issue Tracker] 81 | 82 | Mailing list: http://groups.google.com/group/shadowsocks 83 | 84 | 85 | [bad IPs]: https://github.com/clowwindy/ChinaDNS-Python/blob/master/iplist.txt 86 | [Build Status]: https://img.shields.io/travis/clowwindy/ChinaDNS-Python/master.svg?style=flat 87 | [ChinaDNS-C]: https://github.com/clowwindy/ChinaDNS 88 | [Download]: https://sourceforge.net/projects/chinadns/files/dist/ 89 | [Fake IP]: https://github.com/clowwindy/ChinaDNS/issues/42 90 | [Issue Tracker]: https://github.com/clowwindy/ChinaDNS-Python/issues?state=open 91 | [PyPI]: https://pypi.python.org/pypi/chinadns 92 | [PyPI version]: https://img.shields.io/pypi/v/chinadns.svg?style=flat 93 | [Shadowsocks]: https://github.com/clowwindy/shadowsocks 94 | [Travis CI]: https://travis-ci.org/clowwindy/ChinaDNS-Python 95 | [weird things]: http://en.wikipedia.org/wiki/Great_Firewall_of_China#Blocking_methods 96 | -------------------------------------------------------------------------------- /iplist.txt: -------------------------------------------------------------------------------- 1 | 1.1.127.45 2 | 1.1.67.51 3 | 1.2.3.4 4 | 1.209.208.200 5 | 1.226.83.147 6 | 1.234.21.83 7 | 1.234.29.40 8 | 1.234.39.14 9 | 1.234.4.91 10 | 1.234.70.80 11 | 1.234.83.104 12 | 1.244.115.172 13 | 1.33.170.68 14 | 1.33.188.62 15 | 1.33.190.228 16 | 1.33.190.70 17 | 1.33.191.58 18 | 104.200.31.226 19 | 104.28.1.22 20 | 104.28.14.112 21 | 104.28.20.14 22 | 104.28.30.59 23 | 106.186.120.157 24 | 106.187.39.80 25 | 107.6.34.101 26 | 108.168.215.230 27 | 108.168.250.3 28 | 108.179.196.77 29 | 108.179.250.106 30 | 108.61.250.218 31 | 109.123.115.205 32 | 109.206.173.212 33 | 109.234.159.38 34 | 109.71.81.130 35 | 110.173.154.142 36 | 110.74.163.40 37 | 112.175.60.31 38 | 113.11.194.190 39 | 113.160.102.90 40 | 118.145.17.184 41 | 118.219.253.245 42 | 118.5.49.6 43 | 119.18.62.130 44 | 119.235.57.82 45 | 119.245.217.155 46 | 119.9.94.83 47 | 12.87.133.0 48 | 120.89.93.248 49 | 122.214.2.171 50 | 122.218.101.190 51 | 123.126.249.238 52 | 123.30.175.29 53 | 123.50.49.171 54 | 125.230.148.48 55 | 127.0.0.2 56 | 128.121.126.139 57 | 128.199.180.162 58 | 133.192.181.66 59 | 133.242.165.24 60 | 133.42.48.3 61 | 137.135.129.175 62 | 14.102.249.18 63 | 141.101.118.102 64 | 141.8.195.47 65 | 141.8.195.78 66 | 141.8.225.80 67 | 142.4.5.109 68 | 144.76.106.232 69 | 144.76.127.114 70 | 144.76.21.13 71 | 145.253.183.23 72 | 147.87.244.32 73 | 155.92.182.118 74 | 157.205.32.64 75 | 157.7.143.209 76 | 159.106.121.75 77 | 159.253.20.179 78 | 159.50.88.77 79 | 16.63.155.0 80 | 162.159.243.101 81 | 162.243.137.163 82 | 162.253.33.134 83 | 164.109.96.232 84 | 164.138.221.68 85 | 168.156.168.21 86 | 169.132.13.103 87 | 171.17.130.53 88 | 171.25.204.141 89 | 173.192.219.59 90 | 173.194.127.144 91 | 173.201.216.6 92 | 173.224.209.14 93 | 173.236.228.108 94 | 173.244.184.10 95 | 173.255.194.174 96 | 173.255.230.196 97 | 174.142.113.142 98 | 174.142.22.25 99 | 176.10.37.81 100 | 176.57.216.145 101 | 178.18.82.216 102 | 178.236.177.77 103 | 178.32.111.136 104 | 178.32.156.59 105 | 178.32.247.82 106 | 178.33.212.162 107 | 178.49.132.135 108 | 178.62.242.156 109 | 178.62.75.99 110 | 178.79.182.248 111 | 180.153.225.168 112 | 180.179.171.121 113 | 180.87.182.227 114 | 181.224.155.41 115 | 183.111.141.95 116 | 184.154.10.146 117 | 184.169.132.244 118 | 184.72.253.232 119 | 185.25.150.45 120 | 185.53.61.50 121 | 188.132.250.186 122 | 188.165.31.24 123 | 188.226.207.251 124 | 188.40.108.13 125 | 188.5.4.96 126 | 189.163.17.5 127 | 192.104.44.6 128 | 192.121.151.106 129 | 192.67.198.6 130 | 192.95.98.202 131 | 193.105.145.158 132 | 193.169.66.88 133 | 193.203.48.18 134 | 193.234.233.149 135 | 193.238.151.98 136 | 193.239.132.44 137 | 193.48.96.218 138 | 193.57.244.117 139 | 193.91.26.132 140 | 194.149.250.20 141 | 194.185.115.1 142 | 194.187.94.6 143 | 194.67.144.70 144 | 195.146.235.33 145 | 195.149.210.211 146 | 195.154.243.151 147 | 195.191.149.103 148 | 195.2.88.68 149 | 195.211.72.200 150 | 195.43.82.170 151 | 195.49.201.30 152 | 195.50.195.15 153 | 195.74.38.62 154 | 195.74.78.21 155 | 195.77.241.242 156 | 195.8.125.64 157 | 197.4.4.12 158 | 198.143.143.36 159 | 198.57.205.133 160 | 198.57.222.88 161 | 198.58.124.68 162 | 199.167.31.142 163 | 199.21.68.222 164 | 199.79.63.83 165 | 2.1.1.2 166 | 2.187.253.121 167 | 2.228.123.7 168 | 2.228.154.8 169 | 20.139.56.0 170 | 200.229.206.115 171 | 200.98.234.14 172 | 201.77.211.143 173 | 202.106.1.2 174 | 202.181.7.85 175 | 202.218.219.10 176 | 202.6.96.25 177 | 203.113.173.22 178 | 203.133.238.172 179 | 203.161.230.171 180 | 203.199.57.81 181 | 203.98.7.65 182 | 206.108.51.91 183 | 206.113.150.70 184 | 207.12.88.98 185 | 207.126.59.27 186 | 207.140.149.247 187 | 207.58.177.166 188 | 208.109.138.55 189 | 208.109.205.232 190 | 208.112.102.122 191 | 208.43.134.107 192 | 208.43.33.194 193 | 208.56.31.43 194 | 208.73.211.164 195 | 208.86.154.112 196 | 208.93.0.150 197 | 209.116.71.109 198 | 209.126.106.182 199 | 209.141.48.35 200 | 209.145.54.50 201 | 209.188.7.186 202 | 209.204.148.22 203 | 209.220.30.174 204 | 209.235.224.25 205 | 209.36.73.33 206 | 209.43.1.130 207 | 209.56.158.42 208 | 209.62.154.94 209 | 209.85.229.138 210 | 210.175.255.154 211 | 210.209.110.199 212 | 210.230.192.183 213 | 211.43.203.33 214 | 211.5.133.18 215 | 211.8.69.27 216 | 211.94.66.147 217 | 212.227.98.130 218 | 212.45.52.219 219 | 212.68.42.67 220 | 212.77.104.29 221 | 213.108.66.21 222 | 213.133.111.102 223 | 213.169.251.35 224 | 213.174.158.108 225 | 213.186.33.5 226 | 213.19.161.141 227 | 213.207.85.148 228 | 213.238.166.227 229 | 216.12.205.2 230 | 216.139.213.144 231 | 216.178.241.101 232 | 216.198.246.103 233 | 216.221.188.182 234 | 216.234.179.13 235 | 216.250.115.144 236 | 216.38.0.92 237 | 216.70.88.29 238 | 216.92.58.37 239 | 217.160.42.85 240 | 217.172.183.9 241 | 217.30.184.161 242 | 218.44.251.212 243 | 220.110.150.90 244 | 220.247.224.8 245 | 221.213.49.149 246 | 221.8.69.27 247 | 222.122.56.219 248 | 23.23.14.192 249 | 23.89.5.60 250 | 24.51.184.0 251 | 243.185.187.30 252 | 243.185.187.39 253 | 249.129.46.48 254 | 253.157.14.165 255 | 28.121.126.139 256 | 28.13.216.0 257 | 31.169.90.4 258 | 31.170.8.8 259 | 31.210.156.212 260 | 31.22.4.60 261 | 31.222.185.202 262 | 31.25.191.134 263 | 34.254.247.151 264 | 37.1.205.21 265 | 37.1.207.129 266 | 37.140.238.35 267 | 37.187.134.150 268 | 37.187.149.129 269 | 37.187.251.35 270 | 37.252.122.184 271 | 37.58.78.79 272 | 37.59.25.95 273 | 37.61.54.158 274 | 37.99.194.148 275 | 38.117.98.231 276 | 4.17.143.131 277 | 4.193.80.0 278 | 4.21.70.9 279 | 4.30.13.168 280 | 4.30.187.9 281 | 4.30.235.229 282 | 4.31.139.146 283 | 4.34.180.178 284 | 4.35.100.20 285 | 4.35.234.200 286 | 4.36.66.178 287 | 4.53.17.215 288 | 4.59.79.206 289 | 4.78.167.196 290 | 4.79.129.122 291 | 41.79.20.9 292 | 43.253.199.12 293 | 46.137.219.7 294 | 46.165.231.144 295 | 46.20.126.252 296 | 46.20.13.100 297 | 46.229.175.95 298 | 46.243.6.170 299 | 46.30.212.198 300 | 46.38.24.209 301 | 46.82.174.68 302 | 49.2.123.56 303 | 49.212.153.128 304 | 5.10.105.41 305 | 5.10.68.187 306 | 5.10.68.188 307 | 5.10.69.29 308 | 5.10.77.72 309 | 5.100.152.24 310 | 5.100.225.204 311 | 5.100.228.206 312 | 5.100.231.27 313 | 5.100.248.208 314 | 5.144.129.20 315 | 5.35.251.108 316 | 5.9.118.111 317 | 5.9.120.140 318 | 5.9.136.210 319 | 5.9.242.232 320 | 5.9.5.26 321 | 5.9.65.105 322 | 50.116.6.162 323 | 50.18.183.233 324 | 50.57.11.12 325 | 50.63.202.13 326 | 50.87.148.140 327 | 50.87.169.77 328 | 50.93.207.101 329 | 50.97.134.91 330 | 54.174.40.182 331 | 54.187.136.30 332 | 54.187.39.38 333 | 54.191.193.138 334 | 54.200.3.32 335 | 54.206.98.127 336 | 54.209.238.28 337 | 54.209.87.186 338 | 54.218.38.198 339 | 54.229.147.183 340 | 54.235.199.154 341 | 54.244.22.77 342 | 54.246.169.32 343 | 54.246.202.250 344 | 54.68.166.130 345 | 54.76.135.1 346 | 54.83.51.191 347 | 54.86.21.64 348 | 54.86.223.202 349 | 54.88.252.91 350 | 59.124.74.28 351 | 59.24.3.173 352 | 61.54.28.6 353 | 62.138.115.35 354 | 62.75.221.31 355 | 62.92.17.213 356 | 64.14.72.41 357 | 64.150.184.98 358 | 64.22.110.34 359 | 64.33.88.161 360 | 64.33.99.47 361 | 64.34.161.142 362 | 64.50.179.133 363 | 64.66.163.251 364 | 64.79.69.250 365 | 64.79.84.141 366 | 64.91.254.97 367 | 65.104.202.252 368 | 65.160.219.113 369 | 65.183.39.139 370 | 66.146.2.241 371 | 66.187.204.50 372 | 66.206.11.194 373 | 66.39.61.161 374 | 66.45.252.237 375 | 66.55.151.148 376 | 66.85.134.186 377 | 66.96.147.160 378 | 67.137.227.11 379 | 67.225.220.248 380 | 68.71.58.18 381 | 69.16.196.113 382 | 69.167.172.162 383 | 69.171.13.49 384 | 69.174.244.221 385 | 69.175.75.202 386 | 69.195.124.90 387 | 69.30.23.10 388 | 69.50.192.218 389 | 69.61.60.122 390 | 70.42.243.33 391 | 72.14.205.104 392 | 72.14.205.99 393 | 72.167.32.10 394 | 72.20.110.50 395 | 72.29.94.240 396 | 72.32.4.243 397 | 72.47.228.79 398 | 72.5.1.109 399 | 72.52.244.56 400 | 74.117.117.122 401 | 74.117.57.138 402 | 74.124.195.73 403 | 74.125.127.102 404 | 74.125.155.102 405 | 74.125.204.121 406 | 74.125.39.102 407 | 74.125.39.113 408 | 74.207.236.174 409 | 74.208.125.184 410 | 74.220.215.67 411 | 74.82.166.166 412 | 75.98.175.166 413 | 76.164.217.116 414 | 77.4.7.92 415 | 78.108.178.26 416 | 78.140.172.33 417 | 78.16.49.15 418 | 78.24.135.99 419 | 79.127.127.68 420 | 79.136.125.49 421 | 79.98.34.60 422 | 8.105.84.0 423 | 8.34.161.150 424 | 8.7.198.45 425 | 80.190.96.26 426 | 80.241.209.19 427 | 80.241.92.180 428 | 80.245.171.70 429 | 80.70.184.118 430 | 80.72.41.146 431 | 80.82.117.209 432 | 80.82.201.154 433 | 80.92.117.132 434 | 82.145.47.117 435 | 83.125.118.122 436 | 83.222.124.187 437 | 83.222.5.171 438 | 84.124.59.165 439 | 85.111.18.138 440 | 85.190.0.110 441 | 85.25.171.103 442 | 85.92.134.229 443 | 87.106.57.209 444 | 87.230.46.50 445 | 88.198.69.101 446 | 88.214.195.67 447 | 89.108.118.129 448 | 89.111.181.74 449 | 89.186.95.11 450 | 89.30.125.204 451 | 89.31.55.106 452 | 90.156.201.42 453 | 91.121.245.154 454 | 91.186.28.41 455 | 91.198.129.47 456 | 91.217.73.22 457 | 91.221.37.35 458 | 91.223.175.25 459 | 91.238.30.54 460 | 91.239.201.16 461 | 92.53.106.175 462 | 92.53.96.9 463 | 92.63.110.174 464 | 93.115.240.148 465 | 93.158.121.72 466 | 93.187.205.2 467 | 93.46.8.89 468 | 93.93.187.49 469 | 94.136.188.30 470 | 94.141.31.140 471 | 94.23.147.142 472 | 94.23.156.11 473 | 94.23.193.224 474 | 94.23.199.144 475 | 95.163.95.47 476 | 95.211.150.70 477 | 95.211.229.156 478 | 95.211.58.97 479 | 95.85.22.163 480 | 96.126.97.15 481 | 96.127.172.221 482 | 96.30.51.148 483 | 97.74.80.22 484 | 98.129.229.202 485 | 98.158.152.159 486 | 98.158.178.141 487 | -------------------------------------------------------------------------------- /chinadns/dnsrelay.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2014 clowwindy 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | 24 | import sys 25 | import os 26 | import time 27 | import socket 28 | import errno 29 | import struct 30 | import logging 31 | 32 | info = sys.version_info 33 | if not (info[0] == 2 and info[1] >= 7): 34 | print 'Python 2.7 required' 35 | sys.exit(1) 36 | 37 | import argparse 38 | from shadowsocks import eventloop, asyncdns, lru_cache 39 | 40 | 41 | BUF_SIZE = 16384 42 | 43 | CACHE_TIMEOUT = 10 44 | 45 | EMPTY_RESULT_DELAY = 4 46 | 47 | GFW_LIST = set(["74.125.127.102", "74.125.155.102", "74.125.39.102", 48 | "74.125.39.113", "209.85.229.138", "128.121.126.139", 49 | "159.106.121.75", "169.132.13.103", "192.67.198.6", 50 | "202.106.1.2", "202.181.7.85", "203.161.230.171", 51 | "203.98.7.65", "207.12.88.98", "208.56.31.43", 52 | "209.145.54.50", "209.220.30.174", "209.36.73.33", 53 | "211.94.66.147", "213.169.251.35", "216.221.188.182", 54 | "216.234.179.13", "243.185.187.39", "37.61.54.158", 55 | "4.36.66.178", "46.82.174.68", "59.24.3.173", "64.33.88.161", 56 | "64.33.99.47", "64.66.163.251", "65.104.202.252", 57 | "65.160.219.113", "66.45.252.237", "72.14.205.104", 58 | "72.14.205.99", "78.16.49.15", "8.7.198.45", "93.46.8.89"]) 59 | 60 | 61 | class DNSRelay(object): 62 | def __init__(self, config): 63 | self._loop = None 64 | self._config = config 65 | self._last_time = time.time() 66 | 67 | self._local_addr = (config['local_address'], config['local_port']) 68 | self._remote_addrs = [] 69 | for addr in config['dns'].split(','): 70 | parts = addr.strip().rsplit(':', 1) 71 | host = parts[0] 72 | port = int(parts[1]) if len(parts) == 2 else 53 73 | self._remote_addrs.append((host, port)) 74 | self._remote_addr = self._remote_addrs[-1] 75 | self._hosts = {} 76 | self._parse_hosts() 77 | 78 | def add_to_loop(self, loop): 79 | if self._loop: 80 | raise Exception('already add to loop') 81 | self._loop = loop 82 | loop.add_handler(self.handle_events) 83 | 84 | def _parse_hosts(self): 85 | etc_path = '/etc/hosts' 86 | if os.environ.__contains__('WINDIR'): 87 | etc_path = os.environ['WINDIR'] + '/system32/drivers/etc/hosts' 88 | try: 89 | with open(etc_path, 'rb') as f: 90 | for line in f.readlines(): 91 | line = line.strip() 92 | parts = line.split() 93 | if len(parts) >= 2: 94 | ip = parts[0] 95 | if asyncdns.is_ip(ip): 96 | for i in xrange(1, len(parts)): 97 | hostname = parts[i] 98 | if hostname: 99 | self._hosts[hostname] = ip 100 | except IOError: 101 | pass 102 | 103 | @staticmethod 104 | def build_response(request, ip): 105 | addrs = socket.getaddrinfo(ip, 0, 0, 0, 0) 106 | if not addrs: 107 | return None 108 | af, socktype, proto, canonname, sa = addrs[0] 109 | header = struct.unpack('!HBBHHHH', request[:12]) 110 | header = struct.pack('!HBBHHHH', header[0], 0x80 | header[1], 0x80, 1, 111 | 1, 0, 0) 112 | if af == socket.AF_INET: 113 | qtype = asyncdns.QTYPE_A 114 | else: 115 | qtype = asyncdns.QTYPE_AAAA 116 | addr = socket.inet_pton(af, ip) 117 | question = request[12:] 118 | 119 | # for hostname compression 120 | answer = struct.pack('!H', ((128 + 64) << 8 | 12)) + \ 121 | struct.pack('!HHiH', qtype, asyncdns.QCLASS_IN, 300, 122 | len(addr)) + addr 123 | return header + question + answer 124 | 125 | def handle_events(self, events): 126 | pass 127 | 128 | 129 | class UDPDNSRelay(DNSRelay): 130 | def __init__(self, config): 131 | DNSRelay.__init__(self, config) 132 | 133 | self._id_to_addr = lru_cache.LRUCache(CACHE_TIMEOUT) 134 | self._local_sock = None 135 | self._remote_sock = None 136 | self._create_sockets() 137 | self._pending_responses = [] 138 | 139 | def _create_sockets(self): 140 | sockets = [] 141 | for addr in (self._local_addr, self._remote_addr): 142 | addrs = socket.getaddrinfo(addr[0], addr[1], 0, 143 | socket.SOCK_DGRAM, socket.SOL_UDP) 144 | if len(addrs) == 0: 145 | raise Exception("can't get addrinfo for %s:%d" % addr) 146 | af, socktype, proto, canonname, sa = addrs[0] 147 | sock = socket.socket(af, socktype, proto) 148 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 149 | sock.setblocking(False) 150 | sockets.append(sock) 151 | self._local_sock, self._remote_sock = sockets 152 | self._local_sock.bind(self._local_addr) 153 | 154 | def _rebuild_sockets(self): 155 | self._id_to_addr.clear() 156 | self._loop.remove(self._local_sock) 157 | self._loop.remove(self._remote_sock) 158 | self._local_sock.close() 159 | self._remote_sock.close() 160 | self._create_sockets() 161 | self._loop.add(self._local_sock, eventloop.POLL_IN) 162 | self._loop.add(self._remote_sock, eventloop.POLL_IN) 163 | 164 | def add_to_loop(self, loop): 165 | DNSRelay.add_to_loop(self, loop) 166 | 167 | loop.add(self._local_sock, eventloop.POLL_IN) 168 | loop.add(self._remote_sock, eventloop.POLL_IN) 169 | 170 | def _handle_local(self, sock): 171 | try: 172 | data, addr = sock.recvfrom(BUF_SIZE) 173 | except (OSError, IOError) as e: 174 | logging.error(e) 175 | if eventloop.errno_from_exception(e) == errno.ECONNRESET: 176 | # just for Windows lol 177 | self._rebuild_sockets() 178 | return 179 | header = asyncdns.parse_header(data) 180 | if header: 181 | try: 182 | req_id = header[0] 183 | req = asyncdns.parse_response(data) 184 | logging.info('request %s', req.hostname) 185 | if req.hostname in self._hosts: 186 | response = self.build_response(data, 187 | self._hosts[req.hostname]) 188 | if response: 189 | logging.info('%s hit /etc/hosts', req.hostname) 190 | self._local_sock.sendto(response, addr) 191 | return 192 | self._id_to_addr[req_id] = addr 193 | for remote_addr in self._remote_addrs: 194 | self._remote_sock.sendto(data, remote_addr) 195 | except Exception as e: 196 | import traceback 197 | 198 | traceback.print_exc() 199 | logging.error(e) 200 | 201 | def _handle_remote(self, sock): 202 | try: 203 | data, addr = sock.recvfrom(BUF_SIZE) 204 | except (OSError, IOError) as e: 205 | logging.error(e) 206 | if eventloop.errno_from_exception(e) == errno.ECONNRESET: 207 | # just for Windows lol 208 | self._rebuild_sockets() 209 | return 210 | if data: 211 | try: 212 | header = asyncdns.parse_header(data) 213 | if header: 214 | req_id = header[0] 215 | res = asyncdns.parse_response(data) 216 | logging.info('response from %s:%d %s', addr[0], addr[1], 217 | res) 218 | addr = self._id_to_addr.get(req_id, None) 219 | if addr: 220 | for answer in res.answers: 221 | if answer and answer[0] in GFW_LIST: 222 | return 223 | if not res.answers: 224 | # delay empty results 225 | def _send_later(): 226 | self._local_sock.sendto(data, addr) 227 | self._pending_responses.append((time.time(), 228 | _send_later)) 229 | return 230 | self._local_sock.sendto(data, addr) 231 | del self._id_to_addr[req_id] 232 | except Exception as e: 233 | import traceback 234 | traceback.print_exc() 235 | logging.error(e) 236 | if eventloop.errno_from_exception(e) == errno.EACCES: 237 | # when we have changed our ip 238 | self._rebuild_sockets() 239 | 240 | def handle_events(self, events): 241 | for sock, fd, event in events: 242 | if sock == self._local_sock: 243 | self._handle_local(sock) 244 | elif sock == self._remote_sock: 245 | self._handle_remote(sock) 246 | now = time.time() 247 | if now - self._last_time > CACHE_TIMEOUT / 2: 248 | self._id_to_addr.sweep() 249 | i = 0 250 | for pending_response in self._pending_responses: 251 | ts, cb = pending_response 252 | if now - ts > EMPTY_RESULT_DELAY: 253 | cb() 254 | i += 1 255 | else: 256 | break 257 | self._pending_responses = self._pending_responses[i:] 258 | 259 | 260 | class TCPDNSRelay(DNSRelay): 261 | def __init__(self, config): 262 | DNSRelay.__init__(self, config) 263 | 264 | self._local_to_remote = {} 265 | self._remote_to_local = {} 266 | 267 | addrs = socket.getaddrinfo(self._local_addr[0], self._local_addr[1], 0, 268 | socket.SOCK_STREAM, socket.SOL_TCP) 269 | if len(addrs) == 0: 270 | raise Exception("can't get addrinfo for %s:%d" % self._local_addr) 271 | af, socktype, proto, canonname, sa = addrs[0] 272 | self._listen_sock = socket.socket(af, socktype, proto) 273 | self._listen_sock.setblocking(False) 274 | self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 275 | self._listen_sock.bind(self._local_addr) 276 | self._listen_sock.listen(1024) 277 | 278 | def _handle_conn(self, sock): 279 | try: 280 | local, addr = sock.accept() 281 | addrs = socket.getaddrinfo(self._remote_addr[0], 282 | self._remote_addr[1], 0, 283 | socket.SOCK_STREAM, socket.SOL_TCP) 284 | if len(addrs) == 0: 285 | raise Exception("can't get addrinfo for %s:%d" % 286 | self._remote_addr) 287 | af, socktype, proto, canonname, sa = addrs[0] 288 | remote = socket.socket(af, socktype, proto) 289 | local.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) 290 | remote.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) 291 | self._local_to_remote[local] = remote 292 | self._remote_to_local[remote] = local 293 | 294 | self._loop.add(local, 0) 295 | self._loop.add(remote, eventloop.POLL_OUT) 296 | try: 297 | remote.connect(self._remote_addr) 298 | except (OSError, IOError) as e: 299 | if eventloop.errno_from_exception(e) in (errno.EINPROGRESS, 300 | errno.EAGAIN): 301 | pass 302 | else: 303 | raise 304 | except (OSError, IOError) as e: 305 | logging.error(e) 306 | 307 | def _destroy(self, local, remote): 308 | if local in self._local_to_remote: 309 | self._loop.remove(local) 310 | self._loop.remove(remote) 311 | del self._local_to_remote[local] 312 | del self._remote_to_local[remote] 313 | local.close() 314 | remote.close() 315 | else: 316 | logging.error('already destroyed') 317 | 318 | def _handle_local(self, local, event): 319 | remote = self._local_to_remote[local] 320 | if event & (eventloop.POLL_ERR | eventloop.POLL_HUP): 321 | self._destroy(local, remote) 322 | elif event & eventloop.POLL_IN: 323 | try: 324 | data = local.recv(BUF_SIZE) 325 | if not data: 326 | self._destroy(local, remote) 327 | else: 328 | remote.send(data) 329 | except (OSError, IOError) as e: 330 | self._destroy(local, self._local_to_remote[local]) 331 | logging.error(e) 332 | 333 | def _handle_remote(self, remote, event): 334 | local = self._remote_to_local[remote] 335 | if event & (eventloop.POLL_ERR | eventloop.POLL_HUP): 336 | self._destroy(local, remote) 337 | elif event & eventloop.POLL_OUT: 338 | self._loop.modify(remote, eventloop.POLL_IN) 339 | self._loop.modify(local, eventloop.POLL_IN) 340 | elif event & eventloop.POLL_IN: 341 | try: 342 | data = remote.recv(BUF_SIZE) 343 | if not data: 344 | self._destroy(local, remote) 345 | else: 346 | try: 347 | res = asyncdns.parse_response(data[2:]) 348 | if res: 349 | logging.info('response %s', res) 350 | except Exception as e: 351 | logging.error(e) 352 | local.send(data) 353 | except (OSError, IOError) as e: 354 | self._destroy(local, remote) 355 | logging.error(e) 356 | 357 | def add_to_loop(self, loop): 358 | DNSRelay.add_to_loop(self, loop) 359 | loop.add(self._listen_sock, eventloop.POLL_IN) 360 | 361 | def handle_events(self, events): 362 | for sock, fd, event in events: 363 | if sock == self._listen_sock: 364 | self._handle_conn(sock) 365 | elif sock in self._local_to_remote: 366 | self._handle_local(sock, event) 367 | elif sock in self._remote_to_local: 368 | self._handle_remote(sock, event) 369 | # TODO implement timeout 370 | 371 | 372 | def main(): 373 | logging.basicConfig(level=logging.INFO, 374 | format='%(asctime)s %(levelname)-8s %(message)s', 375 | datefmt='%Y-%m-%d %H:%M:%S', filemode='a+') 376 | 377 | parser = argparse.ArgumentParser(description='Forward DNS requests.') 378 | parser.add_argument('-b', '--local_address', metavar='BIND_ADDR', type=str, 379 | help='address that listens, default: 127.0.0.1', 380 | default='127.0.0.1') 381 | parser.add_argument('-p', '--local_port', metavar='BIND_PORT', type=int, 382 | help='port that listens, default: 53', default=53) 383 | parser.add_argument('-s', '--dns', metavar='DNS', type=str, 384 | help='DNS server to use, default: ' 385 | '114.114.114.114,208.67.222.222,8.8.8.8', 386 | default='114.114.114.114,208.67.222.222,8.8.8.8') 387 | parser.add_argument('-l', '--ip_list', metavar='IP_LIST_FILE', type=str, 388 | default=None) 389 | 390 | config = vars(parser.parse_args()) 391 | 392 | if config['ip_list']: 393 | logging.info('loading IP list from %s', config['ip_list']) 394 | with open(config['ip_list'], 'rb') as f: 395 | global GFW_LIST 396 | GFW_LIST = set(f.readlines()) 397 | 398 | logging.info("starting dns at %s:%d", 399 | config['local_address'], config['local_port']) 400 | 401 | loop = eventloop.EventLoop() 402 | 403 | try: 404 | udprelay = UDPDNSRelay(config) 405 | udprelay.add_to_loop(loop) 406 | tcprelay = TCPDNSRelay(config) 407 | tcprelay.add_to_loop(loop) 408 | loop.run() 409 | except (OSError, IOError) as e: 410 | logging.error(e) 411 | if eventloop.errno_from_exception(e) == errno.EACCES: 412 | logging.info('please use sudo to run this program') 413 | sys.exit(1) 414 | 415 | 416 | if __name__ == '__main__': 417 | main() 418 | --------------------------------------------------------------------------------