Browse Source

multi-user for mudbjson mode

dev
破娃酱 8 years ago
parent
commit
2de2a553d7
  1. 67
      db_transfer.py
  2. 6
      mujson_mgr.py
  3. 68
      server_pool.py
  4. 51
      shadowsocks/tcprelay.py
  5. 49
      shadowsocks/udprelay.py

67
db_transfer.py

@ -85,6 +85,8 @@ class TransferBase(object):
logging.error('load switchrule.py fail') logging.error('load switchrule.py fail')
cur_servers = {} cur_servers = {}
new_servers = {} new_servers = {}
allow_users = {}
mu_servers = {}
for row in rows: for row in rows:
try: try:
allow = switchrule.isTurnOn(row) and row['enable'] == 1 and row['u'] + row['d'] < row['transfer_enable'] allow = switchrule.isTurnOn(row) and row['enable'] == 1 and row['u'] + row['d'] < row['transfer_enable']
@ -113,34 +115,50 @@ class TransferBase(object):
logging.error('more than one user use the same port [%s]' % (port,)) logging.error('more than one user use the same port [%s]' % (port,))
continue continue
if ServerPool.get_instance().server_is_run(port) > 0: if allow:
if not allow: allow_users[port] = 1
logging.info('db stop server at port [%s]' % (port,)) if 'protocol' in cfg and 'protocol_param' in cfg and common.to_str(cfg['protocol']) in ['auth_aes128_md5', 'auth_aes128_sha1']:
ServerPool.get_instance().cb_del_server(port) if '#' in common.to_str(cfg['protocol_param']):
self.force_update_transfer.add(port) mu_servers[port] = 1
else:
cfgchange = False cfgchange = False
if port in ServerPool.get_instance().tcp_servers_pool: if port in ServerPool.get_instance().tcp_servers_pool:
relay = ServerPool.get_instance().tcp_servers_pool[port] relay = ServerPool.get_instance().tcp_servers_pool[port]
for name in merge_config_keys: for name in merge_config_keys:
if name in cfg and not self.cmp(cfg[name], relay._config[name]): if name in cfg and not self.cmp(cfg[name], relay._config[name]):
cfgchange = True cfgchange = True
break; break
if not cfgchange and port in ServerPool.get_instance().tcp_ipv6_servers_pool: if not cfgchange and port in ServerPool.get_instance().tcp_ipv6_servers_pool:
relay = ServerPool.get_instance().tcp_ipv6_servers_pool[port] relay = ServerPool.get_instance().tcp_ipv6_servers_pool[port]
for name in merge_config_keys: for name in merge_config_keys:
if name in cfg and not self.cmp(cfg[name], relay._config[name]): if name in cfg and not self.cmp(cfg[name], relay._config[name]):
cfgchange = True cfgchange = True
break; break
#config changed
if port in mu_servers:
if ServerPool.get_instance().server_is_run(port) > 0:
if cfgchange: if cfgchange:
logging.info('db stop server at port [%s] reason: config changed: %s' % (port, cfg)) logging.info('db stop server at port [%s] reason: config changed: %s' % (port, cfg))
ServerPool.get_instance().cb_del_server(port) ServerPool.get_instance().cb_del_server(port)
self.force_update_transfer.add(port) self.force_update_transfer.add(port)
new_servers[port] = (passwd, cfg) new_servers[port] = (passwd, cfg)
else:
self.new_server(port, passwd, cfg)
else:
if ServerPool.get_instance().server_is_run(port) > 0:
if not allow:
logging.info('db stop server at port [%s]' % (port,))
ServerPool.get_instance().cb_del_server(port)
self.force_update_transfer.add(port)
else:
if cfgchange:
logging.info('db stop server at port [%s] reason: config changed: %s' % (port, cfg))
ServerPool.get_instance().cb_del_server(port)
self.force_update_transfer.add(port)
new_servers[port] = (passwd, cfg)
elif allow and ServerPool.get_instance().server_run_status(port) is False: elif allow and port > 0 and port < 65536 and ServerPool.get_instance().server_run_status(port) is False:
self.new_server(port, passwd, cfg) self.new_server(port, passwd, cfg)
for row in last_rows: for row in last_rows:
if row['port'] in cur_servers: if row['port'] in cur_servers:
@ -159,6 +177,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))
for port in mu_servers:
ServerPool.get_instance().update_mu_server(port, None, allow_users)
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]
if port in self.last_get_transfer: del self.last_get_transfer[port] if port in self.last_get_transfer: del self.last_get_transfer[port]

6
mujson_mgr.py

@ -73,8 +73,12 @@ class MuMgr(object):
def userinfo(self, user): def userinfo(self, user):
ret = "" ret = ""
key_list = ['user', 'port', 'method', 'passwd', 'protocol', 'protocol_param', 'obfs', 'obfs_param', 'transfer_enable', 'u', 'd']
for key in sorted(user): for key in sorted(user):
if key in ['enable']: if key not in key_list:
key_list.append(key)
for key in key_list:
if key in ['enable'] or key not in user:
continue continue
ret += '\n' ret += '\n'
if key in ['transfer_enable', 'u', 'd']: if key in ['transfer_enable', 'u', 'd']:

68
server_pool.py

@ -23,6 +23,7 @@
import os import os
import logging import logging
import struct
import time import time
from shadowsocks import shell, eventloop, tcprelay, udprelay, asyncdns, common from shadowsocks import shell, eventloop, tcprelay, udprelay, asyncdns, common
import threading import threading
@ -213,23 +214,62 @@ class ServerPool(object):
return True return True
def update_mu_server(self, port, protocol_param, acl):
port = int(port)
if port in self.tcp_servers_pool:
try:
self.tcp_servers_pool[port].update_users(protocol_param, acl)
except Exception as e:
logging.warn(e)
try:
self.udp_servers_pool[port].update_users(protocol_param, acl)
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)
except Exception as e:
logging.warn(e)
try:
self.udp_ipv6_servers_pool[port].update_users(protocol_param, acl)
except Exception as e:
logging.warn(e)
def get_server_transfer(self, port): def get_server_transfer(self, port):
port = int(port) port = int(port)
uid = struct.pack('<I', port)
ret = [0, 0] ret = [0, 0]
if port in self.tcp_servers_pool: if port in self.tcp_servers_pool:
ret[0] = self.tcp_servers_pool[port].server_transfer_ul ret[0], ret[1] = self.tcp_servers_pool[port].get_ud()
ret[1] = self.tcp_servers_pool[port].server_transfer_dl
if port in self.udp_servers_pool: if port in self.udp_servers_pool:
ret[0] += self.udp_servers_pool[port].server_transfer_ul u, d = self.udp_servers_pool[port].get_ud()
ret[1] += self.udp_servers_pool[port].server_transfer_dl ret[0] += u
ret[1] += d
if port in self.tcp_ipv6_servers_pool: if port in self.tcp_ipv6_servers_pool:
ret[0] += self.tcp_ipv6_servers_pool[port].server_transfer_ul u, d = self.tcp_ipv6_servers_pool[port].get_ud()
ret[1] += self.tcp_ipv6_servers_pool[port].server_transfer_dl ret[0] += u
ret[1] += d
if port in self.udp_ipv6_servers_pool: if port in self.udp_ipv6_servers_pool:
ret[0] += self.udp_ipv6_servers_pool[port].server_transfer_ul u, d = self.udp_ipv6_servers_pool[port].get_ud()
ret[1] += self.udp_ipv6_servers_pool[port].server_transfer_dl ret[0] += u
ret[1] += d
return ret return ret
def get_server_mu_transfer(self, server):
return server.get_users_ud()
def update_mu_transfer(self, user_dict, u, d):
for uid in u:
port = struct.unpack('<I', uid)[0]
if port not in user_dict:
user_dict[port] = [0, 0]
user_dict[port][0] += u[uid]
for uid in d:
port = struct.unpack('<I', uid)[0]
if port not in user_dict:
user_dict[port] = [0, 0]
user_dict[port][1] += d[uid]
def get_servers_transfer(self): def get_servers_transfer(self):
servers = self.tcp_servers_pool.copy() servers = self.tcp_servers_pool.copy()
servers.update(self.tcp_ipv6_servers_pool) servers.update(self.tcp_ipv6_servers_pool)
@ -238,5 +278,17 @@ class ServerPool(object):
ret = {} ret = {}
for port in servers.keys(): for port in servers.keys():
ret[port] = self.get_server_transfer(port) ret[port] = self.get_server_transfer(port)
for port in self.tcp_servers_pool:
u, d = self.get_server_mu_transfer(self.tcp_servers_pool[port])
self.update_mu_transfer(ret, u, d)
for port in self.tcp_ipv6_servers_pool:
u, d = self.get_server_mu_transfer(self.tcp_ipv6_servers_pool[port])
self.update_mu_transfer(ret, u, d)
for port in self.udp_servers_pool:
u, d = self.get_server_mu_transfer(self.udp_servers_pool[port])
self.update_mu_transfer(ret, u, d)
for port in self.udp_ipv6_servers_pool:
u, d = self.get_server_mu_transfer(self.udp_ipv6_servers_pool[port])
self.update_mu_transfer(ret, u, d)
return ret return ret

51
shadowsocks/tcprelay.py

@ -27,6 +27,7 @@ import binascii
import traceback import traceback
import random import random
import platform import platform
import threading
from shadowsocks import encrypt, obfs, eventloop, shell, common, lru_cache from shadowsocks import encrypt, obfs, eventloop, shell, common, lru_cache
from shadowsocks.common import pre_parse_header, parse_header from shadowsocks.common import pre_parse_header, parse_header
@ -900,6 +901,9 @@ class TCPRelayHandler(object):
if self._stage == STAGE_DESTROYED: if self._stage == STAGE_DESTROYED:
logging.debug('ignore handle_event: destroyed') logging.debug('ignore handle_event: destroyed')
return return
if self._user is not None and self._user not in self._server.server_users:
self.destroy()
return
# order is important # order is important
if sock == self._remote_sock or sock == self._remote_sock_v6: if sock == self._remote_sock or sock == self._remote_sock_v6:
if event & eventloop.POLL_ERR: if event & eventloop.POLL_ERR:
@ -1000,6 +1004,8 @@ class TCPRelay(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
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()
@ -1020,16 +1026,7 @@ class TCPRelay(object):
self._listen_port = listen_port self._listen_port = listen_port
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"]:
param = common.to_bytes(config['protocol_param']).split(b'#') self._update_users(None, None)
if len(param) == 2:
user_list = param[1].split(b',')
if user_list:
for user in user_list:
items = user.split(b':')
if len(items) == 2:
uid = struct.pack('<I', int(items[0]))
passwd = items[1]
self.add_user(uid, passwd)
addrs = socket.getaddrinfo(listen_addr, listen_port, 0, addrs = socket.getaddrinfo(listen_addr, listen_port, 0,
socket.SOCK_STREAM, socket.SOL_TCP) socket.SOCK_STREAM, socket.SOL_TCP)
@ -1070,10 +1067,38 @@ class TCPRelay(object):
self.server_connections += val self.server_connections += val
logging.debug('server port %5d connections = %d' % (self._listen_port, self.server_connections,)) logging.debug('server port %5d connections = %d' % (self._listen_port, self.server_connections,))
def get_ud(self):
return (self.server_transfer_ul, self.server_transfer_dl)
def get_users_ud(self):
return (self.server_user_transfer_ul.copy(), self.server_user_transfer_dl.copy())
def _update_users(self, protocol_param, acl):
if protocol_param is None:
protocol_param = self._config['protocol_param']
param = common.to_bytes(protocol_param).split(b'#')
if len(param) == 2:
user_list = param[1].split(b',')
if user_list:
for user in user_list:
items = user.split(b':')
if len(items) == 2:
user_int_id = int(items[0])
uid = struct.pack('<I', user_int_id)
if acl is not None and user_int_id not in acl:
self.del_user(uid)
else:
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 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)
def del_user(self, user, passwd): def del_user(self, user):
if user in self.server_users: if user in self.server_users:
del self.server_users[user] del self.server_users[user]
@ -1189,6 +1214,10 @@ 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):

49
shadowsocks/udprelay.py

@ -70,6 +70,7 @@ import errno
import random import random
import binascii import binascii
import traceback import traceback
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
@ -900,18 +901,11 @@ 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"]:
param = common.to_bytes(config['protocol_param']).split(b'#') self._update_users(None, None)
if len(param) == 2:
user_list = param[1].split(b',')
if user_list:
for user in user_list:
items = user.split(b':')
if len(items) == 2:
uid = struct.pack('<I', int(items[0]))
passwd = items[1]
self.add_user(uid, passwd)
self.protocol_data = obfs.obfs(config['protocol']).init_data() self.protocol_data = obfs.obfs(config['protocol']).init_data()
self._protocol = obfs.obfs(config['protocol']) self._protocol = obfs.obfs(config['protocol'])
@ -972,10 +966,39 @@ class UDPRelay(object):
logging.debug('chosen server: %s:%d', server, server_port) logging.debug('chosen server: %s:%d', server, server_port)
return server, server_port return server, server_port
def get_ud(self):
return (self.server_transfer_ul, self.server_transfer_dl)
def get_users_ud(self):
ret = (self.server_user_transfer_ul.copy(), self.server_user_transfer_dl.copy())
return ret
def _update_users(self, protocol_param, acl):
if protocol_param is None:
protocol_param = self._config['protocol_param']
param = common.to_bytes(protocol_param).split(b'#')
if len(param) == 2:
user_list = param[1].split(b',')
if user_list:
for user in user_list:
items = user.split(b':')
if len(items) == 2:
user_int_id = int(items[0])
uid = struct.pack('<I', user_int_id)
if acl is not None and user_int_id not in acl:
self.del_user(uid)
else:
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 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)
def del_user(self, user, passwd): def del_user(self, user):
if user in self.server_users: if user in self.server_users:
del self.server_users[user] del self.server_users[user]
@ -1434,6 +1457,10 @@ 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…
Cancel
Save