Пример #1
0
 def handle_event(self, sock, fd, event):
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             logging.error('UDP server_socket err')
         try:
             self._handle_server()
         except Exception as e:
             shell.print_exception(e)
             if self._config['verbose']:
                 traceback.print_exc()
     elif sock and (fd in self._sockets):
         if event & eventloop.POLL_ERR:
             logging.error('UDP client_socket err')
         try:
             self._handle_client(sock)
         except Exception as e:
             shell.print_exception(e)
             if self._config['verbose']:
                 traceback.print_exc()
     else:
         if sock:
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
Пример #2
0
def write_pid_file(pid_file, pid):
    import fcntl
    import stat

    try:
        fd = os.open(pid_file, os.O_RDWR | os.O_CREAT,
                     stat.S_IRUSR | stat.S_IWUSR)
    except OSError as e:
        shell.print_exception(e)
        return -1
    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
    assert flags != -1
    flags |= fcntl.FD_CLOEXEC
    r = fcntl.fcntl(fd, fcntl.F_SETFD, flags)
    assert r != -1
    # There is no platform independent way to implement fcntl(fd, F_SETLK, &fl)
    # via fcntl.fcntl. So use lockf instead
    try:
        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB, 0, 0, os.SEEK_SET)
    except IOError:
        r = os.read(fd, 32)
        if r:
            logging.error('already started at pid %s' % common.to_str(r))
        else:
            logging.error('already started')
        os.close(fd)
        return -1
    os.ftruncate(fd, 0)
    os.write(fd, common.to_bytes(str(pid)))
    return 0
def write_pid_file(pid_file, pid):
    import fcntl
    import stat

    try:
        fd = os.open(pid_file, os.O_RDWR | os.O_CREAT,
                     stat.S_IRUSR | stat.S_IWUSR)
    except OSError as e:
        shell.print_exception(e)
        return -1
    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
    assert flags != -1
    flags |= fcntl.FD_CLOEXEC
    r = fcntl.fcntl(fd, fcntl.F_SETFD, flags)
    assert r != -1
    # There is no platform independent way to implement fcntl(fd, F_SETLK, &fl)
    # via fcntl.fcntl. So use lockf instead
    try:
        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB, 0, 0, os.SEEK_SET)
    except IOError:
        r = os.read(fd, 32)
        if r:
            logging.error('already started at pid %s' % common.to_str(r))
        else:
            logging.error('already started')
        os.close(fd)
        return -1
    os.ftruncate(fd, 0)
    os.write(fd, common.to_bytes(str(pid)))
    return 0
Пример #4
0
    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))

            daemon.set_user(config.get('user', None))
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)
Пример #5
0
 def handle_event(self, sock, fd, event):
     # handle events and dispatch to handlers
     if sock:
         logging.log(shell.VERBOSE_LEVEL, 'fd %d %s', fd,
                     eventloop.EVENT_NAMES.get(event, event))
     if sock == self._server_socket:
         # 服务器socket接收连接
         if event & eventloop.POLL_ERR:
             # TODO
             raise Exception('server_socket error')
         try:
             logging.debug('accept')
             conn = self._server_socket.accept()
             TCPRelayHandler(self, self._fd_to_handlers, self._eventloop,
                             conn[0], self._config, self._dns_resolver,
                             self._is_local)
         except (OSError, IOError) as e:
             error_no = eventloop.errno_from_exception(e)
             if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                             errno.EWOULDBLOCK):
                 return
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
     else:
         # 其他socket,可能是与客户端的,也可能是web的(相对ssserver)
         if sock:
             # 回调之
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
 def run(self):
     events = []
     while self._ref_handlers:
         try:
             events = self.poll(1)
         except (OSError, IOError) as e:
             if errno_from_exception(e) in (errno.EPIPE, errno.EINTR):
                 # EPIPE: Happens when the client closes the connection
                 # EINTR: Happens when received a signal
                 # handles them as soon as possible
                 logging.debug('poll:%s', e)
             else:
                 logging.error('poll:%s', e)
                 import traceback
                 traceback.print_exc()
                 continue
         self._iterating = True
         for handler in self._handlers:
             # TODO when there are a lot of handlers
             try:
                 handler(events)
             except (OSError, IOError) as e:
                 shell.print_exception(e)
         if self._handlers_to_remove:
             for handler in self._handlers_to_remove:
                 self._handlers.remove(handler)
             self._handlers_to_remove = []
         self._iterating = False
Пример #7
0
 def run(self):
     events = []
     while not self._stopping:
         asap = False
         try:
             events = self.poll(TIMEOUT_PRECISION)
         except (OSError, IOError) as e:
             if errno_from_exception(e) in (errno.EPIPE, errno.EINTR):
                 # EPIPE: Happens when the client closes the connection
                 # EINTR: Happens when received a signal
                 # handles them as soon as possible
                 asap = True
                 logging.debug('poll:%s', e)
             else:
                 logging.error('poll:%s', e)
                 import traceback
                 traceback.print_exc()
                 continue
         # 开始回调
         for sock, fd, event in events:
             handler = self._fdmap.get(fd, None)
             if handler is not None:
                 handler = handler[1]
                 try:
                     handler.handle_event(sock, fd, event)
                 except (OSError, IOError) as e:
                     shell.print_exception(e)
         # 回调定时任务
         now = time.time()
         if asap or now - self._last_time >= TIMEOUT_PRECISION:
             for callback in self._periodic_callbacks:
                 callback()
             self._last_time = now
 def run(self):
     events = []
     while self._ref_handlers:
         try:
             events = self.poll(1)
         except (OSError, IOError) as e:
             if errno_from_exception(e) in (errno.EPIPE, errno.EINTR):
                 # EPIPE: Happens when the client closes the connection
                 # EINTR: Happens when received a signal
                 # handles them as soon as possible
                 logging.debug('poll:%s', e)
             else:
                 logging.error('poll:%s', e)
                 import traceback
                 traceback.print_exc()
                 continue
         self._iterating = True
         for handler in self._handlers:
             # TODO when there are a lot of handlers
             try:
                 handler(events)
             except (OSError, IOError) as e:
                 shell.print_exception(e)
         if self._handlers_to_remove:
             for handler in self._handlers_to_remove:
                 self._handlers.remove(handler)
             self._handlers_to_remove = []
         self._iterating = False
Пример #9
0
    def _on_remote_read(self):
        # handle all remote read events
        data = None
        try:
            data = self._remote_sock.recv(BUF_SIZE)

        except (OSError, IOError) as e:
            if eventloop.errno_from_exception(e) in \
                    (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
                return
        if not data:
            self.destroy()
            return
        self._update_activity(len(data))
        # 注意,往local发送的数据不经过ota
        if self._is_local:
            # 服务器的数据经过加密,客户端进行解密
            data = self._encryptor.decrypt(data)
        else:
            # 收到web的数据,服务器加密之后才能发给客户端
            data = self._encryptor.encrypt(data)
        try:
            # 立即就写?写失败也不放到data_write_to_local吗
            self._write_to_sock(data, self._local_sock)
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            # TODO use logging when debug completed
            self.destroy()
 def _on_remote_read(self):
     # handle all remote read events
     self._update_activity()
     data = None
     try:
         data = self._remote_sock.recv(BUF_SIZE)
     except (OSError, IOError) as e:
         if eventloop.errno_from_exception(e) in \
                 (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
             return
     if not data:
         self.destroy()
         return
     self._server.server_transfer_dl += len(data)
     if self._is_local:
         data = self._encryptor.decrypt(data)
     else:
         data = self._encryptor.encrypt(data)
     try:
         self._write_to_sock(data, self._local_sock)
     except Exception as e:
         shell.print_exception(e)
         if self._config['verbose']:
             traceback.print_exc()
         # TODO use logging when debug completed
         self.destroy()
 def _on_remote_read(self):
     # handle all remote read events
     self._update_activity()
     data = None
     try:
         data = self._remote_sock.recv(BUF_SIZE)
     except (OSError, IOError) as e:
         if eventloop.errno_from_exception(e) in \
                 (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
             return
     if not data:
         self.destroy()
         return
     self._server.server_transfer_dl += len(data)
     if self._is_local:
         data = self._encryptor.decrypt(data)
     else:
         data = self._encryptor.encrypt(data)
     try:
         self._write_to_sock(data, self._local_sock)
     except Exception as e:
         shell.print_exception(e)
         if self._config['verbose']:
             traceback.print_exc()
         # TODO use logging when debug completed
         self.destroy()
Пример #12
0
 def _handle_stage_connecting(self, data):
     # 客户端读取web数据进行ota生成,服务器获取客户端数据,进行ota校验
     # upstream数据才进行ota,downstream不进行ota
     # 收到local_sock数据,放到data_to_write_to_remote
     if self._is_local:
         # 客户端接收到浏览器的数据要加密
         if self._ota_enable:
             data = self._ota_chunk_data_gen(data)
         data = self._encryptor.encrypt(data)
         self._data_to_write_to_remote.append(data)
     else:
         # 服务器接收客户端的数据,在数据读取的时候已经解密
         if self._ota_enable:
             self._ota_chunk_data(data,
                                  self._data_to_write_to_remote.append)
         else:
             self._data_to_write_to_remote.append(data)
     if self._is_local and not self._fastopen_connected and \
             self._config['fast_open']:
         # for sslocal and fastopen, we basically wait for data and use
         # sendto to connect
         try:
             # only connect once
             self._fastopen_connected = True
             remote_sock = \
                 self._create_remote_socket(self._chosen_server[0],
                                            self._chosen_server[1])
             self._loop.add(remote_sock, eventloop.POLL_ERR, self._server)
             data = b''.join(self._data_to_write_to_remote)
             l = len(data)
             # tcp 直接sendto
             s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
             # 处理没法送完的包
             if s < l:
                 data = data[s:]
                 self._data_to_write_to_remote = [data]
             else:
                 self._data_to_write_to_remote = []
             self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
         except (OSError, IOError) as e:
             if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
                 # in this case data is not sent at all
                 self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
             elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
                 logging.error('fast open not supported on this OS')
                 self._config['fast_open'] = False
                 self.destroy()
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
                 self.destroy()
Пример #13
0
 def _send_control_data(self, data):
     if self._control_client_addr:
         try:
             self._control_socket.sendto(data, self._control_client_addr)
         except (socket.error, OSError, IOError) as e:
             error_no = eventloop.errno_from_exception(e)
             if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                             errno.EWOULDBLOCK):
                 return
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
Пример #14
0
    def _handle_dns_resolved(self, result, error):
        # 解析成功,remote_sock连接远端,开始收发数据
        # 状态变为STAGE_CONNECTING
        if error:
            self._log_error(error)
            self.destroy()
            return
        if result and result[1]:
            ip = result[1]
            try:
                self._stage = STAGE_CONNECTING
                remote_addr = ip
                if self._is_local:
                    # sslocal得到ssserver的端口
                    remote_port = self._chosen_server[1]
                else:
                    # 服务器得到远程端要连接的端口
                    remote_port = self._remote_address[1]

                if self._is_local and self._config['fast_open']:
                    # for fastopen:
                    # wait for more data arrive and send them in one SYN
                    self._stage = STAGE_CONNECTING
                    # we don't have to wait for remote since it's not
                    # created
                    self._update_stream(STREAM_UP, WAIT_STATUS_READING)
                    # TODO when there is already data in this packet
                else:
                    # else do connect
                    # 服务器创建连接远程的socket
                    remote_sock = self._create_remote_socket(
                        remote_addr, remote_port)
                    try:
                        remote_sock.connect((remote_addr, remote_port))
                    except (OSError, IOError) as e:
                        if eventloop.errno_from_exception(e) == \
                                errno.EINPROGRESS:
                            pass
                    self._loop.add(remote_sock,
                                   eventloop.POLL_ERR | eventloop.POLL_OUT,
                                   self._server)
                    self._stage = STAGE_CONNECTING
                    self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
                    self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
                return
            except Exception as e:
                shell.print_exception(e)
                if self._config['verbose']:
                    traceback.print_exc()
        self.destroy()
Пример #15
0
def main():
    shell.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 = shell.get_config(True)

    if not config.get('dns_ipv6', False):
        asyncdns.IPV6_CONNECTION_SUPPORT = False

    daemon.daemon_exec(config)
    logging.info(
        "local start with protocol[%s] password [%s] method [%s] obfs [%s] obfs_param [%s]"
        % (config['protocol'], config['password'], config['method'],
           config['obfs'], config['obfs_param']))

    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)

        daemon.set_user(config.get('user', None))
        loop.run()
    except Exception as e:
        shell.print_exception(e)
        sys.exit(1)
    def _handle_dns_resolved(self, result, error):
        if error:
            self._log_error(error)
            self.destroy()
            return
        if result:
            ip = result[1]
            if ip:

                try:
                    self._stage = STAGE_CONNECTING
                    remote_addr = ip
                    if self._is_local:
                        remote_port = self._chosen_server[1]
                    else:
                        remote_port = self._remote_address[1]

                    if self._is_local and self._config['fast_open']:
                        # for fastopen:
                        # wait for more data to arrive and send them in one SYN
                        self._stage = STAGE_CONNECTING
                        # we don't have to wait for remote since it's not
                        # created
                        self._update_stream(STREAM_UP, WAIT_STATUS_READING)
                        # TODO when there is already data in this packet
                    else:
                        # else do connect
                        remote_sock = self._create_remote_socket(remote_addr,
                                                                 remote_port)
                        try:
                            remote_sock.connect((remote_addr, remote_port))
                        except (OSError, IOError) as e:
                            if eventloop.errno_from_exception(e) == \
                                    errno.EINPROGRESS:
                                pass
                        self._loop.add(remote_sock,
                                       eventloop.POLL_ERR | eventloop.POLL_OUT)
                        self._stage = STAGE_CONNECTING
                        self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
                        self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
                    return
                except Exception as e:
                    shell.print_exception(e)
                    if self._config['verbose']:
                        traceback.print_exc()
        self.destroy()
    def _handle_events(self, events):
        # handle events and dispatch to handlers
        for sock, fd, event in events:
            if sock:
                logging.log(shell.VERBOSE_LEVEL, 'fd %d %s', fd,
                            eventloop.EVENT_NAMES.get(event, event))
            if sock == self._server_socket:
                if event & eventloop.POLL_ERR:
                    # TODO
                    raise Exception('server_socket error')
                try:
                    logging.debug('accept')
                    conn = self._server_socket.accept()
                    TCPRelayHandler(self, self._fd_to_handlers,
                                    self._eventloop, conn[0], self._config,
                                    self._dns_resolver, self._is_local)
                except (OSError, IOError) as e:
                    error_no = eventloop.errno_from_exception(e)
                    if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                                    errno.EWOULDBLOCK):
                        continue
                    else:
                        shell.print_exception(e)
                        if self._config['verbose']:
                            traceback.print_exc()
            else:
                if sock:
                    handler = self._fd_to_handlers.get(fd, None)
                    if handler:
                        handler.handle_event(sock, event)
                else:
                    logging.warn('poll removed fd')

        now = time.time()
        if now - self._last_time > TIMEOUT_PRECISION:
            self._sweep_timeout()
            self._last_time = now
        if self._closed:
            if self._server_socket:
                self._eventloop.remove(self._server_socket)
                self._server_socket.close()
                self._server_socket = None
                logging.info('closed listen port %d', self._listen_port)
            if not self._fd_to_handlers:
                self._eventloop.remove_handler(self._handle_events)
    def _handle_events(self, events):
        # handle events and dispatch to handlers
        for sock, fd, event in events:
            if sock:
                logging.log(shell.VERBOSE_LEVEL, 'fd %d %s', fd,
                            eventloop.EVENT_NAMES.get(event, event))
            if sock == self._server_socket:
                if event & eventloop.POLL_ERR:
                    # TODO
                    raise Exception('server_socket error')
                try:
                    logging.debug('accept')
                    conn = self._server_socket.accept()
                    TCPRelayHandler(self, self._fd_to_handlers,
                                    self._eventloop, conn[0], self._config,
                                    self._dns_resolver, self._is_local)
                except (OSError, IOError) as e:
                    error_no = eventloop.errno_from_exception(e)
                    if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                                    errno.EWOULDBLOCK):
                        continue
                    else:
                        shell.print_exception(e)
                        if self._config['verbose']:
                            traceback.print_exc()
            else:
                if sock:
                    handler = self._fd_to_handlers.get(fd, None)
                    if handler:
                        handler.handle_event(sock, event)
                else:
                    logging.warn('poll removed fd')

        now = time.time()
        if now - self._last_time > TIMEOUT_PRECISION:
            self._sweep_timeout()
            self._last_time = now
        if self._closed:
            if self._server_socket:
                self._eventloop.remove(self._server_socket)
                self._server_socket.close()
                self._server_socket = None
                logging.info('closed listen port %d', self._listen_port)
            if not self._fd_to_handlers:
Пример #19
0
    def _handle_stage_connecting(self, data):
        if not self._is_local:
            if self._ota_enable_session:
                self._ota_chunk_data(data,
                                     self._data_to_write_to_remote.append)
            else:
                self._data_to_write_to_remote.append(data)
            return
        if self._ota_enable_session:
            data = self._ota_chunk_data_gen(data)
        data = self._cryptor.encrypt(data)
        self._data_to_write_to_remote.append(data)

        if self._config['fast_open'] and not self._fastopen_connected:
            # for sslocal and fastopen, we basically wait for data and use
            # sendto to connect
            try:
                # only connect once
                self._fastopen_connected = True
                remote_sock = \
                    self._create_remote_socket(self._chosen_server[0],
                                               self._chosen_server[1])
                self._loop.add(remote_sock, eventloop.POLL_ERR, self._server)
                data = b''.join(self._data_to_write_to_remote)
                l = len(data)
                s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
                if s < l:
                    data = data[s:]
                    self._data_to_write_to_remote = [data]
                else:
                    self._data_to_write_to_remote = []
                self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
            except (OSError, IOError) as e:
                if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
                    # in this case data is not sent at all
                    self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
                elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
                    logging.error('fast open not supported on this OS')
                    self._config['fast_open'] = False
                    self.destroy()
                else:
                    shell.print_exception(e)
                    if self._config['verbose']:
                        traceback.print_exc()
                    self.destroy()
def daemon_stop(pid_file):
    import errno
    try:
        with open(pid_file) as f:
            buf = f.read()
            pid = common.to_str(buf)
            if not buf:
                logging.error('not running')
    except IOError as e:
        shell.print_exception(e)
        if e.errno == errno.ENOENT:
            # always exit 0 if we are sure daemon is not running
            logging.error('not running')
            return
        sys.exit(1)
    pid = int(pid)
    if pid > 0:
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as e:
            if e.errno == errno.ESRCH:
                logging.error('not running')
                # always exit 0 if we are sure daemon is not running
                return
            shell.print_exception(e)
            sys.exit(1)
    else:
        logging.error('pid is not positive: %d', pid)

    # sleep for maximum 10s
    for i in range(0, 200):
        try:
            # query for the pid
            os.kill(pid, 0)
        except OSError as e:
            if e.errno == errno.ESRCH:
                break
        time.sleep(0.05)
    else:
        logging.error('timed out when stopping pid %d', pid)
        sys.exit(1)
    print('stopped')
    os.unlink(pid_file)
Пример #21
0
def daemon_stop(pid_file):
    import errno
    try:
        with open(pid_file) as f:
            buf = f.read()
            pid = common.to_str(buf)
            if not buf:
                logging.error('not running')
    except IOError as e:
        shell.print_exception(e)
        if e.errno == errno.ENOENT:
            # always exit 0 if we are sure daemon is not running
            logging.error('not running')
            return
        sys.exit(1)
    pid = int(pid)
    if pid > 0:
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as e:
            if e.errno == errno.ESRCH:
                logging.error('not running')
                # always exit 0 if we are sure daemon is not running
                return
            shell.print_exception(e)
            sys.exit(1)
    else:
        logging.error('pid is not positive: %d', pid)

    # sleep for maximum 10s
    for i in range(0, 200):
        try:
            # query for the pid
            os.kill(pid, 0)
        except OSError as e:
            if e.errno == errno.ESRCH:
                break
        time.sleep(0.05)
    else:
        logging.error('timed out when stopping pid %d', pid)
        sys.exit(1)
    print('stopped')
    os.unlink(pid_file)
Пример #22
0
 def write_to_server_socket(self, data, addr):
     uncomplete = False
     retry = 0
     try:
         self._server_socket.sendto(data, addr)
         data = None
         while self._data_to_write_to_server_socket:
             data_buf = self._data_to_write_to_server_socket[0]
             retry = data_buf[1] + 1
             del self._data_to_write_to_server_socket[0]
             data, addr = data_buf[0]
             self._server_socket.sendto(data, addr)
     except (OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         uncomplete = True
         if error_no in (errno.EWOULDBLOCK, ):
             pass
         else:
             shell.print_exception(e)
             return False
Пример #23
0
 def _write_to_sock(self, data, sock):
     # write data to sock
     # if only some of the data are written, put remaining in the buffer
     # and update the stream to wait for writing
     if not data or not sock:
         return False
     uncomplete = False
     try:
         l = len(data)
         s = sock.send(data)
         if s < l:
             data = data[s:]
             uncomplete = True
     except (OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                         errno.EWOULDBLOCK):
             uncomplete = True
         else:
             shell.print_exception(e)
             self.destroy()
             return False
     if uncomplete:
         # 还有数据未写完,继续写
         if sock == self._local_sock:
             self._data_to_write_to_local.append(data)
             self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING)
         elif sock == self._remote_sock:
             self._data_to_write_to_remote.append(data)
             self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
         else:
             logging.error('write_all_to_sock:unknown socket')
     else:
         # 写完之后读
         if sock == self._local_sock:
             self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
         elif sock == self._remote_sock:
             self._update_stream(STREAM_UP, WAIT_STATUS_READING)
         else:
             logging.error('write_all_to_sock:unknown socket')
     return True
Пример #24
0
def parse_response(data):
    # 解析一个响应包
    try:
        if len(data) >= 12:
            header = parse_header(data)
            if not header:
                return None
            res_id, res_qr, res_tc, res_ra, res_rcode, res_qdcount, \
                res_ancount, res_nscount, res_arcount = header

            qds = []
            ans = []
            offset = 12
            for i in range(0, res_qdcount):
                l, r = parse_record(data, offset, True)
                offset += l
                if r:
                    qds.append(r)
            for i in range(0, res_ancount):
                l, r = parse_record(data, offset)
                offset += l
                if r:
                    ans.append(r)
            for i in range(0, res_nscount):
                l, r = parse_record(data, offset)
                offset += l
            for i in range(0, res_arcount):
                l, r = parse_record(data, offset)
                offset += l
            response = DNSResponse()
            if qds:
                response.hostname = qds[0][0]
            for an in qds:
                response.questions.append((an[1], an[2], an[3]))
            for an in ans:
                response.answers.append((an[1], an[2], an[3]))
            return response
    except Exception as e:
        shell.print_exception(e)
        return None
 def _write_to_sock(self, data, sock):
     # write data to sock
     # if only some of the data are written, put remaining in the buffer
     # and update the stream to wait for writing
     if not data or not sock:
         return False
     uncomplete = False
     try:
         l = len(data)
         s = sock.send(data)
         if s < l:
             data = data[s:]
             uncomplete = True
     except (OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                         errno.EWOULDBLOCK):
             uncomplete = True
         else:
             shell.print_exception(e)
             self.destroy()
             return False
     if uncomplete:
         if sock == self._local_sock:
             self._data_to_write_to_local.append(data)
             self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING)
         elif sock == self._remote_sock:
             self._data_to_write_to_remote.append(data)
             self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
         else:
             logging.error('write_all_to_sock:unknown socket')
     else:
         if sock == self._local_sock:
             self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)
         elif sock == self._remote_sock:
             self._update_stream(STREAM_UP, WAIT_STATUS_READING)
         else:
             logging.error('write_all_to_sock:unknown socket')
     return True
Пример #26
0
def daemon_start(pid_file, log_file):

    def handle_exit(signum, _):
        if signum == signal.SIGTERM:
            sys.exit(0)
        sys.exit(1)

    signal.signal(signal.SIGINT, handle_exit)
    signal.signal(signal.SIGTERM, handle_exit)

    # fork only once because we are sure parent will exit
    pid = os.fork()
    assert pid != -1

    if pid > 0:
        # parent waits for its child
        time.sleep(5)
        sys.exit(0)

    # child signals its parent to exit
    ppid = os.getppid()
    pid = os.getpid()
    if write_pid_file(pid_file, pid) != 0:
        os.kill(ppid, signal.SIGINT)
        sys.exit(1)

    os.setsid()
    signal.signal(signal.SIG_IGN, signal.SIGHUP)

    print('started')
    os.kill(ppid, signal.SIGTERM)

    sys.stdin.close()
    try:
        freopen(log_file, 'a', sys.stdout)
        freopen(log_file, 'a', sys.stderr)
    except IOError as e:
        shell.print_exception(e)
        sys.exit(1)
def parse_response(data):
    try:
        if len(data) >= 12:
            header = parse_header(data)
            if not header:
                return None
            res_id, res_qr, res_tc, res_ra, res_rcode, res_qdcount, \
                res_ancount, res_nscount, res_arcount = header

            qds = []
            ans = []
            offset = 12
            for i in range(0, res_qdcount):
                l, r = parse_record(data, offset, True)
                offset += l
                if r:
                    qds.append(r)
            for i in range(0, res_ancount):
                l, r = parse_record(data, offset)
                offset += l
                if r:
                    ans.append(r)
            for i in range(0, res_nscount):
                l, r = parse_record(data, offset)
                offset += l
            for i in range(0, res_arcount):
                l, r = parse_record(data, offset)
                offset += l
            response = DNSResponse()
            if qds:
                response.hostname = qds[0][0]
            for an in qds:
                response.questions.append((an[1], an[2], an[3]))
            for an in ans:
                response.answers.append((an[1], an[2], an[3]))
            return response
    except Exception as e:
        shell.print_exception(e)
        return None
 def _handle_stage_connecting(self, data):
     if self._is_local:
         data = self._encryptor.encrypt(data)
     self._data_to_write_to_remote.append(data)
     if self._is_local and not self._fastopen_connected and \
             self._config['fast_open']:
         # for sslocal and fastopen, we basically wait for data and use
         # sendto to connect
         try:
             # only connect once
             self._fastopen_connected = True
             remote_sock = \
                 self._create_remote_socket(self._chosen_server[0],
                                            self._chosen_server[1])
             self._loop.add(remote_sock, eventloop.POLL_ERR)
             data = b''.join(self._data_to_write_to_remote)
             l = len(data)
             s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server)
             if s < l:
                 data = data[s:]
                 self._data_to_write_to_remote = [data]
             else:
                 self._data_to_write_to_remote = []
             self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
         except (OSError, IOError) as e:
             if eventloop.errno_from_exception(e) == errno.EINPROGRESS:
                 # in this case data is not sent at all
                 self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING)
             elif eventloop.errno_from_exception(e) == errno.ENOTCONN:
                 logging.error('fast open not supported on this OS')
                 self._config['fast_open'] = False
                 self.destroy()
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
                 self.destroy()
Пример #29
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        key = None
        iv = None
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            if self._is_tunnel:
                # add ss header to data
                tunnel_remote = self.tunnel_remote
                tunnel_remote_port = self.tunnel_remote_port
                data = common.add_header(tunnel_remote, tunnel_remote_port,
                                         data)
            else:
                frag = common.ord(data[2])
                if frag != 0:
                    logging.warn('UDP drop a message since frag is not 0')
                    return
                else:
                    data = data[3:]
        else:
            # decrypt data
            try:
                data, key, iv = cryptor.decrypt_all(self._password,
                                                    self._method, data,
                                                    self._crypto_path)
            except Exception:
                logging.debug('UDP handle_server: decrypt data failed')
                return
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result
        logging.info("udp data to %s:%d from %s:%d" %
                     (dest_addr, dest_port, r_addr[0], r_addr[1]))
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            self._ota_enable_session = addrtype & ADDRTYPE_AUTH
            if self._ota_enable and not self._ota_enable_session:
                logging.warn('client one time auth is required')
                return
            if self._ota_enable_session:
                if len(data) < header_length + ONETIMEAUTH_BYTES:
                    logging.warn('UDP one time auth header is too short')
                    return
                _hash = data[-ONETIMEAUTH_BYTES:]
                data = data[:-ONETIMEAUTH_BYTES]
                _key = iv + key
                if onetimeauth_verify(_hash, data, _key) is False:
                    logging.warn('UDP one time auth fail')
                    return
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN, self)

        if self._is_local:
            key, iv, m = cryptor.gen_key_iv(self._password, self._method)
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._ota_enable_session:
                data = self._ota_chunk_data_gen(key, iv, data)
            try:
                data = cryptor.encrypt_all_m(key, iv, m, self._method, data,
                                             self._crypto_path)
            except Exception:
                logging.debug("UDP handle_server: encrypt data failed")
                return
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Пример #30
0
def main():

    shell.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 = shell.get_config(True)

    #added by cloud for local random choose a server and the port and the port_password
    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'
            )


#         config['server_port'] = int(random.choice(config['port_password'].items())[0])
        if config.has_key('server_port'):
            if type(config['server_port']) == list and config['server_port']:
                config['server_port'] = random.choice(
                    config.get('server_port', 8388))
            elif config['server_port']:
                config['server_port'] == int(
                    common.to_str(config.get('server_port', 8388)))
            else:
                config['server_port'] = int(
                    random.choice(config['port_password'].items())[0])
        else:
            config['server_port'] = int(
                random.choice(config['port_password'].items())[0])
        if not config['password'] or str(config['password']) == "":
            config['password'] = common.to_str(
                config['port_password']["%s" % config['server_port']])
    else:
        if type(config['server_port']) == list and config['server_port']:
            config['server_port'] = random.choice(
                config.get('server_port', 8388))
        else:
            config['server_port'] == int(
                common.to_str(config.get('server_port', 8388)))
        config["password"] = str(
            config["port_password"]["%s" % config["server_port"]]).strip()

    logging.warn('!' * 30)
    logging.info(
        "OK.. I choose this guy to help me f**k the GFW.. [ %s : %s : %s : %s : %s]"
        % (config['server'], config['server_port'], config['password'],
           config['server_info']["%s" % config['server']], config['method']))
    logging.warn('!' * 30)
    time.sleep(1)

    daemon.daemon_exec(config)

    try:
        logging.info("starting local at %s:%d" %
                     (config['local_address'], config['local_port']))

        dns_resolver = asyncdns.DNSResolver(config)
        tcp_server = tcprelay.TCPRelay(config, dns_resolver, True)
        udp_server = udprelay.UDPRelay(config, dns_resolver, True)
        loop = eventloop.EventLoop(config)
        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)

        daemon.set_user(config.get('user', None))
        loop.run()
    except Exception as e:
        shell.print_exception(e)
        sys.exit(1)
Пример #31
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        key = None
        iv = None
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('UDP drop a message since frag is not 0')
                return
            else:
                # RSV and FRAG are dropped
                data = data[3:]
        else:
            # 服务器解密
            data, key, iv = encrypt.dencrypt_all(self._password, self._method,
                                                 data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        # +------+---------------------+------------------+----------+-----------+
        # | ATYP | Destination Address | Destination Port | DATA | HMAC - SHA1 |
        # +------+---------------------+------------------+----------+-----------+
        # | 1 | Variable | 2 | Variable | 10 |
        # +------+---------------------+------------------+----------+-----------+
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            # 服务端拆包,ota验证
            server_addr, server_port = dest_addr, dest_port
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH:
                self._one_time_auth_enable = True
                if len(data) < header_length + ONETIMEAUTH_BYTES:
                    logging.warn('UDP one time auth header is too short')
                    return
                # 尾巴的hmac-sha1
                _hash = data[-ONETIMEAUTH_BYTES:]
                data = data[:-ONETIMEAUTH_BYTES]
                _key = iv + key
                if onetimeauth_verify(_hash, data, _key) is False:
                    logging.warn('UDP one time auth fail')
                    return
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            # 同步查询DNS
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)
        if not client:
            # 创建client socket
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            # 记录数据要返回给谁
            self._client_fd_to_server_addr[client.fileno()] = r_addr

            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN, self)

        if self._is_local:
            # 客户端 ota数据生成,然后加密
            key, iv, m = encrypt.gen_key_iv(self._password, self._method)
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable:
                data = self._ota_chunk_data_gen(key, iv, data)
            data = encrypt.encrypt_all_m(key, iv, m, self._method, data)
            if not data:
                return
        else:
            # 服务器忽略前面的地址与端口头
            data = data[header_length:]
        if not data:
            return
        try:
            # 数据上行upstream
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Пример #32
0
    def _handle_server_dns_resolved(self, error, remote_addr, server_addr,
                                    params):
        if error:
            return
        data, r_addr, uid, header_length = params
        user_id = self._listen_port
        try:
            server_port = remote_addr[1]
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:  # drop
                return
            af, socktype, proto, canonname, sa = addrs[0]
            server_addr = sa[0]
            key = client_key(r_addr, af)
            client_pair = self._cache.get(key, None)
            if client_pair is None:
                client_pair = self._cache_dns_client.get(key, None)
            if client_pair is None:
                if self._forbidden_iplist:
                    if common.to_str(sa[0]) in self._forbidden_iplist:
                        logging.debug('IP %s is in forbidden list, drop' %
                                      common.to_str(sa[0]))
                        # drop
                        return
                if self._forbidden_portset:
                    if sa[1] in self._forbidden_portset:
                        logging.debug('Port %d is in forbidden list, reject' %
                                      sa[1])
                        # drop
                        return
                client = socket.socket(af, socktype, proto)
                client_uid = uid
                client.setblocking(False)
                self._socket_bind_addr(client, af)
                is_dns = False
                if len(data) > header_length + 13 and data[
                        header_length + 4:header_length +
                        12] == b"\x00\x01\x00\x00\x00\x00\x00\x00":
                    is_dns = True
                else:
                    pass
                if sa[1] == 53 and is_dns:  #DNS
                    logging.debug("DNS query %s from %s:%d" %
                                  (common.to_str(sa[0]), r_addr[0], r_addr[1]))
                    self._cache_dns_client[key] = (client, uid)
                else:
                    self._cache[key] = (client, uid)
                self._client_fd_to_server_addr[client.fileno()] = (r_addr, af)

                self._sockets.add(client.fileno())
                self._eventloop.add(client, eventloop.POLL_IN, self)

                logging.debug('UDP port %5d sockets %d' %
                              (self._listen_port, len(self._sockets)))

                if uid is not None:
                    user_id = struct.unpack('<I', client_uid)[0]
            else:
                client, client_uid = client_pair
            self._cache.clear(self._udp_cache_size)
            self._cache_dns_client.clear(16)

            if self._is_local:
                ref_iv = [encrypt.encrypt_new_iv(self._method)]
                self._protocol.obfs.server_info.iv = ref_iv[0]
                data = self._protocol.client_udp_pre_encrypt(data)
                #logging.debug("%s" % (binascii.hexlify(data),))
                data = encrypt.encrypt_all_iv(
                    self._protocol.obfs.server_info.key, self._method, 1, data,
                    ref_iv)
                if not data:
                    return
            else:
                data = data[header_length:]
            if not data:
                return
        except Exception as e:
            shell.print_exception(e)
            logging.error("exception from user %d" % (user_id, ))

        try:
            client.sendto(data, (server_addr, server_port))
            self.add_transfer_u(client_uid, len(data))
            if client_pair is None:  # new request
                addr, port = client.getsockname()[:2]
                common.connect_log(
                    'UDP data to %s(%s):%d from %s:%d by user %d' %
                    (common.to_str(remote_addr[0]), common.to_str(server_addr),
                     server_port, addr, port, user_id))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            logging.warning('IOError sendto %s:%d by user %d' %
                            (server_addr, server_port, user_id))
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port

        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        logging.debug(key)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN)

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Пример #34
0
def main():

    shell.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 = shell.get_config(True)

    #added by tib for local random choose a server and the port and the port_password
    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')
#         config['server_port'] = int(random.choice(config['port_password'].items())[0])        
        if config.has_key('server_port'):
            if type(config['server_port']) == list and config['server_port']:
                config['server_port'] = random.choice(config.get('server_port', 8388))
            elif config['server_port']:
                config['server_port'] == int(common.to_str(config.get('server_port',8388)))
            else:
                config['server_port'] = int(random.choice(config['port_password'].items())[0])
        else:
            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 type(config['server_port']) == list and config['server_port']:
            config['server_port'] = random.choice(config.get('server_port', 8388))
        else:
            config['server_port'] == int(common.to_str(config.get('server_port',8388)))
        config["password"] = str(config["port_password"]["%s" % config["server_port"]]).strip()

    logging.warn('!' * 30)
    logging.info("OK.. I choose this guy to help me f**k the GFW.. [ %s : %s : %s : %s : %s]" % (config['server'],config['server_port'],config['password'],config['server_info']["%s" % config['server']],config['method']))
    logging.warn('!' * 30)
    time.sleep(1)

    daemon.daemon_exec(config)

    try:
        logging.info("starting local at %s:%d" % (config['local_address'], config['local_port']))

        dns_resolver = asyncdns.DNSResolver(config)
        tcp_server = tcprelay.TCPRelay(config, dns_resolver, True)
        udp_server = udprelay.UDPRelay(config, dns_resolver, True)
        loop = eventloop.EventLoop(config)
        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)

        daemon.set_user(config.get('user', None))
        loop.run()
    except Exception as e:
        shell.print_exception(e)
        sys.exit(1)