add additional_ports in config
using user's password as protocol param in multi-user mode
This commit is contained in:
parent
e2957e672e
commit
e1b199fc44
7 changed files with 88 additions and 51 deletions
|
@ -6,8 +6,6 @@
|
||||||
"local_port": 1080,
|
"local_port": 1080,
|
||||||
|
|
||||||
"password": "m",
|
"password": "m",
|
||||||
"timeout": 120,
|
|
||||||
"udp_timeout": 60,
|
|
||||||
"method": "aes-128-ctr",
|
"method": "aes-128-ctr",
|
||||||
"protocol": "auth_aes128_md5",
|
"protocol": "auth_aes128_md5",
|
||||||
"protocol_param": "",
|
"protocol_param": "",
|
||||||
|
@ -16,6 +14,9 @@
|
||||||
"speed_limit_per_con": 0,
|
"speed_limit_per_con": 0,
|
||||||
"speed_limit_per_user": 0,
|
"speed_limit_per_user": 0,
|
||||||
|
|
||||||
|
"additional_ports" : {}, // only works under multi-user mode
|
||||||
|
"timeout": 120,
|
||||||
|
"udp_timeout": 60,
|
||||||
"dns_ipv6": false,
|
"dns_ipv6": false,
|
||||||
"connect_verbose_info": 0,
|
"connect_verbose_info": 0,
|
||||||
"redirect": "",
|
"redirect": "",
|
||||||
|
|
|
@ -24,6 +24,7 @@ class TransferBase(object):
|
||||||
self.port_uid_table = {} #端口到uid的映射(仅v3以上有用)
|
self.port_uid_table = {} #端口到uid的映射(仅v3以上有用)
|
||||||
self.onlineuser_cache = lru_cache.LRUCache(timeout=60*30) #用户在线状态记录
|
self.onlineuser_cache = lru_cache.LRUCache(timeout=60*30) #用户在线状态记录
|
||||||
self.pull_ok = False #记录是否已经拉出过数据
|
self.pull_ok = False #记录是否已经拉出过数据
|
||||||
|
self.mu_ports = {}
|
||||||
|
|
||||||
def load_cfg(self):
|
def load_cfg(self):
|
||||||
pass
|
pass
|
||||||
|
@ -41,7 +42,7 @@ class TransferBase(object):
|
||||||
dt_transfer[id] = [self.last_get_transfer[id][0] - last_transfer[id][0], self.last_get_transfer[id][1] - last_transfer[id][1]]
|
dt_transfer[id] = [self.last_get_transfer[id][0] - last_transfer[id][0], self.last_get_transfer[id][1] - last_transfer[id][1]]
|
||||||
|
|
||||||
for id in curr_transfer.keys():
|
for id in curr_transfer.keys():
|
||||||
if id in self.force_update_transfer:
|
if id in self.force_update_transfer or id in self.mu_ports:
|
||||||
continue
|
continue
|
||||||
#算出与上次记录的流量差值,保存于dt_transfer表
|
#算出与上次记录的流量差值,保存于dt_transfer表
|
||||||
if id in last_transfer:
|
if id in last_transfer:
|
||||||
|
@ -95,11 +96,13 @@ class TransferBase(object):
|
||||||
|
|
||||||
port = row['port']
|
port = row['port']
|
||||||
passwd = common.to_bytes(row['passwd'])
|
passwd = common.to_bytes(row['passwd'])
|
||||||
|
if hasattr(passwd, 'encode'):
|
||||||
|
passwd = passwd.encode('utf-8')
|
||||||
cfg = {'password': passwd}
|
cfg = {'password': passwd}
|
||||||
if 'id' in row:
|
if 'id' in row:
|
||||||
self.port_uid_table[row['port']] = row['id']
|
self.port_uid_table[row['port']] = row['id']
|
||||||
|
|
||||||
read_config_keys = ['method', 'obfs', 'obfs_param', 'protocol', 'protocol_param', 'forbidden_ip', 'forbidden_port']
|
read_config_keys = ['method', 'obfs', 'obfs_param', 'protocol', 'protocol_param', 'forbidden_ip', 'forbidden_port', 'speed_limit_per_con', 'speed_limit_per_user']
|
||||||
for name in read_config_keys:
|
for name in read_config_keys:
|
||||||
if name in row and row[name]:
|
if name in row and row[name]:
|
||||||
cfg[name] = row[name]
|
cfg[name] = row[name]
|
||||||
|
@ -116,10 +119,11 @@ class TransferBase(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if allow:
|
if allow:
|
||||||
allow_users[port] = 1
|
allow_users[port] = passwd
|
||||||
if 'protocol' in cfg and 'protocol_param' in cfg and common.to_str(cfg['protocol']) in ['auth_aes128_md5', 'auth_aes128_sha1']:
|
if 'protocol' in cfg and 'protocol_param' in cfg and common.to_str(cfg['protocol']) in ['auth_aes128_md5', 'auth_aes128_sha1']:
|
||||||
if '#' in common.to_str(cfg['protocol_param']):
|
if '#' in common.to_str(cfg['protocol_param']):
|
||||||
mu_servers[port] = 1
|
mu_servers[port] = passwd
|
||||||
|
del allow_users[port]
|
||||||
|
|
||||||
cfgchange = False
|
cfgchange = False
|
||||||
if port in ServerPool.get_instance().tcp_servers_pool:
|
if port in ServerPool.get_instance().tcp_servers_pool:
|
||||||
|
@ -177,10 +181,11 @@ class TransferBase(object):
|
||||||
passwd, cfg = new_servers[port]
|
passwd, cfg = new_servers[port]
|
||||||
self.new_server(port, passwd, cfg)
|
self.new_server(port, passwd, cfg)
|
||||||
|
|
||||||
if isinstance(self, MuJsonTransfer): # works in MuJsonTransfer only
|
|
||||||
logging.debug('db allow users %s \nmu_servers %s' % (allow_users, mu_servers))
|
logging.debug('db allow users %s \nmu_servers %s' % (allow_users, mu_servers))
|
||||||
for port in mu_servers:
|
for port in mu_servers:
|
||||||
ServerPool.get_instance().update_mu_server(port, None, allow_users)
|
ServerPool.get_instance().update_mu_users(port, allow_users)
|
||||||
|
|
||||||
|
self.mu_ports = mu_servers
|
||||||
|
|
||||||
def clear_cache(self, port):
|
def clear_cache(self, port):
|
||||||
if port in self.force_update_transfer: del self.force_update_transfer[port]
|
if port in self.force_update_transfer: del self.force_update_transfer[port]
|
||||||
|
@ -237,6 +242,17 @@ class TransferBase(object):
|
||||||
rows = db_instance.pull_db_all_user()
|
rows = db_instance.pull_db_all_user()
|
||||||
if rows:
|
if rows:
|
||||||
db_instance.pull_ok = True
|
db_instance.pull_ok = True
|
||||||
|
config = shell.get_config(False)
|
||||||
|
for port in config['additional_ports']:
|
||||||
|
val = config['additional_ports'][port]
|
||||||
|
val['port'] = int(port)
|
||||||
|
val['enable'] = 1
|
||||||
|
val['transfer_enable'] = 1024 ** 7
|
||||||
|
val['u'] = 0
|
||||||
|
val['d'] = 0
|
||||||
|
if "password" in val:
|
||||||
|
val["passwd"] = val["password"]
|
||||||
|
rows.append(val)
|
||||||
db_instance.del_server_out_of_bound_safe(last_rows, rows)
|
db_instance.del_server_out_of_bound_safe(last_rows, rows)
|
||||||
last_rows = rows
|
last_rows = rows
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -68,24 +68,17 @@ class MuMgr(object):
|
||||||
obfs = user.get('obfs', '')
|
obfs = user.get('obfs', '')
|
||||||
protocol = protocol.replace("_compatible", "")
|
protocol = protocol.replace("_compatible", "")
|
||||||
obfs = obfs.replace("_compatible", "")
|
obfs = obfs.replace("_compatible", "")
|
||||||
link = "%s:%s:%s:%s:%s:%s" % (self.server_addr, user['port'], protocol, user['method'], obfs, common.to_str(base64.urlsafe_b64encode(common.to_bytes(user['passwd']))).replace("=", ""))
|
protocol_param = ''
|
||||||
if muid is not None:
|
if muid is not None:
|
||||||
protocol_param = user.get('protocol_param', '')
|
protocol_param_ = user.get('protocol_param', '')
|
||||||
param = protocol_param.split('#')
|
param = protocol_param_.split('#')
|
||||||
if len(param) == 2:
|
if len(param) == 2:
|
||||||
user_dict = {}
|
for row in self.data.json:
|
||||||
user_list = param[1].split(',')
|
if int(row['port']) == muid:
|
||||||
if user_list:
|
param = str(muid) + ':' + row['passwd']
|
||||||
for userinfo in user_list:
|
|
||||||
items = userinfo.split(':')
|
|
||||||
if len(items) == 2:
|
|
||||||
user_int_id = int(items[0])
|
|
||||||
passwd = items[1]
|
|
||||||
user_dict[user_int_id] = passwd
|
|
||||||
if muid in user_dict:
|
|
||||||
param = str(muid) + ':' + user_dict[muid]
|
|
||||||
protocol_param = '/?protoparam=' + base64.urlsafe_b64encode(common.to_bytes(param)).replace("=", "")
|
protocol_param = '/?protoparam=' + base64.urlsafe_b64encode(common.to_bytes(param)).replace("=", "")
|
||||||
link += protocol_param
|
break
|
||||||
|
link = ("%s:%s:%s:%s:%s:%s" % (self.server_addr, user['port'], protocol, user['method'], obfs, common.to_str(base64.urlsafe_b64encode(common.to_bytes(user['passwd']))).replace("=", ""))) + protocol_param
|
||||||
return "ssr://" + (encode and common.to_str(base64.urlsafe_b64encode(common.to_bytes(link))).replace("=", "") or link)
|
return "ssr://" + (encode and common.to_str(base64.urlsafe_b64encode(common.to_bytes(link))).replace("=", "") or link)
|
||||||
|
|
||||||
def userinfo(self, user, muid = None):
|
def userinfo(self, user, muid = None):
|
||||||
|
@ -98,7 +91,18 @@ class MuMgr(object):
|
||||||
if key in ['enable'] or key not in user:
|
if key in ['enable'] or key not in user:
|
||||||
continue
|
continue
|
||||||
ret += '\n'
|
ret += '\n'
|
||||||
if key in ['transfer_enable', 'u', 'd']:
|
if (muid is not None) and (key in ['protocol_param']):
|
||||||
|
for row in self.data.json:
|
||||||
|
if int(row['port']) == muid:
|
||||||
|
ret += " %s : %s" % (key, str(muid) + ':' + row['passwd'])
|
||||||
|
break
|
||||||
|
elif key in ['transfer_enable', 'u', 'd']:
|
||||||
|
if muid is not None:
|
||||||
|
for row in self.data.json:
|
||||||
|
if int(row['port']) == muid:
|
||||||
|
val = row[key]
|
||||||
|
break
|
||||||
|
else:
|
||||||
val = user[key]
|
val = user[key]
|
||||||
if val / 1024 < 4:
|
if val / 1024 < 4:
|
||||||
ret += " %s : %s" % (key, val)
|
ret += " %s : %s" % (key, val)
|
||||||
|
|
|
@ -214,24 +214,24 @@ class ServerPool(object):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_mu_server(self, port, protocol_param, acl):
|
def update_mu_users(self, port, users):
|
||||||
port = int(port)
|
port = int(port)
|
||||||
if port in self.tcp_servers_pool:
|
if port in self.tcp_servers_pool:
|
||||||
try:
|
try:
|
||||||
self.tcp_servers_pool[port].update_users(protocol_param, acl)
|
self.tcp_servers_pool[port].update_users(users)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
try:
|
try:
|
||||||
self.udp_servers_pool[port].update_users(protocol_param, acl)
|
self.udp_servers_pool[port].update_users(users)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
if port in self.tcp_ipv6_servers_pool:
|
if port in self.tcp_ipv6_servers_pool:
|
||||||
try:
|
try:
|
||||||
self.tcp_ipv6_servers_pool[port].update_users(protocol_param, acl)
|
self.tcp_ipv6_servers_pool[port].update_users(users)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
try:
|
try:
|
||||||
self.udp_ipv6_servers_pool[port].update_users(protocol_param, acl)
|
self.udp_ipv6_servers_pool[port].update_users(users)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warn(e)
|
logging.warn(e)
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ def get_config(is_local):
|
||||||
|
|
||||||
|
|
||||||
if config_path:
|
if config_path:
|
||||||
logging.info('loading config from %s' % config_path)
|
logging.debug('loading config from %s' % config_path)
|
||||||
with open(config_path, 'rb') as f:
|
with open(config_path, 'rb') as f:
|
||||||
try:
|
try:
|
||||||
config = parse_json_in_str(remove_comment(f.read().decode('utf8')))
|
config = parse_json_in_str(remove_comment(f.read().decode('utf8')))
|
||||||
|
@ -244,6 +244,7 @@ def get_config(is_local):
|
||||||
config['obfs'] = to_str(config.get('obfs', 'plain'))
|
config['obfs'] = to_str(config.get('obfs', 'plain'))
|
||||||
config['obfs_param'] = to_str(config.get('obfs_param', ''))
|
config['obfs_param'] = to_str(config.get('obfs_param', ''))
|
||||||
config['port_password'] = config.get('port_password', None)
|
config['port_password'] = config.get('port_password', None)
|
||||||
|
config['additional_ports'] = config.get('additional_ports', {})
|
||||||
config['timeout'] = int(config.get('timeout', 300))
|
config['timeout'] = int(config.get('timeout', 300))
|
||||||
config['udp_timeout'] = int(config.get('udp_timeout', 120))
|
config['udp_timeout'] = int(config.get('udp_timeout', 120))
|
||||||
config['udp_cache'] = int(config.get('udp_cache', 64))
|
config['udp_cache'] = int(config.get('udp_cache', 64))
|
||||||
|
|
|
@ -101,6 +101,9 @@ class SpeedTester(object):
|
||||||
self._cache = deque()
|
self._cache = deque()
|
||||||
self.sum_len = 0
|
self.sum_len = 0
|
||||||
|
|
||||||
|
def update_limit(self, max_speed):
|
||||||
|
self.max_speed = max_speed * 1024
|
||||||
|
|
||||||
def add(self, data_len):
|
def add(self, data_len):
|
||||||
if self.max_speed > 0:
|
if self.max_speed > 0:
|
||||||
self._cache.append((time.time(), data_len))
|
self._cache.append((time.time(), data_len))
|
||||||
|
@ -1057,8 +1060,6 @@ class TCPRelay(object):
|
||||||
self.mu = False
|
self.mu = False
|
||||||
self._speed_tester_u = {}
|
self._speed_tester_u = {}
|
||||||
self._speed_tester_d = {}
|
self._speed_tester_d = {}
|
||||||
self.update_users_protocol_param = None
|
|
||||||
self.update_users_acl = None
|
|
||||||
self.server_connections = 0
|
self.server_connections = 0
|
||||||
self.protocol_data = obfs.obfs(config['protocol']).init_data()
|
self.protocol_data = obfs.obfs(config['protocol']).init_data()
|
||||||
self.obfs_data = obfs.obfs(config['obfs']).init_data()
|
self.obfs_data = obfs.obfs(config['obfs']).init_data()
|
||||||
|
@ -1145,9 +1146,18 @@ class TCPRelay(object):
|
||||||
passwd = items[1]
|
passwd = items[1]
|
||||||
self.add_user(uid, passwd)
|
self.add_user(uid, passwd)
|
||||||
|
|
||||||
def update_users(self, protocol_param, acl):
|
def update_user(self, id, passwd):
|
||||||
self.update_users_protocol_param = protocol_param
|
uid = struct.pack('<I', id)
|
||||||
self.update_users_acl = acl
|
self.add_user(uid, passwd)
|
||||||
|
|
||||||
|
def update_users(self, users):
|
||||||
|
for uid in list(self.server_users.keys()):
|
||||||
|
id = struct.unpack('<I', uid)[0]
|
||||||
|
if id not in users:
|
||||||
|
self.del_user(uid)
|
||||||
|
for id in users:
|
||||||
|
uid = struct.pack('<I', id)
|
||||||
|
self.add_user(uid, users[id])
|
||||||
|
|
||||||
def add_user(self, user, passwd): # user: binstr[4], passwd: str
|
def add_user(self, user, passwd): # user: binstr[4], passwd: str
|
||||||
self.server_users[user] = common.to_bytes(passwd)
|
self.server_users[user] = common.to_bytes(passwd)
|
||||||
|
@ -1190,6 +1200,12 @@ class TCPRelay(object):
|
||||||
self._speed_tester_d[uid] = SpeedTester(self._config.get("speed_limit_per_user", 0))
|
self._speed_tester_d[uid] = SpeedTester(self._config.get("speed_limit_per_user", 0))
|
||||||
return self._speed_tester_d[uid]
|
return self._speed_tester_d[uid]
|
||||||
|
|
||||||
|
def update_limit(self, uid, max_speed):
|
||||||
|
if uid in self._speed_tester_u:
|
||||||
|
self._speed_tester_u[uid].update_limit(max_speed)
|
||||||
|
if uid in self._speed_tester_d:
|
||||||
|
self._speed_tester_d[uid].update_limit(max_speed)
|
||||||
|
|
||||||
def update_stat(self, port, stat_dict, val):
|
def update_stat(self, port, stat_dict, val):
|
||||||
newval = stat_dict.get(0, 0) + val
|
newval = stat_dict.get(0, 0) + val
|
||||||
stat_dict[0] = newval
|
stat_dict[0] = newval
|
||||||
|
@ -1286,10 +1302,6 @@ class TCPRelay(object):
|
||||||
logging.info('closed TCP port %d', self._listen_port)
|
logging.info('closed TCP port %d', self._listen_port)
|
||||||
for handler in list(self._fd_to_handlers.values()):
|
for handler in list(self._fd_to_handlers.values()):
|
||||||
handler.destroy()
|
handler.destroy()
|
||||||
elif self.update_users_protocol_param is not None or self.update_users_acl is not None:
|
|
||||||
self._update_users(self.update_users_protocol_param, self.update_users_acl)
|
|
||||||
self.update_users_protocol_param = None
|
|
||||||
self.update_users_acl = None
|
|
||||||
self._sweep_timeout()
|
self._sweep_timeout()
|
||||||
|
|
||||||
def close(self, next_tick=False):
|
def close(self, next_tick=False):
|
||||||
|
|
|
@ -910,8 +910,6 @@ class UDPRelay(object):
|
||||||
self.server_users = {}
|
self.server_users = {}
|
||||||
self.server_user_transfer_ul = {}
|
self.server_user_transfer_ul = {}
|
||||||
self.server_user_transfer_dl = {}
|
self.server_user_transfer_dl = {}
|
||||||
self.update_users_protocol_param = None
|
|
||||||
self.update_users_acl = None
|
|
||||||
|
|
||||||
if common.to_bytes(config['protocol']) in [b"auth_aes128_md5", b"auth_aes128_sha1"]:
|
if common.to_bytes(config['protocol']) in [b"auth_aes128_md5", b"auth_aes128_sha1"]:
|
||||||
self._update_users(None, None)
|
self._update_users(None, None)
|
||||||
|
@ -1000,9 +998,18 @@ class UDPRelay(object):
|
||||||
passwd = items[1]
|
passwd = items[1]
|
||||||
self.add_user(uid, passwd)
|
self.add_user(uid, passwd)
|
||||||
|
|
||||||
def update_users(self, protocol_param, acl):
|
def update_user(self, id, passwd):
|
||||||
self.update_users_protocol_param = protocol_param
|
uid = struct.pack('<I', id)
|
||||||
self.update_users_acl = acl
|
self.add_user(uid, passwd)
|
||||||
|
|
||||||
|
def update_users(self, users):
|
||||||
|
for uid in list(self.server_users.keys()):
|
||||||
|
id = struct.unpack('<I', uid)[0]
|
||||||
|
if id not in users:
|
||||||
|
self.del_user(uid)
|
||||||
|
for id in users:
|
||||||
|
uid = struct.pack('<I', id)
|
||||||
|
self.add_user(uid, users[id])
|
||||||
|
|
||||||
def add_user(self, user, passwd): # user: binstr[4], passwd: str
|
def add_user(self, user, passwd): # user: binstr[4], passwd: str
|
||||||
self.server_users[user] = common.to_bytes(passwd)
|
self.server_users[user] = common.to_bytes(passwd)
|
||||||
|
@ -1476,10 +1483,6 @@ class UDPRelay(object):
|
||||||
self._dns_cache.sweep()
|
self._dns_cache.sweep()
|
||||||
if before_sweep_size != len(self._sockets):
|
if before_sweep_size != len(self._sockets):
|
||||||
logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets)))
|
logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets)))
|
||||||
if self.update_users_protocol_param is not None or self.update_users_acl is not None:
|
|
||||||
self._update_users(self.update_users_protocol_param, self.update_users_acl)
|
|
||||||
self.update_users_protocol_param = None
|
|
||||||
self.update_users_acl = None
|
|
||||||
self._sweep_timeout()
|
self._sweep_timeout()
|
||||||
|
|
||||||
def close(self, next_tick=False):
|
def close(self, next_tick=False):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue