From b276d52735ce848202b8d1ea82e1f088216c0655 Mon Sep 17 00:00:00 2001 From: htc Date: Sat, 20 Feb 2016 10:37:25 +0800 Subject: [PATCH] Add support for option 'prefer-ipv6' --- debian/config.json | 3 ++- shadowsocks/asyncdns.py | 29 +++++++++++++++++------------ shadowsocks/server.py | 5 +++-- shadowsocks/shell.py | 7 ++++++- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/debian/config.json b/debian/config.json index 35cb14a..7846cb2 100644 --- a/debian/config.json +++ b/debian/config.json @@ -7,5 +7,6 @@ "timeout":300, "method":"aes-256-cfb", "fast_open": false, - "workers": 1 + "workers": 1, + "prefer_ipv6": false } \ No newline at end of file diff --git a/shadowsocks/asyncdns.py b/shadowsocks/asyncdns.py index 25a0e6b..44528d7 100644 --- a/shadowsocks/asyncdns.py +++ b/shadowsocks/asyncdns.py @@ -242,13 +242,13 @@ class DNSResponse(object): return '%s: %s' % (self.hostname, str(self.answers)) -STATUS_IPV4 = 0 -STATUS_IPV6 = 1 +STATUS_FIRST = 0 +STATUS_SECOND = 1 class DNSResolver(object): - def __init__(self, server_list=None): + def __init__(self, server_list=None, prefer_ipv6=False): self._loop = None self._hosts = {} self._hostname_status = {} @@ -261,6 +261,10 @@ class DNSResolver(object): self._parse_resolv() else: self._servers = server_list + if prefer_ipv6: + self._QTYPES = [QTYPE_AAAA, QTYPE_A] + else: + self._QTYPES = [QTYPE_A, QTYPE_AAAA] self._parse_hosts() # TODO monitor hosts change and reload hosts # TODO parse /etc/gai.conf and follow its rules @@ -341,17 +345,18 @@ class DNSResolver(object): answer[2] == QCLASS_IN: ip = answer[0] break - if not ip and self._hostname_status.get(hostname, STATUS_IPV6) \ - == STATUS_IPV4: - self._hostname_status[hostname] = STATUS_IPV6 - self._send_req(hostname, QTYPE_AAAA) + if not ip and self._hostname_status.get(hostname, STATUS_SECOND) \ + == STATUS_FIRST: + self._hostname_status[hostname] = STATUS_SECOND + self._send_req(hostname, self._QTYPES[1]) else: if ip: self._cache[hostname] = ip self._call_callback(hostname, ip) - elif self._hostname_status.get(hostname, None) == STATUS_IPV6: + elif self._hostname_status.get(hostname, None) \ + == STATUS_SECOND: for question in response.questions: - if question[1] == QTYPE_AAAA: + if question[1] == self._QTYPES[1]: self._call_callback(hostname, None) break @@ -417,14 +422,14 @@ class DNSResolver(object): return arr = self._hostname_to_cb.get(hostname, None) if not arr: - self._hostname_status[hostname] = STATUS_IPV4 - self._send_req(hostname, QTYPE_A) + self._hostname_status[hostname] = STATUS_FIRST + self._send_req(hostname, self._QTYPES[0]) self._hostname_to_cb[hostname] = [callback] self._cb_to_hostname[callback] = hostname else: arr.append(callback) # TODO send again only if waited too long - self._send_req(hostname, QTYPE_A) + self._send_req(hostname, self._QTYPES[0]) def close(self): if self._sock: diff --git a/shadowsocks/server.py b/shadowsocks/server.py index 1be4c0f..4dc5621 100755 --- a/shadowsocks/server.py +++ b/shadowsocks/server.py @@ -58,9 +58,10 @@ def main(): udp_servers = [] if 'dns_server' in config: # allow override settings in resolv.conf - dns_resolver = asyncdns.DNSResolver(config['dns_server']) + dns_resolver = asyncdns.DNSResolver(config['dns_server'], + config['prefer_ipv6']) else: - dns_resolver = asyncdns.DNSResolver() + dns_resolver = asyncdns.DNSResolver(prefer_ipv6=config['prefer_ipv6']) port_password = config['port_password'] del config['port_password'] diff --git a/shadowsocks/shell.py b/shadowsocks/shell.py index 380bf25..42efbc0 100644 --- a/shadowsocks/shell.py +++ b/shadowsocks/shell.py @@ -137,7 +137,8 @@ def get_config(is_local): else: shortopts = 'hd:s:p:k:m:c:t:vqa' longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=', - 'forbidden-ip=', 'user=', 'manager-address=', 'version'] + 'forbidden-ip=', 'user=', 'manager-address=', 'version', + 'prefer-ipv6'] try: config_path = find_config() optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts) @@ -207,6 +208,8 @@ def get_config(is_local): elif key == '-q': v_count -= 1 config['verbose'] = v_count + elif key == '--prefer-ipv6': + config['prefer_ipv6'] = True except getopt.GetoptError as e: print(e, file=sys.stderr) print_help(is_local) @@ -229,6 +232,7 @@ def get_config(is_local): config['local_address'] = to_str(config.get('local_address', '127.0.0.1')) config['local_port'] = config.get('local_port', 1080) config['one_time_auth'] = config.get('one_time_auth', False) + config['prefer_ipv6'] = config.get('prefer_ipv6', False) if is_local: if config.get('server', None) is None: logging.error('server addr not specified') @@ -324,6 +328,7 @@ Proxy options: --workers WORKERS number of workers, available on Unix/Linux --forbidden-ip IPLIST comma seperated IP list forbidden to connect --manager-address ADDR optional server manager UDP address, see wiki + --prefer-ipv6 resolve ipv6 address first General options: -h, --help show this help message and exit