From e1b199fc44008f226eb786f9aaa3b210aa3ed8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=B4=E5=A8=83=E9=85=B1?= Date: Sun, 19 Feb 2017 10:27:25 +0800 Subject: [PATCH] add additional_ports in config using user's password as protocol param in multi-user mode --- config.json | 5 +++-- db_transfer.py | 32 ++++++++++++++++++++++++-------- mujson_mgr.py | 38 +++++++++++++++++++++----------------- server_pool.py | 10 +++++----- shadowsocks/shell.py | 3 ++- shadowsocks/tcprelay.py | 30 +++++++++++++++++++++--------- shadowsocks/udprelay.py | 21 ++++++++++++--------- 7 files changed, 88 insertions(+), 51 deletions(-) diff --git a/config.json b/config.json index ef4c79e..988100f 100644 --- a/config.json +++ b/config.json @@ -6,8 +6,6 @@ "local_port": 1080, "password": "m", - "timeout": 120, - "udp_timeout": 60, "method": "aes-128-ctr", "protocol": "auth_aes128_md5", "protocol_param": "", @@ -16,6 +14,9 @@ "speed_limit_per_con": 0, "speed_limit_per_user": 0, + "additional_ports" : {}, // only works under multi-user mode + "timeout": 120, + "udp_timeout": 60, "dns_ipv6": false, "connect_verbose_info": 0, "redirect": "", diff --git a/db_transfer.py b/db_transfer.py index 4d6088f..5862de7 100644 --- a/db_transfer.py +++ b/db_transfer.py @@ -24,6 +24,7 @@ class TransferBase(object): self.port_uid_table = {} #端口到uid的映射(仅v3以上有用) self.onlineuser_cache = lru_cache.LRUCache(timeout=60*30) #用户在线状态记录 self.pull_ok = False #记录是否已经拉出过数据 + self.mu_ports = {} def load_cfg(self): 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]] 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 #算出与上次记录的流量差值,保存于dt_transfer表 if id in last_transfer: @@ -95,11 +96,13 @@ class TransferBase(object): port = row['port'] passwd = common.to_bytes(row['passwd']) + if hasattr(passwd, 'encode'): + passwd = passwd.encode('utf-8') cfg = {'password': passwd} if 'id' in row: 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: if name in row and row[name]: cfg[name] = row[name] @@ -116,10 +119,11 @@ class TransferBase(object): continue 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 '#' in common.to_str(cfg['protocol_param']): - mu_servers[port] = 1 + mu_servers[port] = passwd + del allow_users[port] cfgchange = False if port in ServerPool.get_instance().tcp_servers_pool: @@ -177,10 +181,11 @@ class TransferBase(object): passwd, cfg = new_servers[port] 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)) - for port in mu_servers: - ServerPool.get_instance().update_mu_server(port, None, allow_users) + logging.debug('db allow users %s \nmu_servers %s' % (allow_users, mu_servers)) + for port in mu_servers: + ServerPool.get_instance().update_mu_users(port, allow_users) + + self.mu_ports = mu_servers def clear_cache(self, 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() if rows: 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) last_rows = rows except Exception as e: diff --git a/mujson_mgr.py b/mujson_mgr.py index 5d85798..760763c 100644 --- a/mujson_mgr.py +++ b/mujson_mgr.py @@ -68,24 +68,17 @@ class MuMgr(object): obfs = user.get('obfs', '') protocol = protocol.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: - protocol_param = user.get('protocol_param', '') - param = protocol_param.split('#') + protocol_param_ = user.get('protocol_param', '') + param = protocol_param_.split('#') if len(param) == 2: - user_dict = {} - user_list = param[1].split(',') - if user_list: - 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] + for row in self.data.json: + if int(row['port']) == muid: + param = str(muid) + ':' + row['passwd'] 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) def userinfo(self, user, muid = None): @@ -98,8 +91,19 @@ class MuMgr(object): if key in ['enable'] or key not in user: continue ret += '\n' - if key in ['transfer_enable', 'u', 'd']: - val = user[key] + 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] if val / 1024 < 4: ret += " %s : %s" % (key, val) elif val / 1024 ** 2 < 4: diff --git a/server_pool.py b/server_pool.py index 45fe6a1..2e6a85b 100644 --- a/server_pool.py +++ b/server_pool.py @@ -214,24 +214,24 @@ class ServerPool(object): return True - def update_mu_server(self, port, protocol_param, acl): + def update_mu_users(self, port, users): port = int(port) if port in self.tcp_servers_pool: try: - self.tcp_servers_pool[port].update_users(protocol_param, acl) + self.tcp_servers_pool[port].update_users(users) except Exception as e: logging.warn(e) try: - self.udp_servers_pool[port].update_users(protocol_param, acl) + self.udp_servers_pool[port].update_users(users) except Exception as e: logging.warn(e) if port in self.tcp_ipv6_servers_pool: 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: logging.warn(e) 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: logging.warn(e) diff --git a/shadowsocks/shell.py b/shadowsocks/shell.py index 2fb268a..41d2323 100755 --- a/shadowsocks/shell.py +++ b/shadowsocks/shell.py @@ -168,7 +168,7 @@ def get_config(is_local): 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: try: 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_param'] = to_str(config.get('obfs_param', '')) config['port_password'] = config.get('port_password', None) + config['additional_ports'] = config.get('additional_ports', {}) config['timeout'] = int(config.get('timeout', 300)) config['udp_timeout'] = int(config.get('udp_timeout', 120)) config['udp_cache'] = int(config.get('udp_cache', 64)) diff --git a/shadowsocks/tcprelay.py b/shadowsocks/tcprelay.py index f4551f2..5afefc4 100644 --- a/shadowsocks/tcprelay.py +++ b/shadowsocks/tcprelay.py @@ -101,6 +101,9 @@ class SpeedTester(object): self._cache = deque() self.sum_len = 0 + def update_limit(self, max_speed): + self.max_speed = max_speed * 1024 + def add(self, data_len): if self.max_speed > 0: self._cache.append((time.time(), data_len)) @@ -1057,8 +1060,6 @@ class TCPRelay(object): self.mu = False self._speed_tester_u = {} self._speed_tester_d = {} - self.update_users_protocol_param = None - self.update_users_acl = None self.server_connections = 0 self.protocol_data = obfs.obfs(config['protocol']).init_data() self.obfs_data = obfs.obfs(config['obfs']).init_data() @@ -1145,9 +1146,18 @@ class TCPRelay(object): passwd = items[1] self.add_user(uid, passwd) - def update_users(self, protocol_param, acl): - self.update_users_protocol_param = protocol_param - self.update_users_acl = acl + def update_user(self, id, passwd): + uid = struct.pack('