auto adjust TCP_MAXSEG
This commit is contained in:
parent
8e27035851
commit
d82c931f8e
6 changed files with 84 additions and 20 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
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 full_buf_size >= self.server_info.buffer_size:
|
||||
return 0
|
||||
rev_len = self.server_info.tcp_mss - buf_size - 9
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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…
Add table
Reference in a new issue