Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master #6

Open
wants to merge 36 commits into
base: manyuser
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
62dca9d
udp over tcp
breakwa11 Jun 9, 2015
f167499
drop UDP message if frag != 0
breakwa11 Jun 10, 2015
d065dba
merge manyuser
breakwa11 Jun 16, 2015
c549929
fix udp ipv6
breakwa11 Jun 16, 2015
3d1563e
fix udp ipv6
breakwa11 Jun 20, 2015
e5b4a80
double UDP sockets for IPv4 and IPv6
breakwa11 Jun 20, 2015
0edae70
Add fail2ban filter.
jackyyf Jun 20, 2015
a2edd6a
Merge pull request #361 from jackyyf/master
clowwindy Jun 21, 2015
1b0504a
merge manyuser branch
breakwa11 Jun 26, 2015
7c3e047
merge manyuser branch
breakwa11 Jul 4, 2015
1a62694
add udp source port test
clowwindy Jul 10, 2015
c34c994
fix UDP source port issue
clowwindy Jul 10, 2015
99b4121
fix problem when UDP client requesting both IPv4 and IPv6
clowwindy Jul 10, 2015
13a6bb0
cache DNS results in UDPRelay
clowwindy Jul 10, 2015
f55bd03
update CHANGES
clowwindy Jul 10, 2015
f7d69db
bump
clowwindy Jul 10, 2015
1bb0e51
refine tests
clowwindy Jul 11, 2015
e751534
Merge branch 'master' of shadowsocks/shadowsocks
breakwa11 Jul 12, 2015
d475076
listen ipv6
breakwa11 Jul 14, 2015
a38db82
new UDP over TCP protocol, merge master
breakwa11 Aug 5, 2015
5b6dec5
merge manyuser branch
breakwa11 Aug 27, 2015
a37623b
log TCP header if parse error
breakwa11 Sep 2, 2015
8f40227
merge manyuser branch
breakwa11 Oct 4, 2015
3200b7d
merge manyuser branch
breakwa11 Oct 4, 2015
1bc0e60
merge manyuser branch
breakwa11 Oct 20, 2015
c18b002
bump 2.6.11
breakwa11 Oct 20, 2015
418cadb
Update lru_cache.py
mengskysama Oct 26, 2015
b059b9a
memory leak
mengskysama Oct 26, 2015
9bb52ac
Merge pull request #25 from mengskysama/patch-4
breakwa11 Oct 26, 2015
1e41de7
Merge pull request #24 from mengskysama/patch-2
breakwa11 Oct 26, 2015
3db5a49
发现好多坑
mengskysama Oct 26, 2015
eebd5c5
Merge pull request #26 from mengskysama/patch-6
breakwa11 Oct 26, 2015
7df3152
merge manyuser
breakwa11 Oct 27, 2015
2d69544
bump 2.6.12
breakwa11 Oct 27, 2015
a681a72
a stupid bug
breakwa11 Oct 27, 2015
1ee3442
merge manyuser 2.6.13
breakwa11 Nov 2, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ before_install:
- sudo dd if=/dev/urandom of=/usr/share/nginx/www/file bs=1M count=10
- sudo sh -c "echo '127.0.0.1 localhost' > /etc/hosts"
- sudo service nginx restart
- pip install pep8 pyflakes nose coverage
- pip install pep8 pyflakes nose coverage PySocks
- sudo tests/socksify/install.sh
- sudo tests/libsodium/install.sh
- sudo tests/setup_tc.sh
Expand Down
18 changes: 18 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
2.6.13 2015-11-02
- add protocol setting

2.6.12 2015-10-27
- IPv6 first
- Fix mem leaks
- auth_simple plugin
- remove FORCE_NEW_PROTOCOL
- optimize code

2.6.11 2015-10-20
- Obfs plugin
- Obfs parameters
- UDP over TCP
- TCP over UDP (experimental)
- Fix socket leaks
- Catch abnormal UDP package

2.6.10 2015-06-08
- Optimize LRU cache
- Refine logging
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name="shadowsocks",
version="2.6.11",
version="2.6.12",
license='http://www.apache.org/licenses/LICENSE-2.0',
description="A fast tunnel proxy that help you get through firewalls",
author='clowwindy',
Expand Down
135 changes: 88 additions & 47 deletions shadowsocks/asyncdns.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@
from __future__ import absolute_import, division, print_function, \
with_statement

import time
import os
import socket
import struct
import re
import logging

if __name__ == '__main__':
import sys
import inspect
file_path = os.path.dirname(os.path.realpath(inspect.getfile(inspect.currentframe())))
os.chdir(file_path)
sys.path.insert(0, os.path.join(file_path, '../'))

from shadowsocks import common, lru_cache, eventloop, shell


Expand Down Expand Up @@ -72,6 +78,19 @@
QTYPE_NS = 2
QCLASS_IN = 1

def detect_ipv6_supprot():
if 'has_ipv6' in dir(socket):
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
s.connect(('ipv6.google.com', 0))
print('IPv6 support')
return True
except:
pass
print('IPv6 not support')
return False

IPV6_CONNECTION_SUPPORT = detect_ipv6_supprot()

def build_address(address):
address = address.strip(b'.')
Expand Down Expand Up @@ -256,7 +275,6 @@ def __init__(self):
self._hostname_to_cb = {}
self._cb_to_hostname = {}
self._cache = lru_cache.LRUCache(timeout=300)
self._last_time = time.time()
self._sock = None
self._servers = None
self._parse_resolv()
Expand Down Expand Up @@ -304,16 +322,16 @@ def _parse_hosts(self):
except IOError:
self._hosts['localhost'] = '127.0.0.1'

def add_to_loop(self, loop, ref=False):
def add_to_loop(self, loop):
if self._loop:
raise Exception('already add to loop')
self._loop = loop
# TODO when dns server is IPv6
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
socket.SOL_UDP)
self._sock.setblocking(False)
loop.add(self._sock, eventloop.POLL_IN)
loop.add_handler(self.handle_events, ref=ref)
loop.add(self._sock, eventloop.POLL_IN, self)
loop.add_periodic(self.handle_periodic)

def _call_callback(self, hostname, ip, error=None):
callbacks = self._hostname_to_cb.get(hostname, [])
Expand All @@ -340,44 +358,56 @@ def _handle_data(self, data):
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)
else:
if ip:
self._cache[hostname] = ip
self._call_callback(hostname, ip)
elif self._hostname_status.get(hostname, None) == STATUS_IPV6:
for question in response.questions:
if question[1] == QTYPE_AAAA:
self._call_callback(hostname, None)
break

def handle_events(self, events):
for sock, fd, event in events:
if sock != self._sock:
continue
if event & eventloop.POLL_ERR:
logging.error('dns socket err')
self._loop.remove(self._sock)
self._sock.close()
# TODO when dns server is IPv6
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
socket.SOL_UDP)
self._sock.setblocking(False)
self._loop.add(self._sock, eventloop.POLL_IN)
if IPV6_CONNECTION_SUPPORT:
if not ip and self._hostname_status.get(hostname, STATUS_IPV4) \
== STATUS_IPV6:
self._hostname_status[hostname] = STATUS_IPV4
self._send_req(hostname, QTYPE_A)
else:
if ip:
self._cache[hostname] = ip
self._call_callback(hostname, ip)
elif self._hostname_status.get(hostname, None) == STATUS_IPV4:
for question in response.questions:
if question[1] == QTYPE_A:
self._call_callback(hostname, None)
break
else:
data, addr = sock.recvfrom(1024)
if addr[0] not in self._servers:
logging.warn('received a packet other than our dns')
break
self._handle_data(data)
break
now = time.time()
if now - self._last_time > CACHE_SWEEP_INTERVAL:
self._cache.sweep()
self._last_time = now
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)
else:
if ip:
self._cache[hostname] = ip
self._call_callback(hostname, ip)
elif self._hostname_status.get(hostname, None) == STATUS_IPV6:
for question in response.questions:
if question[1] == QTYPE_AAAA:
self._call_callback(hostname, None)
break

def handle_event(self, sock, fd, event):
if sock != self._sock:
return
if event & eventloop.POLL_ERR:
logging.error('dns socket err')
self._loop.remove(self._sock)
self._sock.close()
# TODO when dns server is IPv6
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
socket.SOL_UDP)
self._sock.setblocking(False)
self._loop.add(self._sock, eventloop.POLL_IN, self)
else:
data, addr = sock.recvfrom(1024)
if addr[0] not in self._servers:
logging.warn('received a packet other than our dns')
return
self._handle_data(data)

def handle_periodic(self):
self._cache.sweep()

def remove_callback(self, callback):
hostname = self._cb_to_hostname.get(callback)
Expand Down Expand Up @@ -419,25 +449,35 @@ def resolve(self, hostname, callback):
return
arr = self._hostname_to_cb.get(hostname, None)
if not arr:
self._hostname_status[hostname] = STATUS_IPV4
self._send_req(hostname, QTYPE_A)
if IPV6_CONNECTION_SUPPORT:
self._hostname_status[hostname] = STATUS_IPV6
self._send_req(hostname, QTYPE_AAAA)
else:
self._hostname_status[hostname] = STATUS_IPV4
self._send_req(hostname, QTYPE_A)
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)
if IPV6_CONNECTION_SUPPORT:
self._send_req(hostname, QTYPE_AAAA)
else:
self._send_req(hostname, QTYPE_A)

def close(self):
if self._sock:
if self._loop:
self._loop.remove_periodic(self.handle_periodic)
self._loop.remove(self._sock)
self._sock.close()
self._sock = None


def test():
dns_resolver = DNSResolver()
loop = eventloop.EventLoop()
dns_resolver.add_to_loop(loop, ref=True)
dns_resolver.add_to_loop(loop)

global counter
counter = 0
Expand All @@ -451,8 +491,8 @@ def callback(result, error):
print(result, error)
counter += 1
if counter == 9:
loop.remove_handler(dns_resolver.handle_events)
dns_resolver.close()
loop.stop()
a_callback = callback
return a_callback

Expand Down Expand Up @@ -481,3 +521,4 @@ def callback(result, error):

if __name__ == '__main__':
test()

56 changes: 53 additions & 3 deletions shadowsocks/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import socket
import struct
import logging

import binascii

def compat_ord(s):
if type(s) == int:
Expand Down Expand Up @@ -54,6 +54,16 @@ def to_str(s):
return s.decode('utf-8')
return s

def int32(x):
if x > 0xFFFFFFFF or x < 0:
x &= 0xFFFFFFFF
if x > 0x7FFFFFFF:
x = int(0x100000000 - x)
if x < 0x80000000:
return -x
else:
return -2147483648
return x

def inet_ntop(family, ipstr):
if family == socket.AF_INET:
Expand Down Expand Up @@ -138,12 +148,52 @@ def pack_addr(address):
address = address[:255] # TODO
return b'\x03' + chr(len(address)) + address

def pre_parse_header(data):
datatype = ord(data[0])
if datatype == 0x80:
if len(data) <= 2:
return None
rand_data_size = ord(data[1])
if rand_data_size + 2 >= len(data):
logging.warn('header too short, maybe wrong password or '
'encryption method')
return None
data = data[rand_data_size + 2:]
elif datatype == 0x81:
data = data[1:]
elif datatype == 0x82:
if len(data) <= 3:
return None
rand_data_size = struct.unpack('>H', data[1:3])[0]
if rand_data_size + 3 >= len(data):
logging.warn('header too short, maybe wrong password or '
'encryption method')
return None
data = data[rand_data_size + 3:]
elif datatype == 0x88 or (~datatype & 0xff) == 0x88:
if len(data) <= 7 + 7:
return None
data_size = struct.unpack('>H', data[1:3])[0]
ogn_data = data
data = data[:data_size]
crc = binascii.crc32(data) & 0xffffffff
if crc != 0xffffffff:
logging.warn('uncorrect CRC32, maybe wrong password or '
'encryption method')
return None
start_pos = 3 + ord(data[3])
data = data[start_pos:-4]
if data_size < len(ogn_data):
data += ogn_data[data_size:]
return data

def parse_header(data):
addrtype = ord(data[0])
dest_addr = None
dest_port = None
header_length = 0
connecttype = (addrtype & 0x10) and 1 or 0
addrtype &= ~0x10
if addrtype == ADDRTYPE_IPV4:
if len(data) >= 7:
dest_addr = socket.inet_ntoa(data[1:5])
Expand All @@ -157,7 +207,7 @@ def parse_header(data):
if len(data) >= 2 + addrlen:
dest_addr = data[2:2 + addrlen]
dest_port = struct.unpack('>H', data[2 + addrlen:4 +
addrlen])[0]
addrlen])[0]
header_length = 4 + addrlen
else:
logging.warn('header is too short')
Expand All @@ -175,7 +225,7 @@ def parse_header(data):
'encryption method' % addrtype)
if dest_addr is None:
return None
return addrtype, to_bytes(dest_addr), dest_port, header_length
return connecttype, to_bytes(dest_addr), dest_port, header_length


class IPNetwork(object):
Expand Down
Loading