def main(): # 检查python版本 utils.check_python() # fix py2exe # 应该是专门为py2exe检查当前执行路径用的 if hasattr(sys, "frozen") and sys.frozen in \ ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) # 形参是is_local=True config = utils.get_config(True) # linux系统:执行守护进程 daemon.daemon_exec(config) # 显示当前的ss版本号 utils.print_shadowsocks() # 创建加密器类的实例 encrypt.try_cipher(config['password'], config['method']) try: logging.info("starting local at %s:%d" % (config['local_address'], config['local_port'])) # dns只是tcp上面的一个应用,所以没有自己的bind # 新建dns_resolver dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) # 创建时间循环的类实例 loop = eventloop.EventLoop() # dns请求报文发出去了之后要监测响应报文 dns_resolver.add_to_loop(loop) # client发远程网站地址给proxy,proxy去查找DNS tcp_server.add_to_loop(loop) # 递送tcp数据 udp_server.add_to_loop(loop) # 递送udp数据 # 定义退出信号捕获处理函数 def handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') # 连带关闭socket(因为next = true) tcp_server.close(next_tick = True) udp_server.close(next_tick = True) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler) # 进程终止 def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) # 运行事件循环,思想还是挺高端的 loop.run() # 按下 Ctrl+c 退出 except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1)
def check_config(config, is_local): """ 校验配置文件正确性 :param config: :param is_local: 是否为本地启动(也就是客户端) :return: """ if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return # 本地需要密码 if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) # 服务器,需要密码 端口密码, 管理地址 if not is_local and not config.get('password', None) \ and not config.get('port_password', None) \ and not config.get('manager_address'): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) # 格式转化 if 'local_port' in config: config['local_port'] = int(config['local_port']) if config.get('server_port', None) and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, ' 'like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher, ' 'like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) # 设定底层加密算法 encrypt.try_cipher(config['password'], config['method'])
def main(): global loop utils.check_python() # fix py2exe if hasattr(sys, "frozen") and sys.frozen in \ ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) config = utils.get_config(True) daemon.daemon_exec(config) utils.print_shadowsocks() encrypt.try_cipher(config['password'], config['method']) try: logging.info("starting local at %s:%d" % (config['local_address'], config['local_port'])) dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) tcp_server.add_to_loop(loop) udp_server.add_to_loop(loop) def handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') tcp_server.close(next_tick=True) udp_server.close(next_tick=True) # signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler) def int_handler(signum, _): sys.exit(1) # signal.signal(signal.SIGINT, int_handler) loop.run() try: tcp_server.close(next_tick=True) udp_server.close(next_tick=True) except: pass except (KeyboardInterrupt, IOError, OSError) as e: import traceback traceback.print_exc() logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1)
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) \ and not config.get('port_password', None) \ and not config.get('manager_address'): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if config.get('server_port', None) and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, ' 'like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher, ' 'like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if 'cc_algo' in config and not sys.platform.startswith('linux'): logging.warn('pluggable congestion control algorithm requires linux!') if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) if 'cc_algo' in config and sys.platform.startswith('linux'): logging.info('use %s as socket congestion control algorithm' % config.get('cc_algo', None)) encrypt.try_cipher(config['password'], config['method'])
def main(): utils.check_python() # fix py2exe if hasattr(sys, "frozen") and sys.frozen in \ ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) config = utils.get_config(True) daemon.daemon_exec(config) # # host = config['server']# 测试时候使用 # port = config['server_port'] # s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # s.connect((host, port)) utils.print_shadowsocks() encrypt.try_cipher(config['password'], config['method']) try: logging.info("starting local at %s:%d" % (config['local_address'], config['local_port'])) # dns只是tcp上面的一个应用,所以没有自己的bind dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) loop = eventloop.EventLoop() # dns请求报文发出去了之后要监测响应报文 dns_resolver.add_to_loop(loop) # client发远程网站地址给proxy,proxy去查找DNS tcp_server.add_to_loop(loop) # 递送tcp数据 udp_server.add_to_loop(loop) # 递送udp数据 def handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') tcp_server.close(next_tick=True) udp_server.close(next_tick=True) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler) def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1)
def check_config(config, is_local): if config.get("daemon", None) == "stop": # no need to specify configuration for daemon stop return if is_local and not config.get("password", None): logging.error("password not specified") print_help(is_local) sys.exit(2) if ( not is_local and not config.get("password", None) and not config.get("port_password", None) and not config.get("manager_address") ): logging.error("password or port_password not specified") print_help(is_local) sys.exit(2) if "local_port" in config: config["local_port"] = int(config["local_port"]) if config.get("server_port", None) and type(config["server_port"]) != list: config["server_port"] = int(config["server_port"]) if config.get("local_address", "") in [b"0.0.0.0"]: logging.warn("warning: local set to listen on 0.0.0.0, it's not safe") if config.get("server", "") in ["127.0.0.1", "localhost"]: logging.warn( "warning: server set to listen on %s:%s, are you sure?" % (to_str(config["server"]), config["server_port"]) ) if (config.get("method", "") or "").lower() == "table": logging.warn("warning: table is not safe; please use a safer cipher, " "like AES-256-CFB") if (config.get("method", "") or "").lower() == "rc4": logging.warn("warning: RC4 is not safe; please use a safer cipher, " "like AES-256-CFB") if config.get("timeout", 300) < 100: logging.warn("warning: your timeout %d seems too short" % int(config.get("timeout"))) if config.get("timeout", 300) > 600: logging.warn("warning: your timeout %d seems too long" % int(config.get("timeout"))) if config.get("password") in [b"mypassword"]: logging.error("DON'T USE DEFAULT PASSWORD! Please change it in your " "config.json!") sys.exit(1) if "cc_algo" in config and not sys.platform.startswith("linux"): logging.warn("pluggable congestion control algorithm requires linux!") if config.get("user", None) is not None: if os.name != "posix": logging.error("user can be used only on Unix") sys.exit(1) if "cc_algo" in config and sys.platform.startswith("linux"): logging.info("use %s as socket congestion control algorithm" % config.get("cc_algo", None)) encrypt.try_cipher(config["password"], config["method"])
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local and not config.get('password', None) and not config.get('port_password',None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) and not config.get('port_password', None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher,like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your config.json!') sys.exit(1) if config['log'].has_key('log_enable') is False: config['log'] = {} config['log']['log_enable'] = False if config['log'].has_key('log_path') is False: config['log']['log_path'] = "%s" % os.path.expanduser("~/ss.log") if config['forbid'].has_key('site') is False: config['forbid'] = {} config['forbid']['site'] = [] if config['forbid'].has_key('port') is False: config['forbid']['port'] = [] if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) encrypt.try_cipher(config['password'], config['method'])
def main(): utils.check_python() # fix py2exe if hasattr(sys, "frozen") and sys.frozen in \ ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) config = utils.get_config(True) daemon.daemon_exec(config) utils.print_shadowsocks() encrypt.try_cipher(config['password'], config['method']) try: logging.info("starting local at %s:%d" % (config['local_address'], config['local_port'])) # dns is only a application on TCP, so it does not has its own bind dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) loop = eventloop.EventLoop() # dns请求报文发出去了之后要监测响应报文 # listen the response after dns query is sent dns_resolver.add_to_loop(loop) # The proxy will find the DNS after the client send the address of dest website tcp_server.add_to_loop(loop) # Send tcp data udp_server.add_to_loop(loop) # Send udp data def handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') tcp_server.close(next_tick=True) udp_server.close(next_tick=True) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler) def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1)
def main(): utils.check_python() # fix py2exe if hasattr(sys, "frozen") and sys.frozen in ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) config = utils.get_config(True) daemon.daemon_exec(config) utils.print_shadowsocks() encrypt.try_cipher(config["password"], config["method"]) try: logging.info("starting local at %s:%d" % (config["local_address"], config["local_port"])) dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) tcp_server.add_to_loop(loop) udp_server.add_to_loop(loop) def handler(signum, _): logging.warn("received SIGQUIT, doing graceful shutting down..") tcp_server.close(next_tick=True) udp_server.close(next_tick=True) signal.signal(getattr(signal, "SIGQUIT", signal.SIGTERM), handler) def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config["verbose"]: import traceback traceback.print_exc() os._exit(1)
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) \ and not config.get('port_password', None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and not isinstance(config['server_port'], list): config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if 'block_hostname_list' in config and not isinstance(config['block_hostname_list'], list): config['block_hostname_list'] = [] if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) encrypt.try_cipher(config['password'], config['method'])
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) \ and not config.get('port_password', None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warning('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warning('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if config.get('timeout', 300) < 100: logging.warning('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warning('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) encrypt.try_cipher(config['password'], config['method'])
def check_config(config, is_local): """ 检查配置 :param config: 配置设置 :param is_local: 是否客户端(否则为服务器端) :return: None """ if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return #密码未指定 if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) #密码或端口密码未指定 if not is_local and not config.get('password', None) \ and not config.get('port_password', None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) #端口号转为数值型? if 'local_port' in config: config['local_port'] = int(config['local_port']) #服务器端口单转 if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) #本地监听全零地址警告 if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') #服务器监听提示 if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) #table型不安全提示 if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, ' 'like AES-256-CFB') #RC4算法不安全提示 if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher, ' 'like AES-256-CFB') #延时太短 if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) #延时太长 if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) #使用默认密码提示 if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) #获取用户名失败 if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) encrypt.try_cipher(config['password'], config['method'])
def main(): utils.check_python() config = utils.get_config(False) daemon.daemon_exec(config) utils.print_shadowsocks() if config['port_password']: if config['password']: logging.warn('warning: port_password should not be used with ' 'server_port and password. server_port and password ' 'will be ignored') else: config['port_password'] = {} server_port = config['server_port'] if type(server_port) == list: for a_server_port in server_port: config['port_password'][a_server_port] = config['password'] else: config['port_password'][str(server_port)] = config['password'] encrypt.try_cipher(config['password'], config['method']) tcp_servers = [] udp_servers = [] dns_resolver = asyncdns.DNSResolver() # 一个服务器端可以打开多个端口 # 对于每个端口,都要新建一个对应的处理器 for port, password in config['port_password'].items(): a_config = config.copy() a_config['server_port'] = int(port) a_config['password'] = password logging.info("starting server at %s:%d" % (a_config['server'], int(port))) tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False)) udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False)) def run_server(): def child_handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') list(map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers)) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), child_handler) def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) try: loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) # 这条语句有点屌 list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers)) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1) if int(config['workers']) > 1: if os.name == 'posix': children = [] is_child = False for i in range(0, int(config['workers'])): r = os.fork() if r == 0: logging.info('worker started') is_child = True run_server() break else: children.append(r) if not is_child: def handler(signum, _): for pid in children: try: os.kill(pid, signum) os.waitpid(pid, 0) except OSError: # child may already exited pass sys.exit() signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGINT, handler) # master for a_tcp_server in tcp_servers: a_tcp_server.close() for a_udp_server in udp_servers: a_udp_server.close() dns_resolver.close() for child in children: os.waitpid(child, 0) else: logging.warn('worker is only available on Unix/Linux') run_server() else: run_server()
def main(): # 检查python版本 utils.check_python() # fix py2exe # 应该是专门为py2exe检查当前执行路径用的 if hasattr(sys, "frozen") and sys.frozen in \ ("windows_exe", "console_exe"): p = os.path.dirname(os.path.abspath(sys.executable)) os.chdir(p) # 形参是is_local=True config = utils.get_config(True) # linux系统:执行守护进程 daemon.daemon_exec(config) # 显示当前的ss版本号 utils.print_shadowsocks() # 创建加密器类的实例 encrypt.try_cipher(config['password'], config['method']) try: logging.info("starting local at %s:%d" % (config['local_address'], config['local_port'])) # dns只是tcp上面的一个应用,所以没有自己的bind # 新建dns_resolver dns_resolver = asyncdns.DNSResolver() tcp_server = tcprelay.TCPRelay(config, dns_resolver, True) udp_server = udprelay.UDPRelay(config, dns_resolver, True) # 创建时间循环的类实例 loop = eventloop.EventLoop() # dns请求报文发出去了之后要监测响应报文 dns_resolver.add_to_loop(loop) # client发远程网站地址给proxy,proxy去查找DNS tcp_server.add_to_loop(loop) # 递送tcp数据 udp_server.add_to_loop(loop) # 递送udp数据 # 定义退出信号捕获处理函数 def handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') # 连带关闭socket(因为next = true) tcp_server.close(next_tick=True) udp_server.close(next_tick=True) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), handler) # 进程终止 def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) # 运行事件循环,思想还是挺高端的 loop.run() # 按下 Ctrl+c 退出 except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1)
def main(): utils.check_python() config = utils.get_config(False) utils.print_shadowsocks() if config['port_password']: if config['password']: logging.warn('warning: port_password should not be used with ' 'server_port and password. server_port and password ' 'will be ignored') else: config['port_password'] = {} server_port = config['server_port'] if type(server_port) == list: for a_server_port in server_port: config['port_password'][a_server_port] = config['password'] else: config['port_password'][str(server_port)] = config['password'] encrypt.try_cipher(config['password'], config['method']) tcp_servers = [] udp_servers = [] dns_resolver = asyncdns.DNSResolver() for port, password in config['port_password'].items(): a_config = config.copy() a_config['server_port'] = int(port) a_config['password'] = password logging.info("starting server at %s:%d" % (a_config['server'], int(port))) tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False)) udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False)) def run_server(): def child_handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') list( map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers)) signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), child_handler) try: loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers)) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1) if int(config['workers']) > 1: if os.name == 'posix': children = [] is_child = False for i in range(0, int(config['workers'])): r = os.fork() if r == 0: logging.info('worker started') is_child = True run_server() break else: children.append(r) if not is_child: def handler(signum, _): for pid in children: try: os.kill(pid, signum) except OSError: # child may already exited pass sys.exit() signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGQUIT, handler) # master for a_tcp_server in tcp_servers: a_tcp_server.close() for a_udp_server in udp_servers: a_udp_server.close() dns_resolver.close() for child in children: os.waitpid(child, 0) else: logging.warn('worker is only available on Unix/Linux') run_server() else: run_server()
def check_config(config): encrypt.try_cipher(config['password'], config['method'])
def main(): utils.check_python() # is_local=false config = utils.get_config(False) daemon.daemon_exec(config) utils.print_shadowsocks() # 支持多客户端 if config['port_password']: if config['password']: logging.warn('warning: port_password should not be used with ' 'server_port and password. server_port and password ' 'will be ignored') else: config['port_password'] = {} server_port = config['server_port'] # 若发现有多用户配置:采用‘端口->密码’的映射方式。 if type(server_port) == list: for a_server_port in server_port: config['port_password'][a_server_port] = config['password'] else: config['port_password'][str(server_port)] = config['password'] # Create an instance of the cipher class encrypt.try_cipher(config['password'], config['method']) tcp_servers = [] udp_servers = [] dns_resolver = asyncdns.DNSResolver() # 一个服务器端可以打开多个端口 # 对于每个端口,都要新建一个对应的处理器 for port, password in config['port_password'].items(): a_config = config.copy() a_config['server_port'] = int(port) a_config['password'] = password logging.info("starting server at %s:%d" % (a_config['server'], int(port))) # 逐一加到tcp、udp列表 tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False)) udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False)) def run_server(): # 收到退出信号的处理函数,关闭所有socket释放资源。 def child_handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') # 关闭所有的socket,一句话搞定,好厉害,跪拜ing # map(function, sequence[, sequence, ...]) -> list # Return a list of the results of applying the function to the items of the argument sequence(s). list( map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers)) # 收到退出信号,调用child_handler进行自杀。 signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), child_handler) # 收到退出信号,调用int_handler进行自杀。 def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) try: loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) # 把所有的监听端口添加到时间循环中,一句话搞定,好厉害,跪拜ing list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers)) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1) # Shadowsocks supports spawning child processes like nginx. # You can use --workers to specify how many workers to use. # This argument is only supported on Unix and ssserver. # Currently UDP relay does not work well on multiple workers. # 支持像nginx多进程,可以在config中指定worker的数量。仅在linux下生效。 # 目前的bug:worker设为大于1时,udp转发有可能工作不正常 if int(config['workers']) > 1: if os.name == 'posix': children = [] is_child = False for i in range(0, int(config['workers'])): r = os.fork() if r == 0: logging.info('worker started') is_child = True run_server() break else: children.append(r) if not is_child: def handler(signum, _): for pid in children: try: os.kill(pid, signum) os.waitpid(pid, 0) except OSError: # child may already exited pass sys.exit() signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGINT, handler) # master for a_tcp_server in tcp_servers: a_tcp_server.close() for a_udp_server in udp_servers: a_udp_server.close() dns_resolver.close() for child in children: os.waitpid(child, 0) else: logging.warn('worker is only available on Unix/Linux') run_server() else: run_server()
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local: if config.get('server', None) is None: logging.error('server addr not specified') print_local_help() sys.exit(2) else: config['server'] = to_str(config['server']) if config.get('tunnel_remote', None) is None: logging.error('tunnel_remote addr not specified') print_local_help() sys.exit(2) else: config['tunnel_remote'] = to_str(config['tunnel_remote']) else: config['server'] = to_str(config.get('server', '0.0.0.0')) try: config['forbidden_ip'] = \ IPNetwork(config.get('forbidden_ip', '127.0.0.0/8,::1/128')) except Exception as e: logging.error(e) sys.exit(2) if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) \ and not config.get('port_password', None) \ and not config.get('manager_address'): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if 'tunnel_remote_port' in config: config['tunnel_remote_port'] = \ int(config['tunnel_remote_port']) if 'tunnel_port' in config: config['tunnel_port'] = int(config['tunnel_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, ' 'like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher, ' 'like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) if config.get('dns_server', None) is not None: logging.info('Specified DNS server: %s' % config['dns_server']) encrypt.try_cipher(config['password'], config['method'])
def main(): utils.check_python() # is_local=false config = utils.get_config(False) daemon.daemon_exec(config) utils.print_shadowsocks() # 支持多客户端 if config['port_password']: if config['password']: logging.warn('warning: port_password should not be used with ' 'server_port and password. server_port and password ' 'will be ignored') else: config['port_password'] = {} server_port = config['server_port'] # 若发现有多用户配置:采用‘端口->密码’的映射方式。 if type(server_port) == list: for a_server_port in server_port: config['port_password'][a_server_port] = config['password'] else: config['port_password'][str(server_port)] = config['password'] # Create an instance of the cipher class encrypt.try_cipher(config['password'], config['method']) tcp_servers = [] udp_servers = [] dns_resolver = asyncdns.DNSResolver() # 一个服务器端可以打开多个端口 # 对于每个端口,都要新建一个对应的处理器 for port, password in config['port_password'].items(): a_config = config.copy() a_config['server_port'] = int(port) a_config['password'] = password logging.info("starting server at %s:%d" % (a_config['server'], int(port))) # 逐一加到tcp、udp列表 tcp_servers.append(tcprelay.TCPRelay(a_config, dns_resolver, False)) udp_servers.append(udprelay.UDPRelay(a_config, dns_resolver, False)) def run_server(): # 收到退出信号的处理函数,关闭所有socket释放资源。 def child_handler(signum, _): logging.warn('received SIGQUIT, doing graceful shutting down..') # 关闭所有的socket,一句话搞定,好厉害,跪拜ing # map(function, sequence[, sequence, ...]) -> list # Return a list of the results of applying the function to the items of the argument sequence(s). list(map(lambda s: s.close(next_tick = True), tcp_servers + udp_servers)) # 收到退出信号,调用child_handler进行自杀。 signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM), child_handler) # 收到退出信号,调用int_handler进行自杀。 def int_handler(signum, _): sys.exit(1) signal.signal(signal.SIGINT, int_handler) try: loop = eventloop.EventLoop() dns_resolver.add_to_loop(loop) # 把所有的监听端口添加到时间循环中,一句话搞定,好厉害,跪拜ing list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers)) loop.run() except (KeyboardInterrupt, IOError, OSError) as e: logging.error(e) if config['verbose']: import traceback traceback.print_exc() os._exit(1) # Shadowsocks supports spawning child processes like nginx. # You can use --workers to specify how many workers to use. # This argument is only supported on Unix and ssserver. # Currently UDP relay does not work well on multiple workers. # 支持像nginx多进程,可以在config中指定worker的数量。仅在linux下生效。 # 目前的bug:worker设为大于1时,udp转发有可能工作不正常 if int(config['workers']) > 1: if os.name == 'posix': children = [] is_child = False for i in range(0, int(config['workers'])): r = os.fork() if r == 0: logging.info('worker started') is_child = True run_server() break else: children.append(r) if not is_child: def handler(signum, _): for pid in children: try: os.kill(pid, signum) os.waitpid(pid, 0) except OSError: # child may already exited pass sys.exit() signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGINT, handler) # master for a_tcp_server in tcp_servers: a_tcp_server.close() for a_udp_server in udp_servers: a_udp_server.close() dns_resolver.close() for child in children: os.waitpid(child, 0) else: logging.warn('worker is only available on Unix/Linux') run_server() else: run_server()
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local: if config.get('server', None) is None: logging.error('server addr not specified') print_local_help() sys.exit(2) else: config['server'] = to_str(config['server']) if config.get('tunnel_remote', None) is None: logging.error('tunnel_remote addr not specified') print_local_help() sys.exit(2) else: config['tunnel_remote'] = to_str(config['tunnel_remote']) else: config['server'] = to_str(config.get('server', '0.0.0.0')) try: config['forbidden_ip'] = \ IPNetwork(config.get('forbidden_ip', '127.0.0.0/8,::1/128')) except Exception as e: logging.error(e) sys.exit(2) if is_local and not config.get('password', None): logging.error('password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) \ and not config.get('port_password', None) \ and not config.get('manager_address'): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if 'tunnel_remote_port' in config: config['tunnel_remote_port'] = \ int(config['tunnel_remote_port']) if 'tunnel_port' in config: config['tunnel_port'] = int(config['tunnel_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, ' 'like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher, ' 'like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your ' 'config.json!') sys.exit(1) if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) if config.get('dns_server', None) is not None: logging.info('Specified DNS server: %s' % config['dns_server']) encrypt.try_cipher(config['password'], config['method'])
def check_config(config, is_local): if config.get('daemon', None) == 'stop': # no need to specify configuration for daemon stop return if is_local and not config.get('password', None) and not config.get('port_password',None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if not is_local and not config.get('password', None) and not config.get('port_password', None): logging.error('password or port_password not specified') print_help(is_local) sys.exit(2) if config.has_key('port_password') and len(config['port_password']) != 0: config['server_port'] = int(random.choice(config['port_password'].items())[0]) config['password'] = common.to_str(config['port_password']["%s" % config['server_port']]) else: if config.has_key("password") and config.has_key("server_port"): if type(config['server_port']) == list and len(config['server_port']) != 0: config['server_port'] = random.choice(config.get('server_port', 1990)) elif type(config['server_port']) == str and config['server_port'] != "": config['server_port'] == int(common.to_str(config.get('server_port',1990))) elif type(config['server_port']) == int and config['server_port'] <= 65530: config['server_port'] = config['server_port'] else: print("Sorry..config error please check config.json again") sys.exit(1) if config['password'] == "": print("Sorry..config error please check config.json again [password is empty]") sys.exit(1) else: print("Sorry..config error please check config.json again [At lease give me password and server_port]") sys.exit(1) if 'local_port' in config: config['local_port'] = int(config['local_port']) if 'server_port' in config and type(config['server_port']) != list: config['server_port'] = int(config['server_port']) if config.get('local_address', '') in [b'0.0.0.0']: logging.warn('warning: local set to listen on 0.0.0.0, it\'s not safe') if config.get('server', '') in ['127.0.0.1', 'localhost']: logging.warn('warning: server set to listen on %s:%s, are you sure?' % (to_str(config['server']), config['server_port'])) if (config.get('method', '') or '').lower() == 'table': logging.warn('warning: table is not safe; please use a safer cipher, like AES-256-CFB') if (config.get('method', '') or '').lower() == 'rc4': logging.warn('warning: RC4 is not safe; please use a safer cipher,like AES-256-CFB') if config.get('timeout', 300) < 100: logging.warn('warning: your timeout %d seems too short' % int(config.get('timeout'))) if config.get('timeout', 300) > 600: logging.warn('warning: your timeout %d seems too long' % int(config.get('timeout'))) if config.get('password') in [b'mypassword']: logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your config.json!') sys.exit(1) if config['log'].has_key('log_enable') is False: config['log'] = {} config['log']['log_enable'] = False if config['log'].has_key('log_path') is False: config['log']['log_path'] = "%s" % os.path.expanduser("~/ss.log") if config['forbid'].has_key('site') is False: config['forbid'] = {} config['forbid']['site'] = [] if config['forbid'].has_key('port') is False: config['forbid']['port'] = [] if config.get('user', None) is not None: if os.name != 'posix': logging.error('user can be used only on Unix') sys.exit(1) encrypt.try_cipher(config['password'], config['method'])