Browse Source

always UDP on

random length TCP/UDP packet
dev
breakwa11 10 years ago
parent
commit
d4ca0d281c
  1. 46
      server_pool.py
  2. 14
      shadowsocks/common.py
  3. 18
      shadowsocks/tcprelay.py
  4. 8
      shadowsocks/udprelay.py

46
server_pool.py

@ -46,7 +46,6 @@ class ServerPool(object):
shell.print_shadowsocks() shell.print_shadowsocks()
self.dns_resolver = asyncdns.DNSResolver() self.dns_resolver = asyncdns.DNSResolver()
self.mgr = asyncmgr.ServerMgr() self.mgr = asyncmgr.ServerMgr()
self.udp_on = True ### UDP switch =====================================
self.tcp_servers_pool = {} self.tcp_servers_pool = {}
self.tcp_ipv6_servers_pool = {} self.tcp_ipv6_servers_pool = {}
@ -110,19 +109,21 @@ class ServerPool(object):
a_config['password'] = password a_config['password'] = password
try: try:
logging.info("starting server at [%s]:%d" % (a_config['server'], port)) logging.info("starting server at [%s]:%d" % (a_config['server'], port))
tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False) tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False)
tcp_server.add_to_loop(self.loop) tcp_server.add_to_loop(self.loop)
self.tcp_ipv6_servers_pool.update({port: tcp_server}) self.tcp_ipv6_servers_pool.update({port: tcp_server})
if self.udp_on:
udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False) udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False)
udp_server.add_to_loop(self.loop) udp_server.add_to_loop(self.loop)
self.udp_ipv6_servers_pool.update({port: udp_server}) self.udp_ipv6_servers_pool.update({port: udp_server})
if a_config['server_ipv6'] == "::": if a_config['server_ipv6'] == "::":
ipv6_ok = True ipv6_ok = True
except Exception, e: except Exception, e:
logging.warn("IPV6 %s " % (e,)) logging.warn("IPV6 %s " % (e,))
if not ipv6_ok and 'server' in self.config: if 'server' in self.config:
if port in self.tcp_servers_pool: if port in self.tcp_servers_pool:
logging.info("server already at %s:%d" % (self.config['server'], port)) logging.info("server already at %s:%d" % (self.config['server'], port))
return 'this port server is already running' return 'this port server is already running'
@ -132,13 +133,16 @@ class ServerPool(object):
a_config['password'] = password a_config['password'] = password
try: try:
logging.info("starting server at %s:%d" % (a_config['server'], port)) logging.info("starting server at %s:%d" % (a_config['server'], port))
tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False)
tcp_server.add_to_loop(self.loop) if not ipv6_ok:
self.tcp_servers_pool.update({port: tcp_server}) tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False)
if self.udp_on: tcp_server.add_to_loop(self.loop)
self.tcp_servers_pool.update({port: tcp_server})
udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False) udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False)
udp_server.add_to_loop(self.loop) udp_server.add_to_loop(self.loop)
self.udp_servers_pool.update({port: udp_server}) self.udp_servers_pool.update({port: udp_server})
except Exception, e: except Exception, e:
logging.warn("IPV4 %s " % (e,)) logging.warn("IPV4 %s " % (e,))
@ -167,12 +171,11 @@ class ServerPool(object):
del self.tcp_servers_pool[port] del self.tcp_servers_pool[port]
except Exception, e: except Exception, e:
logging.warn(e) logging.warn(e)
if self.udp_on: try:
try: self.udp_servers_pool[port].close(True)
self.udp_servers_pool[port].close(True) del self.udp_servers_pool[port]
del self.udp_servers_pool[port] except Exception, e:
except Exception, e: logging.warn(e)
logging.warn(e)
if 'server_ipv6' in self.config: if 'server_ipv6' in self.config:
if port not in self.tcp_ipv6_servers_pool: if port not in self.tcp_ipv6_servers_pool:
@ -184,12 +187,11 @@ class ServerPool(object):
del self.tcp_ipv6_servers_pool[port] del self.tcp_ipv6_servers_pool[port]
except Exception, e: except Exception, e:
logging.warn(e) logging.warn(e)
if self.udp_on: try:
try: self.udp_ipv6_servers_pool[port].close(True)
self.udp_ipv6_servers_pool[port].close(True) del self.udp_ipv6_servers_pool[port]
del self.udp_ipv6_servers_pool[port] except Exception, e:
except Exception, e: logging.warn(e)
logging.warn(e)
return True return True

14
shadowsocks/common.py

@ -138,6 +138,20 @@ def pack_addr(address):
address = address[:255] # TODO address = address[:255] # TODO
return b'\x03' + chr(len(address)) + address 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:]
return data
def parse_header(data): def parse_header(data):
addrtype = ord(data[0]) addrtype = ord(data[0])

18
shadowsocks/tcprelay.py

@ -27,7 +27,7 @@ import traceback
import random import random
from shadowsocks import encrypt, eventloop, shell, common from shadowsocks import encrypt, eventloop, shell, common
from shadowsocks.common import parse_header from shadowsocks.common import pre_parse_header, parse_header
# we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time # we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time
TIMEOUTS_CLEAN_SIZE = 512 TIMEOUTS_CLEAN_SIZE = 512
@ -320,12 +320,15 @@ class TCPRelayHandler(object):
logging.error('unknown command %d', cmd) logging.error('unknown command %d', cmd)
self.destroy() self.destroy()
return return
data = pre_parse_header(data)
if data is None:
raise Exception('can not parse header')
header_result = parse_header(data) header_result = parse_header(data)
if header_result is None: if header_result is None:
raise Exception('can not parse header') raise Exception('can not parse header')
connecttype, remote_addr, remote_port, header_length = header_result connecttype, remote_addr, remote_port, header_length = header_result
logging.info('%s connecting %s:%d from %s:%d' % logging.info('%s connecting %s:%d from %s:%d' %
((connecttype == 0) and 'tcp' or 'udp', ((connecttype == 0) and 'TCP' or 'UDP',
common.to_str(remote_addr), remote_port, common.to_str(remote_addr), remote_port,
self._client_address[0], self._client_address[1])) self._client_address[0], self._client_address[1]))
self._remote_address = (common.to_str(remote_addr), remote_port) self._remote_address = (common.to_str(remote_addr), remote_port)
@ -356,15 +359,6 @@ class TCPRelayHandler(object):
# TODO use logging when debug completed # TODO use logging when debug completed
self.destroy() self.destroy()
def _has_ipv6_addr(self, addr_list):
for item in addr_list:
if type(item) is list:
if self._has_ipv6_addr(item):
return True
elif ':' in item:
return True
return False
def _create_remote_socket(self, ip, port): def _create_remote_socket(self, ip, port):
if self._remote_udp: if self._remote_udp:
addrs_v6 = socket.getaddrinfo("::", 0, 0, socket.SOCK_DGRAM, socket.SOL_UDP) addrs_v6 = socket.getaddrinfo("::", 0, 0, socket.SOCK_DGRAM, socket.SOL_UDP)
@ -505,7 +499,7 @@ class TCPRelayHandler(object):
except Exception as e: except Exception as e:
ip = socket.inet_pton(socket.AF_INET6, addr[0]) ip = socket.inet_pton(socket.AF_INET6, addr[0])
data = '\x00\x00\x00\x04' + ip + port + data data = '\x00\x00\x00\x04' + ip + port + data
logging.info('udp recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) logging.info('UDP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1]))
else: else:
data = self._remote_sock.recv(BUF_SIZE) data = self._remote_sock.recv(BUF_SIZE)
except (OSError, IOError) as e: except (OSError, IOError) as e:

8
shadowsocks/udprelay.py

@ -70,7 +70,7 @@ import errno
import random import random
from shadowsocks import encrypt, eventloop, lru_cache, common, shell from shadowsocks import encrypt, eventloop, lru_cache, common, shell
from shadowsocks.common import parse_header, pack_addr from shadowsocks.common import pre_parse_header, parse_header, pack_addr
BUF_SIZE = 65536 BUF_SIZE = 65536
@ -159,6 +159,10 @@ class UDPRelay(object):
if not data: if not data:
logging.debug('UDP handle_server: data is empty after decrypt') logging.debug('UDP handle_server: data is empty after decrypt')
return return
data = pre_parse_header(data)
if data is None:
return
header_result = parse_header(data) header_result = parse_header(data)
if header_result is None: if header_result is None:
return return
@ -173,7 +177,7 @@ class UDPRelay(object):
client = self._cache.get(key, None) client = self._cache.get(key, None)
if not client: if not client:
# TODO async getaddrinfo # TODO async getaddrinfo
logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port)) #logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port))
addrs = socket.getaddrinfo(server_addr, server_port, 0, addrs = socket.getaddrinfo(server_addr, server_port, 0,
socket.SOCK_DGRAM, socket.SOL_UDP) socket.SOCK_DGRAM, socket.SOL_UDP)
if addrs: if addrs:

Loading…
Cancel
Save