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):
|
def set_server_info(self, server_info):
|
||||||
return self.obfs.set_server_info(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):
|
def get_method_info(self, method):
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
m = method_supported.get(method)
|
m = method_supported.get(method)
|
||||||
|
@ -62,6 +65,9 @@ class obfs(object):
|
||||||
m = self._method_info
|
m = self._method_info
|
||||||
return m[0](method)
|
return m[0](method)
|
||||||
|
|
||||||
|
def get_overhead(self, direction):
|
||||||
|
return self.obfs.get_overhead(direction)
|
||||||
|
|
||||||
def client_pre_encrypt(self, buf):
|
def client_pre_encrypt(self, buf):
|
||||||
return self.obfs.client_pre_encrypt(buf)
|
return self.obfs.client_pre_encrypt(buf)
|
||||||
|
|
||||||
|
|
|
@ -82,10 +82,14 @@ class auth_base(plain.plain):
|
||||||
super(auth_base, self).__init__(method)
|
super(auth_base, self).__init__(method)
|
||||||
self.method = method
|
self.method = method
|
||||||
self.no_compatible_method = ''
|
self.no_compatible_method = ''
|
||||||
|
self.overhead = 7
|
||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
return ''
|
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):
|
def set_server_info(self, server_info):
|
||||||
self.server_info = server_info
|
self.server_info = server_info
|
||||||
|
|
||||||
|
@ -103,6 +107,7 @@ class auth_base(plain.plain):
|
||||||
|
|
||||||
def not_match_return(self, buf):
|
def not_match_return(self, buf):
|
||||||
self.raw_trans = True
|
self.raw_trans = True
|
||||||
|
self.overhead = 0
|
||||||
if self.method == self.no_compatible_method:
|
if self.method == self.no_compatible_method:
|
||||||
return (b'E'*2048, False)
|
return (b'E'*2048, False)
|
||||||
return (buf, False)
|
return (buf, False)
|
||||||
|
@ -871,6 +876,9 @@ class auth_aes128(auth_base):
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
return obfs_auth_v2_data()
|
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):
|
def set_server_info(self, server_info):
|
||||||
self.server_info = server_info
|
self.server_info = server_info
|
||||||
try:
|
try:
|
||||||
|
@ -1174,10 +1182,14 @@ class auth_aes128_sha1(auth_base):
|
||||||
self.user_id = None
|
self.user_id = None
|
||||||
self.user_key = None
|
self.user_key = None
|
||||||
self.last_rnd_len = 0
|
self.last_rnd_len = 0
|
||||||
|
self.overhead = 9
|
||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
return obfs_auth_mu_data()
|
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):
|
def set_server_info(self, server_info):
|
||||||
self.server_info = server_info
|
self.server_info = server_info
|
||||||
try:
|
try:
|
||||||
|
@ -1198,9 +1210,15 @@ class auth_aes128_sha1(auth_base):
|
||||||
return int(v * max_val)
|
return int(v * max_val)
|
||||||
|
|
||||||
def rnd_data_len(self, buf_size, full_buf_size):
|
def rnd_data_len(self, buf_size, full_buf_size):
|
||||||
rev_len = self.server_info.tcp_mss - buf_size - 9
|
if full_buf_size >= self.server_info.buffer_size:
|
||||||
if rev_len <= 0 or self.last_rnd_len >= self.server_info.buffer_size or full_buf_size >= self.server_info.buffer_size:
|
|
||||||
return 0
|
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:
|
if buf_size > 900:
|
||||||
return struct.unpack('>H', os.urandom(2))[0] % rev_len
|
return struct.unpack('>H', os.urandom(2))[0] % rev_len
|
||||||
return self.trapezoid_random_int(rev_len, -0.3)
|
return self.trapezoid_random_int(rev_len, -0.3)
|
||||||
|
|
|
@ -65,10 +65,14 @@ class tls_ticket_auth(plain.plain):
|
||||||
self.client_id = b''
|
self.client_id = b''
|
||||||
self.max_time_dif = 60 * 60 * 24 # time dif (second) setting
|
self.max_time_dif = 60 * 60 * 24 # time dif (second) setting
|
||||||
self.tls_version = b'\x03\x03'
|
self.tls_version = b'\x03\x03'
|
||||||
|
self.overhead = 5
|
||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
return obfs_auth_data()
|
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):
|
def sni(self, url):
|
||||||
url = common.to_bytes(url)
|
url = common.to_bytes(url)
|
||||||
data = b"\x00" + struct.pack('>H', len(url)) + 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):
|
def decode_error_return(self, buf):
|
||||||
self.handshake_status = -1
|
self.handshake_status = -1
|
||||||
|
self.overhead = 0
|
||||||
if self.method == 'tls1.2_ticket_auth':
|
if self.method == 'tls1.2_ticket_auth':
|
||||||
return (b'E'*2048, False, False)
|
return (b'E'*2048, False, False)
|
||||||
return (buf, True, False)
|
return (buf, True, False)
|
||||||
|
|
|
@ -40,6 +40,9 @@ class plain(object):
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
return b''
|
return b''
|
||||||
|
|
||||||
|
def get_overhead(self, direction): # direction: true for c->s false for s->c
|
||||||
|
return 0
|
||||||
|
|
||||||
def get_server_info(self):
|
def get_server_info(self):
|
||||||
return self.server_info
|
return self.server_info
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,8 @@ WAIT_STATUS_READING = 1
|
||||||
WAIT_STATUS_WRITING = 2
|
WAIT_STATUS_WRITING = 2
|
||||||
WAIT_STATUS_READWRITING = WAIT_STATUS_READING | WAIT_STATUS_WRITING
|
WAIT_STATUS_READWRITING = WAIT_STATUS_READING | WAIT_STATUS_WRITING
|
||||||
|
|
||||||
|
NETWORK_MTU = 1492
|
||||||
|
TCP_MSS = NETWORK_MTU - 40
|
||||||
BUF_SIZE = 32 * 1024
|
BUF_SIZE = 32 * 1024
|
||||||
UDP_MAX_BUF_SIZE = 65536
|
UDP_MAX_BUF_SIZE = 65536
|
||||||
|
|
||||||
|
@ -137,6 +139,7 @@ class TCPRelayHandler(object):
|
||||||
self._accept_address = local_sock.getsockname()[:2]
|
self._accept_address = local_sock.getsockname()[:2]
|
||||||
self._user = None
|
self._user = None
|
||||||
self._user_id = server._listen_port
|
self._user_id = server._listen_port
|
||||||
|
self._tcp_mss = TCP_MSS
|
||||||
|
|
||||||
# TCP Relay works as either sslocal or ssserver
|
# TCP Relay works as either sslocal or ssserver
|
||||||
# if is_local, this is sslocal
|
# if is_local, this is sslocal
|
||||||
|
@ -151,6 +154,16 @@ class TCPRelayHandler(object):
|
||||||
return
|
return
|
||||||
self._encrypt_correct = True
|
self._encrypt_correct = True
|
||||||
self._obfs = obfs.obfs(config['obfs'])
|
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 = obfs.server_info(server.obfs_data)
|
||||||
server_info.host = config['server']
|
server_info.host = config['server']
|
||||||
server_info.port = server._listen_port
|
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_str = common.to_bytes(config['password'])
|
||||||
server_info.key = self._encryptor.cipher_key
|
server_info.key = self._encryptor.cipher_key
|
||||||
server_info.head_len = 30
|
server_info.head_len = 30
|
||||||
server_info.tcp_mss = 1448
|
server_info.tcp_mss = self._tcp_mss
|
||||||
server_info.buffer_size = BUF_SIZE
|
server_info.buffer_size = self._recv_buffer_size
|
||||||
self._obfs.set_server_info(server_info)
|
self._obfs.set_server_info(server_info)
|
||||||
|
|
||||||
self._protocol = obfs.obfs(config['protocol'])
|
|
||||||
server_info = obfs.server_info(server.protocol_data)
|
server_info = obfs.server_info(server.protocol_data)
|
||||||
server_info.host = config['server']
|
server_info.host = config['server']
|
||||||
server_info.port = server._listen_port
|
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_str = common.to_bytes(config['password'])
|
||||||
server_info.key = self._encryptor.cipher_key
|
server_info.key = self._encryptor.cipher_key
|
||||||
server_info.head_len = 30
|
server_info.head_len = 30
|
||||||
server_info.tcp_mss = 1448
|
server_info.tcp_mss = self._tcp_mss
|
||||||
server_info.buffer_size = BUF_SIZE
|
server_info.buffer_size = self._recv_buffer_size
|
||||||
self._protocol.set_server_info(server_info)
|
self._protocol.set_server_info(server_info)
|
||||||
|
|
||||||
self._redir_list = config.get('redirect', ["*#0.0.0.0:0"])
|
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_sum = common.to_str(host).rsplit('#', 1)
|
||||||
items_match = common.to_str(items_sum[0]).rsplit(':', 1)
|
items_match = common.to_str(items_sum[0]).rsplit(':', 1)
|
||||||
items = common.to_str(items_sum[1]).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 len(items_match) > 1:
|
||||||
if items_match[1] != "*":
|
if items_match[1] != "*":
|
||||||
try:
|
try:
|
||||||
match_port = int(items_match[1])
|
if self._server._listen_port != int(items_match[1]) and int(items_match[1]) != 0:
|
||||||
|
continue
|
||||||
except:
|
except:
|
||||||
pass
|
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
|
continue
|
||||||
if len(items) > 1:
|
if len(items) > 1:
|
||||||
try:
|
try:
|
||||||
|
@ -573,6 +583,12 @@ class TCPRelayHandler(object):
|
||||||
if header_result is None:
|
if header_result is None:
|
||||||
data = self._handel_protocol_error(self._client_address, ogn_data)
|
data = self._handel_protocol_error(self._client_address, ogn_data)
|
||||||
header_result = parse_header(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
|
connecttype, remote_addr, remote_port, header_length = header_result
|
||||||
common.connect_log('%s connecting %s:%d via port %d by UID %d' %
|
common.connect_log('%s connecting %s:%d via port %d by UID %d' %
|
||||||
((connecttype == 0) and 'TCP' or 'UDP',
|
((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]))
|
logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1]))
|
||||||
self.destroy()
|
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):
|
def _on_local_read(self):
|
||||||
# handle all local read events and dispatch them to methods for
|
# handle all local read events and dispatch them to methods for
|
||||||
# each stage
|
# each stage
|
||||||
if not self._local_sock:
|
if not self._local_sock:
|
||||||
return
|
return
|
||||||
is_local = self._is_local
|
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
|
data = None
|
||||||
try:
|
try:
|
||||||
data = self._local_sock.recv(BUF_SIZE)
|
data = self._local_sock.recv(recv_buffer_size)
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
if eventloop.errno_from_exception(e) in \
|
if eventloop.errno_from_exception(e) in \
|
||||||
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
|
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
|
||||||
|
@ -848,7 +879,11 @@ class TCPRelayHandler(object):
|
||||||
data = struct.pack('>H', size) + data
|
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]))
|
#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:
|
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:
|
except (OSError, IOError) as e:
|
||||||
if eventloop.errno_from_exception(e) in \
|
if eventloop.errno_from_exception(e) in \
|
||||||
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK, 10035): #errno.WSAEWOULDBLOCK
|
(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 import encrypt, obfs, eventloop, lru_cache, common, shell
|
||||||
from shadowsocks.common import pre_parse_header, parse_header, pack_addr
|
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:
|
# for each handler, we have 2 stream directions:
|
||||||
# upstream: from client to server direction
|
# upstream: from client to server direction
|
||||||
# read local and write to remote
|
# 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_str = common.to_bytes(config['password'])
|
||||||
server_info.key = encrypt.encrypt_key(self._password, self._method)
|
server_info.key = encrypt.encrypt_key(self._password, self._method)
|
||||||
server_info.head_len = 30
|
server_info.head_len = 30
|
||||||
server_info.tcp_mss = 1440
|
server_info.tcp_mss = 1452
|
||||||
server_info.buffer_size = BUF_SIZE
|
server_info.buffer_size = BUF_SIZE
|
||||||
self._protocol.set_server_info(server_info)
|
self._protocol.set_server_info(server_info)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue