commit
401da7815f
3 changed files with 63 additions and 14 deletions
|
@ -21,7 +21,7 @@ from __future__ import absolute_import, division, print_function, \
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import logging
|
import logging
|
||||||
|
import binascii
|
||||||
|
|
||||||
def compat_ord(s):
|
def compat_ord(s):
|
||||||
if type(s) == int:
|
if type(s) == int:
|
||||||
|
@ -160,6 +160,21 @@ def pre_parse_header(data):
|
||||||
'encryption method')
|
'encryption method')
|
||||||
return None
|
return None
|
||||||
data = data[rand_data_size + 3:]
|
data = data[rand_data_size + 3:]
|
||||||
|
elif datatype == 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
|
return data
|
||||||
|
|
||||||
def parse_header(data):
|
def parse_header(data):
|
||||||
|
|
|
@ -21,7 +21,6 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import random
|
|
||||||
|
|
||||||
from shadowsocks import common
|
from shadowsocks import common
|
||||||
from shadowsocks.crypto import rc4_md5, openssl, sodium, table
|
from shadowsocks.crypto import rc4_md5, openssl, sodium, table
|
||||||
|
@ -35,10 +34,7 @@ method_supported.update(table.ciphers)
|
||||||
|
|
||||||
|
|
||||||
def random_string(length):
|
def random_string(length):
|
||||||
try:
|
|
||||||
return os.urandom(length)
|
return os.urandom(length)
|
||||||
except (AttributeError, NotImplementedError):
|
|
||||||
return ''.join(chr(random.randrange(255)) for _ in range(length))
|
|
||||||
|
|
||||||
|
|
||||||
cached_keys = {}
|
cached_keys = {}
|
||||||
|
|
|
@ -30,6 +30,10 @@ import random
|
||||||
from shadowsocks import encrypt, eventloop, shell, common
|
from shadowsocks import encrypt, eventloop, shell, common
|
||||||
from shadowsocks.common import pre_parse_header, parse_header
|
from shadowsocks.common import pre_parse_header, parse_header
|
||||||
|
|
||||||
|
# set it 'False' to use both new protocol and the original shadowsocks protocal
|
||||||
|
# set it 'True' to use new protocol ONLY, to avoid GFW detecting
|
||||||
|
FORCE_NEW_PROTOCOL = False
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
|
@ -110,6 +114,7 @@ class TCPRelayHandler(object):
|
||||||
self._stage = STAGE_INIT
|
self._stage = STAGE_INIT
|
||||||
self._encryptor = encrypt.Encryptor(config['password'],
|
self._encryptor = encrypt.Encryptor(config['password'],
|
||||||
config['method'])
|
config['method'])
|
||||||
|
self._encrypt_correct = True
|
||||||
self._fastopen_connected = False
|
self._fastopen_connected = False
|
||||||
self._data_to_write_to_local = []
|
self._data_to_write_to_local = []
|
||||||
self._data_to_write_to_remote = []
|
self._data_to_write_to_remote = []
|
||||||
|
@ -277,6 +282,31 @@ class TCPRelayHandler(object):
|
||||||
logging.error('write_all_to_sock:unknown socket')
|
logging.error('write_all_to_sock:unknown socket')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _get_redirect_host(self, client_address, ogn_data):
|
||||||
|
# test
|
||||||
|
host_list = [("www.bing.com", 80), ("www.microsoft.com", 80), ("www.baidu.com", 443), ("www.qq.com", 80), ("www.csdn.net", 80), ("1.2.3.4", 1000)]
|
||||||
|
hash_code = binascii.crc32(ogn_data)
|
||||||
|
addrs = socket.getaddrinfo(client_address[0], client_address[1], 0, socket.SOCK_STREAM, socket.SOL_TCP)
|
||||||
|
af, socktype, proto, canonname, sa = addrs[0]
|
||||||
|
address_bytes = common.inet_pton(af, sa[0])
|
||||||
|
if len(address_bytes) == 16:
|
||||||
|
addr = struct.unpack('>Q', address_bytes[8:])[0]
|
||||||
|
if len(address_bytes) == 4:
|
||||||
|
addr = struct.unpack('>I', address_bytes)[0]
|
||||||
|
else:
|
||||||
|
addr = 0
|
||||||
|
return host_list[((hash_code & 0xffffffff) + addr + 3) % len(host_list)]
|
||||||
|
|
||||||
|
def _handel_protocol_error(self, client_address, ogn_data):
|
||||||
|
logging.warn("Protocol ERROR, TCP ogn data %s" % (binascii.hexlify(ogn_data), ))
|
||||||
|
self._encrypt_correct = False
|
||||||
|
#create redirect or disconnect by hash code
|
||||||
|
host, port = self._get_redirect_host(client_address, ogn_data)
|
||||||
|
data = "\x03" + chr(len(host)) + host + struct.pack('>H', port)
|
||||||
|
logging.warn("TCP data redir %s:%d %s" % (host, port, binascii.hexlify(data)))
|
||||||
|
#raise Exception('can not parse header')
|
||||||
|
return data + ogn_data
|
||||||
|
|
||||||
def _handle_stage_connecting(self, data):
|
def _handle_stage_connecting(self, data):
|
||||||
if self._is_local:
|
if self._is_local:
|
||||||
data = self._encryptor.encrypt(data)
|
data = self._encryptor.encrypt(data)
|
||||||
|
@ -315,7 +345,7 @@ class TCPRelayHandler(object):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def _handle_stage_addr(self, data):
|
def _handle_stage_addr(self, ogn_data, data):
|
||||||
try:
|
try:
|
||||||
if self._is_local:
|
if self._is_local:
|
||||||
cmd = common.ord(data[1])
|
cmd = common.ord(data[1])
|
||||||
|
@ -341,12 +371,17 @@ class TCPRelayHandler(object):
|
||||||
logging.error('unknown command %d', cmd)
|
logging.error('unknown command %d', cmd)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
before_parse_data = data
|
||||||
|
if FORCE_NEW_PROTOCOL and ord(data[0]) != 0x88:
|
||||||
|
data = self._handel_protocol_error(self._client_address, ogn_data)
|
||||||
data = pre_parse_header(data)
|
data = pre_parse_header(data)
|
||||||
if data is None:
|
if data is None:
|
||||||
raise Exception('can not parse header')
|
data = self._handel_protocol_error(self._client_address, ogn_data)
|
||||||
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')
|
data = self._handel_protocol_error(self._client_address, ogn_data)
|
||||||
|
header_result = parse_header(data)
|
||||||
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',
|
||||||
|
@ -491,8 +526,10 @@ class TCPRelayHandler(object):
|
||||||
if not data:
|
if not data:
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
|
ogn_data = data
|
||||||
self._update_activity(len(data))
|
self._update_activity(len(data))
|
||||||
if not is_local:
|
if not is_local:
|
||||||
|
if self._encrypt_correct:
|
||||||
data = self._encryptor.decrypt(data)
|
data = self._encryptor.decrypt(data)
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
@ -511,7 +548,7 @@ class TCPRelayHandler(object):
|
||||||
self._handle_stage_connecting(data)
|
self._handle_stage_connecting(data)
|
||||||
elif (is_local and self._stage == STAGE_ADDR) or \
|
elif (is_local and self._stage == STAGE_ADDR) or \
|
||||||
(not is_local and self._stage == STAGE_INIT):
|
(not is_local and self._stage == STAGE_INIT):
|
||||||
self._handle_stage_addr(data)
|
self._handle_stage_addr(ogn_data, data)
|
||||||
|
|
||||||
def _on_remote_read(self, is_remote_sock):
|
def _on_remote_read(self, is_remote_sock):
|
||||||
# handle all remote read events
|
# handle all remote read events
|
||||||
|
@ -545,6 +582,7 @@ class TCPRelayHandler(object):
|
||||||
if self._is_local:
|
if self._is_local:
|
||||||
data = self._encryptor.decrypt(data)
|
data = self._encryptor.decrypt(data)
|
||||||
else:
|
else:
|
||||||
|
if self._encrypt_correct:
|
||||||
data = self._encryptor.encrypt(data)
|
data = self._encryptor.encrypt(data)
|
||||||
try:
|
try:
|
||||||
self._write_to_sock(data, self._local_sock)
|
self._write_to_sock(data, self._local_sock)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue