Browse Source

auto adjust TCP_MAXSEG

dev
破娃酱 8 years ago
parent
commit
d82c931f8e
  1. 6
      shadowsocks/obfs.py
  2. 20
      shadowsocks/obfsplugin/auth.py
  3. 5
      shadowsocks/obfsplugin/obfs_tls.py
  4. 3
      shadowsocks/obfsplugin/plain.py
  5. 63
      shadowsocks/tcprelay.py
  6. 5
      shadowsocks/udprelay.py

6
shadowsocks/obfs.py

@ -53,6 +53,9 @@ class obfs(object):
def set_server_info(self, server_info):
return self.obfs.set_server_info(server_info)
def get_server_info(self):
return self.obfs.get_server_info()
def get_method_info(self, method):
method = method.lower()
m = method_supported.get(method)
@ -62,6 +65,9 @@ class obfs(object):
m = self._method_info
return m[0](method)
def get_overhead(self, direction):
return self.obfs.get_overhead(direction)
def client_pre_encrypt(self, buf):
return self.obfs.client_pre_encrypt(buf)

20
shadowsocks/obfsplugin/auth.py

@ -82,10 +82,14 @@ class auth_base(plain.plain):
super(auth_base, self).__init__(method)
self.method = method
self.no_compatible_method = ''
self.overhead = 7
def init_data(self):
return ''
def get_overhead(self, direction): # direction: true for c->s false for s->c
return self.overhead
def set_server_info(self, server_info):
self.server_info = server_info
@ -103,6 +107,7 @@ class auth_base(plain.plain):
def not_match_return(self, buf):
self.raw_trans = True
self.overhead = 0
if self.method == self.no_compatible_method:
return (b'E'*2048, False)
return (buf, False)
@ -871,6 +876,9 @@ class auth_aes128(auth_base):
def init_data(self):
return obfs_auth_v2_data()
def get_overhead(self, direction): # direction: true for c->s false for s->c
return 9
def set_server_info(self, server_info):
self.server_info = server_info
try:
@ -1174,10 +1182,14 @@ class auth_aes128_sha1(auth_base):
self.user_id = None
self.user_key = None
self.last_rnd_len = 0
self.overhead = 9
def init_data(self):
return obfs_auth_mu_data()
def get_overhead(self, direction): # direction: true for c->s false for s->c
return self.overhead
def set_server_info(self, server_info):
self.server_info = server_info
try:
@ -1198,9 +1210,15 @@ class auth_aes128_sha1(auth_base):
return int(v * max_val)
def rnd_data_len(self, buf_size, full_buf_size):
if full_buf_size >= self.server_info.buffer_size:
return 0
rev_len = self.server_info.tcp_mss - buf_size - 9
if rev_len <= 0 or self.last_rnd_len >= self.server_info.buffer_size or full_buf_size >= self.server_info.buffer_size:
if rev_len == 0:
return 0
if rev_len < 0:
if rev_len > -self.server_info.tcp_mss:
return self.trapezoid_random_int(rev_len + self.server_info.tcp_mss, -0.3)
return common.ord(os.urandom(1)[0]) % 32
if buf_size > 900:
return struct.unpack('>H', os.urandom(2))[0] % rev_len
return self.trapezoid_random_int(rev_len, -0.3)

5
shadowsocks/obfsplugin/obfs_tls.py

@ -65,10 +65,14 @@ class tls_ticket_auth(plain.plain):
self.client_id = b''
self.max_time_dif = 60 * 60 * 24 # time dif (second) setting
self.tls_version = b'\x03\x03'
self.overhead = 5
def init_data(self):
return obfs_auth_data()
def get_overhead(self, direction): # direction: true for c->s false for s->c
return self.overhead
def sni(self, url):
url = common.to_bytes(url)
data = b"\x00" + struct.pack('>H', len(url)) + url
@ -184,6 +188,7 @@ class tls_ticket_auth(plain.plain):
def decode_error_return(self, buf):
self.handshake_status = -1
self.overhead = 0
if self.method == 'tls1.2_ticket_auth':
return (b'E'*2048, False, False)
return (buf, True, False)

3
shadowsocks/obfsplugin/plain.py

@ -40,6 +40,9 @@ class plain(object):
def init_data(self):
return b''
def get_overhead(self, direction): # direction: true for c->s false for s->c
return 0
def get_server_info(self):
return self.server_info

63
shadowsocks/tcprelay.py

@ -91,6 +91,8 @@ WAIT_STATUS_READING = 1
WAIT_STATUS_WRITING = 2
WAIT_STATUS_READWRITING = WAIT_STATUS_READING | WAIT_STATUS_WRITING
NETWORK_MTU = 1492
TCP_MSS = NETWORK_MTU - 40
BUF_SIZE = 32 * 1024
UDP_MAX_BUF_SIZE = 65536
@ -137,6 +139,7 @@ class TCPRelayHandler(object):
self._accept_address = local_sock.getsockname()[:2]
self._user = None
self._user_id = server._listen_port
self._tcp_mss = TCP_MSS
# TCP Relay works as either sslocal or ssserver
# if is_local, this is sslocal
@ -151,6 +154,16 @@ class TCPRelayHandler(object):
return
self._encrypt_correct = True
self._obfs = obfs.obfs(config['obfs'])
self._protocol = obfs.obfs(config['protocol'])
self._overhead = self._obfs.get_overhead(self._is_local) + self._protocol.get_overhead(self._is_local)
self._recv_buffer_size = BUF_SIZE - self._overhead
try:
self._tcp_mss = local_sock.getsockopt(socket.SOL_TCP, socket.TCP_MAXSEG)
logging.debug("TCP MSS = %d" % (self._tcp_mss,))
except:
pass
server_info = obfs.server_info(server.obfs_data)
server_info.host = config['server']
server_info.port = server._listen_port
@ -165,11 +178,10 @@ class TCPRelayHandler(object):
server_info.key_str = common.to_bytes(config['password'])
server_info.key = self._encryptor.cipher_key
server_info.head_len = 30
server_info.tcp_mss = 1448
server_info.buffer_size = BUF_SIZE
server_info.tcp_mss = self._tcp_mss
server_info.buffer_size = self._recv_buffer_size
self._obfs.set_server_info(server_info)
self._protocol = obfs.obfs(config['protocol'])
server_info = obfs.server_info(server.protocol_data)
server_info.host = config['server']
server_info.port = server._listen_port
@ -184,8 +196,8 @@ class TCPRelayHandler(object):
server_info.key_str = common.to_bytes(config['password'])
server_info.key = self._encryptor.cipher_key
server_info.head_len = 30
server_info.tcp_mss = 1448
server_info.buffer_size = BUF_SIZE
server_info.tcp_mss = self._tcp_mss
server_info.buffer_size = self._recv_buffer_size
self._protocol.set_server_info(server_info)
self._redir_list = config.get('redirect', ["*#0.0.0.0:0"])
@ -439,18 +451,16 @@ class TCPRelayHandler(object):
items_sum = common.to_str(host).rsplit('#', 1)
items_match = common.to_str(items_sum[0]).rsplit(':', 1)
items = common.to_str(items_sum[1]).rsplit(':', 1)
if len(items_match) > 1:
if self._server._listen_port != int(items_match[1]):
continue
match_port = 0
if len(items_match) > 1:
if items_match[1] != "*":
try:
match_port = int(items_match[1])
if self._server._listen_port != int(items_match[1]) and int(items_match[1]) != 0:
continue
except:
pass
if items_match[0] != "*" and common.match_regex(items_match[0], ogn_data) == False and \
not (match_port == self._server._listen_port or match_port == 0):
if items_match[0] != "*" and common.match_regex(
items_match[0], ogn_data) == False:
continue
if len(items) > 1:
try:
@ -573,6 +583,12 @@ class TCPRelayHandler(object):
if header_result is None:
data = self._handel_protocol_error(self._client_address, ogn_data)
header_result = parse_header(data)
self._overhead = self._obfs.get_overhead(self._is_local) + self._protocol.get_overhead(self._is_local)
self._recv_buffer_size = BUF_SIZE - self._overhead
server_info = self._obfs.get_server_info()
server_info.buffer_size = self._recv_buffer_size
server_info = self._protocol.get_server_info()
server_info.buffer_size = self._recv_buffer_size
connecttype, remote_addr, remote_port, header_length = header_result
common.connect_log('%s connecting %s:%d via port %d by UID %d' %
((connecttype == 0) and 'TCP' or 'UDP',
@ -743,15 +759,30 @@ class TCPRelayHandler(object):
logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1]))
self.destroy()
def _get_read_size(self, sock, recv_buffer_size):
if self._overhead == 0:
return buffer_size
buffer_size = len(sock.recv(recv_buffer_size, socket.MSG_PEEK))
if buffer_size == recv_buffer_size:
return buffer_size
s = buffer_size % self._tcp_mss + self._overhead
if s > self._tcp_mss:
return buffer_size + s - self._tcp_mss
return buffer_size
def _on_local_read(self):
# handle all local read events and dispatch them to methods for
# each stage
if not self._local_sock:
return
is_local = self._is_local
if is_local:
recv_buffer_size = self._get_read_size(self._local_sock, self._recv_buffer_size)
else:
recv_buffer_size = BUF_SIZE
data = None
try:
data = self._local_sock.recv(BUF_SIZE)
data = self._local_sock.recv(recv_buffer_size)
except (OSError, IOError) as e:
if eventloop.errno_from_exception(e) in \
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
@ -848,7 +879,11 @@ class TCPRelayHandler(object):
data = struct.pack('>H', size) + data
#logging.info('UDP over TCP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1]))
else:
data = self._remote_sock.recv(BUF_SIZE)
if self._is_local:
recv_buffer_size = BUF_SIZE
else:
recv_buffer_size = self._get_read_size(self._remote_sock, self._recv_buffer_size)
data = self._remote_sock.recv(recv_buffer_size)
except (OSError, IOError) as e:
if eventloop.errno_from_exception(e) in \
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK, 10035): #errno.WSAEWOULDBLOCK

5
shadowsocks/udprelay.py

@ -75,9 +75,6 @@ import threading
from shadowsocks import encrypt, obfs, eventloop, lru_cache, common, shell
from shadowsocks.common import pre_parse_header, parse_header, pack_addr
# we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time
TIMEOUTS_CLEAN_SIZE = 512
# for each handler, we have 2 stream directions:
# upstream: from client to server direction
# read local and write to remote
@ -927,7 +924,7 @@ class UDPRelay(object):
server_info.key_str = common.to_bytes(config['password'])
server_info.key = encrypt.encrypt_key(self._password, self._method)
server_info.head_len = 30
server_info.tcp_mss = 1440
server_info.tcp_mss = 1452
server_info.buffer_size = BUF_SIZE
self._protocol.set_server_info(server_info)

Loading…
Cancel
Save