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)
Beispiel #2
0
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'])
Beispiel #3
0
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)
Beispiel #4
0
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'])
Beispiel #5
0
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)
Beispiel #6
0
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"])
Beispiel #7
0
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)
Beispiel #9
0
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)
Beispiel #10
0
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'])
Beispiel #11
0
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()
Beispiel #14
0
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()
Beispiel #16
0
def check_config(config):
    encrypt.try_cipher(config['password'], config['method'])
Beispiel #17
0
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()
Beispiel #18
0
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()
Beispiel #20
0
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'])
Beispiel #21
0
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'])