Browse Source

use multiple DNS instead of trying each one

auth
clowwindy 11 years ago
parent
commit
012ab70500
  1. 36
      shadowsocks/asyncdns.py

36
shadowsocks/asyncdns.py

@ -32,7 +32,7 @@ import lru_cache
import eventloop import eventloop
CACHE_SWEEP_INTERVAL = 10 CACHE_SWEEP_INTERVAL = 30
VALID_HOSTNAME = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) VALID_HOSTNAME = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
@ -267,21 +267,18 @@ class DNSResolver(object):
self._hosts = {} self._hosts = {}
self._hostname_status = {} self._hostname_status = {}
self._hostname_to_cb = {} self._hostname_to_cb = {}
self._cb_to_hostname = lru_cache.LRUCache(timeout=15, self._cb_to_hostname = {}
close_callback=self._timedout)
self._cache = lru_cache.LRUCache(timeout=300) self._cache = lru_cache.LRUCache(timeout=300)
self._last_time = time.time() self._last_time = time.time()
self._sock = None self._sock = None
self._servers = None self._servers = None
self._server_index = 0
self._parse_resolv() self._parse_resolv()
self._parse_hosts() self._parse_hosts()
# TODO monitor hosts change and reload hosts # TODO monitor hosts change and reload hosts
# TODO parse /etc/gai.conf and follow its rules # TODO parse /etc/gai.conf and follow its rules
def _parse_resolv(self): def _parse_resolv(self):
servers = [] self._servers = []
self._servers = servers
try: try:
with open('/etc/resolv.conf', 'rb') as f: with open('/etc/resolv.conf', 'rb') as f:
content = f.readlines() content = f.readlines()
@ -293,22 +290,11 @@ class DNSResolver(object):
if len(parts) >= 2: if len(parts) >= 2:
server = parts[1] server = parts[1]
if is_ip(server): if is_ip(server):
servers.append(server) self._servers.append(server)
# TODO support more servers
except IOError: except IOError:
pass pass
if not servers: if not self._servers:
servers.append('8.8.8.8') self._servers = ['8.8.4.4', '8.8.8.8']
self._dns_server = (servers[0], 53)
def _timedout(self, hostname):
error = Exception('timed out when resolving %s with DNS %s' %
(hostname, self._dns_server))
self._server_index += 1
self._server_index %= len(self._servers)
self._dns_server = (self._servers[self._server_index], 53)
self._call_callback(hostname, None, error=error)
def _parse_hosts(self): def _parse_hosts(self):
etc_path = '/etc/hosts' etc_path = '/etc/hosts'
@ -389,7 +375,7 @@ class DNSResolver(object):
self._loop.add(self._sock, eventloop.POLL_IN) self._loop.add(self._sock, eventloop.POLL_IN)
else: else:
data, addr = sock.recvfrom(1024) data, addr = sock.recvfrom(1024)
if addr != self._dns_server: if addr[0] not in self._servers:
logging.warn('received a packet other than our dns') logging.warn('received a packet other than our dns')
break break
self._handle_data(data) self._handle_data(data)
@ -397,7 +383,6 @@ class DNSResolver(object):
now = time.time() now = time.time()
if now - self._last_time > CACHE_SWEEP_INTERVAL: if now - self._last_time > CACHE_SWEEP_INTERVAL:
self._cache.sweep() self._cache.sweep()
self._cb_to_hostname.sweep()
self._last_time = now self._last_time = now
def remove_callback(self, callback): def remove_callback(self, callback):
@ -413,13 +398,14 @@ class DNSResolver(object):
del self._hostname_status[hostname] del self._hostname_status[hostname]
def _send_req(self, hostname, qtype): def _send_req(self, hostname, qtype):
logging.debug('resolving %s with type %d using server %s', hostname,
qtype, self._dns_server)
self._request_id += 1 self._request_id += 1
if self._request_id > 32768: if self._request_id > 32768:
self._request_id = 1 self._request_id = 1
req = build_request(hostname, qtype, self._request_id) req = build_request(hostname, qtype, self._request_id)
self._sock.sendto(req, self._dns_server) for server in self._servers:
logging.debug('resolving %s with type %d using server %s', hostname,
qtype, server)
self._sock.sendto(req, (server, 53))
def resolve(self, hostname, callback): def resolve(self, hostname, callback):
if not hostname: if not hostname:

Loading…
Cancel
Save