Example #1
0
    def _on_remote_read(self):
        logging.debug("Running in the TCPRelayHandler class. [_on_remote_read]")
        # 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))
        if self._is_local:
            data = self._encryptor.decrypt(data)
        else:
            data = self._encryptor.encrypt(data)
        try:
            self._write_to_sock(data, self._local_sock)
#             if not self._is_local:
#                 if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
#                     port_limits = json.loads(open(self._config['port_limit']).read())
#                     if str(self._server._listen_port) in port_limits:
#                         port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + len(data) + BUF_SIZE
#                         open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            # TODO use logging when debug completed
            self.destroy()
Example #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
Example #3
0
    def _on_remote_read(self):
        logging.debug('on remote read')
        # 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))
        if self._is_local:
            data = self._encryptor.decrypt(data)
        else:
            # logging.debug('received data:[%s]' % data)
            # data = 'HTTP/1.1 302 Found\nLocation: https://ashadowsocks.com/'
            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()
Example #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)

        def hup_handler(signum, _):
            users = shell.get_user_dict(config['users-file'])
            for tcp_server in tcp_servers:
                tcp_server.set_users(users)
        signal.signal(signal.SIGHUP, hup_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)
Example #5
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)

        pid = os.getpid();
        logging.info("pid-file=%s,pid=%d", config['pid-file'], pid);
        try:
            with open(config['pid-file'], 'w') as f:
                f.write(str(pid));
                f.close();
        except IOError:
            logging.warn('error on write pid to pid-file..%s, %d', config['pid-file'], pid)
            sys.exit(1)

        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)
Example #6
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
Example #7
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')
Example #8
0
 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
Example #9
0
    def _on_remote_read(self):
        # handle all remote read events
        data = None
        try:
            data = self._remote_sock.recv(BUF_SIZE)

        except socket.error as err:
            error_no = err.args[0]
            if sys.platform == "win32":
                if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                                errno.EWOULDBLOCK, errno.WSAEWOULDBLOCK):
                    return
            elif error_no in (errno.EAGAIN, errno.EINPROGRESS,
                              errno.EWOULDBLOCK):
                return
        if not data:
            self.destroy()
            return
        self._update_activity(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()
Example #10
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))
        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()
Example #11
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:
         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:
         if sock:
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
Example #12
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))
        """
        getattr(object, name[, default]) 如果 siganl.SIGQUIT 不存在,即注册 SIGTERM 事件
        SIGTERM 终止进程,但终止前会允许 handler 被执行,SIGKILL 不会
        SIGQUIT 在 SIGTERM 的基础上,还生成了一份 core dump 文件记录了进程信息
        http://programmergamer.blogspot.jp/2013/05/clarification-on-sigint-sigterm-sigkill.html
        """
        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 解析器到事件循环中
            dns_resolver.add_to_loop(loop)
            # 批量地将所有 tcp_server 和 udp_server 加入事件循环中
            list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))
            # 使守护进程以设置中 user 的名义执行
            daemon.set_user(config.get('user', None))
            # 启动事件循环
            loop.run()
        except Exception as e:
            shell.print_exception(e)
            sys.exit(1)
Example #13
0
def write_pid_file(pid_file, pid):
    """
    pidfile

    通常在 /var/run 目录中会看到很多进程的 pid 文件, 其实这些文件就是一个记录着进程的 PID 号的文本文件。
    它的作用是防止程序启动多个副本,只有获得 pid 文件写入权限的进程才能正常启动并把进程 PID 写入到该文件,
    而同一程序的其他进程则会检测到该文件无法写入退出。

    """
    # 文件描述符控制
    import fcntl
    # 获取文件信息
    import stat

    try:
        # O_RDWR | O_CREAT 如果文件存在,打开文件以读取写入,否则创建该文件,并使其拥有以下权限
        # S_IRUSR 文件所有者具可读取权限
        # S_IWUSR 文件所有者具可写入权限
        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
    # F_GETFD 获取文件描述符标记
    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:
        """
        文件锁
        LOCK_EX exclusive 独占锁
        LOCK_NB non-blocking 非阻塞锁
        在独占锁的情况下,同一时间只有一个进程可以锁住这个文件。
        在有其他进程占有该锁时,
        如果是阻塞锁,lockf 函数会一直阻塞,直到获得锁,而非阻塞锁使 lockf 函数直接返回 IOError。
        fcntl.lockf(fd, operation[, length[, start[, whence]]])
        start 和 length 标记了要锁住的区域的起始位置和长度,而 whence 标记了整个锁区域的偏移量。
        SEEK_SET SEEK_CUR SEEK_END 分别表示文件开头,当前指针位置和文件结尾
        """
        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB, 0, 0, os.SEEK_SET)
    except IOError:
        # pidfile 被其他进程锁住的情况,读取该 pidfile 内容
        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
    # 把 fd 对应文件修剪为长度为 0,即清空该文件
    os.ftruncate(fd, 0)
    # 将当前进程的 pid 文件写入到 fd 对应文件中
    os.write(fd, common.to_bytes(str(pid)))
    return 0
Example #14
0
 def _write_to_sock(self, data, sock):
     logging.debug("Running in the TCPRelayHandler class. [_write_to_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)
         if sock == self._local_sock and self._is_local and self._stage == STAGE_INIT:
             logging.info("[Client] Received data from browser and just sending 'hello' back to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from browser and just sending -encrypted- data to [VPS] ! data length is: [%s]" % l)
         elif sock == self._local_sock and self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Client] Received data from VPS and just sending -decrypted- data to [browser] ! data length is: [%s]" % l)
         elif sock == self._remote_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from client and going to send -decrypted- data to [INTERNET] ! data length is: [%s]" % l)
         elif sock == self._local_sock and not self._is_local and self._stage == STAGE_STREAM:
             logging.info("[Server] Received data from INTERNET and going to send -encrypted- data to [client] ! data length is: [%s]" % l)
         if not self._is_local:
             if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
                 port_limits = json.loads(open(self._config['port_limit']).read())
                 if str(self._server._listen_port) in port_limits:
                     port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + len(data)
                     open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
         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')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     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')
             common.error_to_file('write_all_to_sock:unknown socket',self._config)
     return True
Example #15
0
def parse_response(data):
    try:
        if len(data) >= 12:
            # analyse Header
            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 = []  # [(name, None, record_type, record_class, None, None)]
            ans = []  # [(name, ip, record_type, record_class, record_ttl)]
            offset = 12

            # extract all questions and answers, and store them
            # l is the length of either one Question or one Answer section
            # analyse Question section
            for i in range(0, res_qdcount):
                l, r = parse_record(data, offset, True)

                # update offset
                # Question section contains QDCOUNT entries
                offset += l

                if r:
                    qds.append(r)

            # analyse Answer section
            for i in range(0, res_ancount):
                l, r = parse_record(data, offset)

                # Answer section contains ANCOUNT entries
                offset += l
                if r:
                    ans.append(r)

            # not used
            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]  # name
            for an in qds:
                response.questions.append((an[1], an[2], an[3]))  # [(None, record_type, record_class)]
            for an in ans:
                response.answers.append((an[1], an[2], an[3]))  # [(ip, record_type, record_class)]
            return response
    except Exception as e:
        shell.print_exception(e)
        return None
Example #16
0
    def _handle_dns_resolved(self, result, error):
        if error:
            self._log_error(error)
            self.destroy()
            return

        # when domain name is resolved
        if result:
            ip = result[1]
            if ip:
                try:
                    self._stage = STAGE_CONNECTING
                    remote_addr = ip

                    # port is not included in the result
                    if self._is_local:
                        remote_port = self._chosen_server[1]
                    else:
                        remote_port = self._remote_address[1]

                    # for fastopen sslocal:
                    # sslocal reads from client
                    if self._is_local and self._config['fast_open']:
                        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

                    # for non-fastopen sslocal,
                    # 1. connect to ssremote, add to loop, set event as ERR|OUT
                    # 2. sslocal relays up stream
                    # for ssremote, 
                    # 1. connect to dest, add to loop, set event as ERR|OUT
                    # 2. ssremote reads from dest
                    else:
                        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()
    def _handle_dns_resolved(self, result, error):
        """
        DNS请求解析完成后调用该函数
        result:     (addr, ip)
        error:      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
                    # 若为sslocal,则remote_socket连接的端口为初始化文件中的服务器端口
                    # 若为ssserver,则remote_socket连接的端口为解析出的remote_address的地址
                    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._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()
Example #18
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)

    daemon.daemon_exec(config)

    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,
                                       stat_callback=stat_handler)

        a_config = config.copy()
        if a_config.get('port_password', None):
            a_config['server_port'] = random.choice(
                a_config['port_password'].keys())
            a_config['password'] = a_config['port_password']\
                [a_config['server_port']]

        udp_server = udprelay.UDPRelay(a_config, dns_resolver, True,
                                       stat_callback=stat_handler)
        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))

        t = threading.Thread(target=monitor, args=(), name='monitor')
        t.daemon = True
        t.start()

        loop.run()
    except Exception as e:
        shell.print_exception(e)
        sys.exit(1)
Example #19
0
def run_server():

	try:
		loop = eventloop.EventLoop()
		dns_resolver.add_to_loop(loop)
		list(map(lambda s: s.add_to_loop(loop), tcp_servers))
		daemon.set_user(config.get('user', None))
		loop.run()
	except Exception as e:
		shell.print_exception(e)
		sys.exit(1)
Example #20
0
def daemon_start(pid_file, log_file):
    # 启动一个 daemon
    def handle_exit(signum, _):
        # 如果信号为 SIGTERM,则 sys.exit(0),其中 0 代表正常退出
        if signum == signal.SIGTERM:
            sys.exit(0)
        # 否则为异常退出
        sys.exit(1)

    # 设置当接收到 SIGINIT 或者 SIGTERM 信号时,调用 handle_exit 函数
    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()
    # 断言 fork 函数返回正常
    assert pid != -1

    # 此处为父进程执行
    if pid > 0:
        # parent waits for its child
        # 睡眠 5 秒后正常退出
        time.sleep(5)
        sys.exit(0)

    # child signals its parent to exit
    # 获得父进程 pid
    ppid = os.getppid()
    # 获得子进程 pid
    pid = os.getpid()
    # 将子进程 PID 写入 pid 文件
    if write_pid_file(pid_file, pid) != 0:
        # 如果写入失败则杀死父进程,同时子进程退出自己
        # 写入失败原因可能是有另一进程已经启动,控制了 pid 文件
        os.kill(ppid, signal.SIGINT)
        sys.exit(1)

    # setsid() 以后,子进程就不会因为父进程的退出而终止
    os.setsid()
    # SIGHUP 挂起信号,SIG_IGN 为忽略该挂起信号
    signal.signal(signal.SIGHUP, signal.SIG_IGN)

    print('started')
    # 使用 SIGTERM 信号杀掉父进程,SIGTERM 给了程序一个处理任务的机会,SIGKILL 会直接杀死进程
    os.kill(ppid, signal.SIGTERM)
    # 关闭标准输入,相当于 os.close(sys.stdin.fileno())
    sys.stdin.close()
    try:
        # 以追加的方式将 stdout 和 stderr 重定向到 log_file
        freopen(log_file, 'a', sys.stdout)
        freopen(log_file, 'a', sys.stderr)
    except IOError as e:
        shell.print_exception(e)
        sys.exit(1)
Example #21
0
    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)
                        if self._remote_udp:
                            self._loop.add(remote_sock, eventloop.POLL_IN, self._server)
                            if self._remote_sock_v6:
                                self._loop.add(self._remote_sock_v6, eventloop.POLL_IN, self._server)
                        else:
                            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)
                        if self._remote_udp:
                            while self._data_to_write_to_remote:
                                data = self._data_to_write_to_remote[0]
                                del self._data_to_write_to_remote[0]
                                self._write_to_sock(data, self._remote_sock)
                    return
                except Exception as e:
                    shell.print_exception(e)
                    if self._config["verbose"]:
                        traceback.print_exc()
        self.destroy()
Example #22
0
 def _on_local_read(self):
     # handle all local read events and dispatch them to methods for
     # each stage
     if not self._local_sock:
         return
     is_local = self._is_local
     data = None
     try:
         data = self._local_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
     ogn_data = data
     self._update_activity(len(data))
     if not is_local:
         if self._encrypt_correct:
             obfs_decode = self._obfs.server_decode(data)
             if obfs_decode[2]:
                 self._write_to_sock(b'', self._local_sock)
             if obfs_decode[1]:
                 data = self._encryptor.decrypt(obfs_decode[0])
             else:
                 data = obfs_decode[0]
             try:
                 data = self._obfs.server_post_decrypt(data)
             except Exception as e:
                 shell.print_exception(e)
                 self.destroy()
         if not data:
             return
     self._server.server_transfer_ul += len(data)
     if self._stage == STAGE_STREAM:
         if self._is_local:
             data = self._obfs.client_pre_encrypt(data)
             data = self._encryptor.encrypt(data)
             data = self._obfs.client_encode(data)
         self._write_to_sock(data, self._remote_sock)
         return
     elif is_local and self._stage == STAGE_INIT:
         # TODO check auth method
         self._write_to_sock(b'\x05\00', self._local_sock)
         self._stage = STAGE_ADDR
         return
     elif self._stage == STAGE_CONNECTING:
         self._handle_stage_connecting(data)
     elif (is_local and self._stage == STAGE_ADDR) or \
             (not is_local and self._stage == STAGE_INIT):
         self._handle_stage_addr(ogn_data, data)
Example #23
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()
Example #24
0
 def _on_remote_read(self, is_remote_sock):
     # handle all remote read events
     data = None
     try:
         if self._remote_udp:
             if is_remote_sock:
                 data, addr = self._remote_sock.recvfrom(BUF_SIZE)
             else:
                 data, addr = self._remote_sock_v6.recvfrom(BUF_SIZE)
             port = struct.pack(">H", addr[1])
             try:
                 ip = socket.inet_aton(addr[0])
                 data = b"\x00\x01" + ip + port + data
             except Exception as e:
                 ip = socket.inet_pton(socket.AF_INET6, addr[0])
                 data = b"\x00\x04" + ip + port + data
             data = struct.pack(">H", len(data) + 2) + data
             # logging.info('UDP over TCP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1]))
         else:
             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,
             10035,
         ):  # errno.WSAEWOULDBLOCK
             return
     if not data:
         self.destroy()
         return
     self._server.server_transfer_dl += len(data)
     self._update_activity(len(data))
     if self._is_local:
         obfs_decode = self._obfs.client_decode(data)
         if obfs_decode[1]:
             self._write_to_sock(b"", self._remote_sock)
         data = self._encryptor.decrypt(obfs_decode[0])
         data = self._obfs.client_post_decrypt(data)
     else:
         if self._encrypt_correct:
             data = self._obfs.server_pre_encrypt(data)
             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()
Example #25
0
    def _handle_dns_resolved(self, result, error):
        logging.debug("Running in the TCPRelayHandler class. [_handle_dns_resolved]")
        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:
                            if self._is_local:
                                logging.info("[Client] I am just openning one port to connect VPS.")
                            elif not self._is_local:
                                logging.info("[Server] I am just openning one port to connect INTERNET.")
                            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()
Example #26
0
 def uvcallback(watcher, revents, error):
     event = 0
     if error:
         event = POLL_ERR
     else:
         if revents & pyuv.UV_READABLE:
             event |= POLL_IN
         if revents & pyuv.UV_WRITABLE:
             event |= POLL_OUT
     handler = self._wahtch2handler[watcher]
     try:
         fd = watcher.fileno()
         handler.handle_event(self._fd2sock[fd], fd, event)
     except (OSError, IOError) as e:
         shell.print_exception(e)
def parse_response(data):
    """
    将接收到的数据转化为DNS响应结构体
    :param data:    接收到的数据
    :return:        DNS响应结构体
    """
    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
            # 处理QUESTION部分
            for i in range(0, res_qdcount):
                l, r = parse_record(data, offset, True)
                offset += l
                if r:
                    qds.append(r)
            # 处理ANSWER部分
            for i in range(0, res_ancount):
                l, r = parse_record(data, offset)
                offset += l
                if r:
                    ans.append(r)
            # 处理AUTHORITY部分,实际什么也没干。
            for i in range(0, res_nscount):
                l, r = parse_record(data, offset)
                offset += l
            # 处理ADDITIONAL部分,实际什么也没干
            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
Example #28
0
    def _write_to_sock(self, data, sock):

        # ugly, uncomplete
        if not data or not sock:
            return False
        uncomplete = False

        # send data to the sock and confirm if complete data has been sent
        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 sslocal or ssremote has sent incomplete data
        # prepare to send the remaining
        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')
        # if sslocal has sent complete data
        # client prepares to read
        # if ssremote has sent complete data
        # dest prepares to read
        if ssremote has
        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
Example #29
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)
        # ENOENT No such file or directory
        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:
            # ESRCH No such process
            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):
        # 一直杀到 daemon 进程死了为止
        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')
    # 删除 pidfile
    os.unlink(pid_file)
Example #30
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._encryptor.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()
Example #31
0
    def handle_event(self, sock, fd, event):

        """
        判断事件是新建handler还是已有连接的事件并分发事件

        :param sock: 收到信息的socket连接

        :param fd: socket的fd标识符,转送给该fd对应的handler

        :param event: 触发的事件

        :return: None
        """
        # 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:
            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:
            if sock:
                handler = self._fd_to_handlers.get(fd, None)
                if handler:
                    handler.handle_event(sock, event)
            else:
                logging.warn('poll removed fd')
Example #32
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 (socket.error, OSError, IOError) as e:
         error_no = eventloop.errno_from_exception(e)
         if sys.platform == "win32":
             if error_no in (errno.EAGAIN, errno.EINPROGRESS,
                             errno.EWOULDBLOCK, errno.WSAEWOULDBLOCK):
                 uncomplete = True
         elif 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
Example #33
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)
Example #34
0
    def _handle_dns_resolved(self, result, error):
        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:
                    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
                    remote_sock = self._create_remote_socket(
                        remote_addr, remote_port)
                    try:
                        remote_sock.connect((remote_addr, remote_port))
                    except (socket.error, 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)
        self.destroy()
Example #35
0
def main():
    # 检查 python 版本
    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) # 加载配置文件

    daemon.daemon_exec(config)  # 读取配置文件是否开启进程守护, 仅在UNIX ,Linux 上有效

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

        dns_resolver = asyncdns.DNSResolver()   # 创建dns 查询对象
        tcp_server = tcprelay.TCPRelay(config, dns_resolver, True)  # 创建 TCP 代理转发对象
        udp_server = udprelay.UDPRelay(config, dns_resolver, True)  # 创建 UDP 代理转发对象
        loop = eventloop.EventLoop()    # 创建事件处理对象
        # 将dns查询、tcp代理方式转发、udp代理方式转发绑定到事件循环
        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)  # "Ctrl + C" 中断指令

        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)
Example #36
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)

    daemon.daemon_exec(config)

    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)
Example #37
0
 def _handle_stage_connecting(self, data):
     if self._is_local:
         if self._encryptor is not None:
             data = self._protocol.client_pre_encrypt(data)
             data = self._encryptor.encrypt(data)
             data = self._obfs.client_encode(data)
     if 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, 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()
                 logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1]))
                 self.destroy()
Example #38
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
Example #39
0
    def _on_remote_read(self):
        # handle all remote read events
        data = None
        if self._is_local:
            buf_size = UP_STREAM_BUF_SIZE
        else:
            buf_size = DOWN_STREAM_BUF_SIZE
        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

        activity = {
            'remote_address': self._remote_address[0],
            'local_address': self._client_address[0],
            'protocal': 'TCP',
            'type': 'DOWN',
            'traffic': len(data),
            'time': datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S')
        }

        self._update_activity(activity)

        if self._is_local:
            data = self._cryptor.decrypt(data)
        else:
            data = self._cryptor.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()
Example #40
0
def write_pid_file(pid_file, pid):
    # fcntl: 给文件加锁
    # stat: os.stat是将文件的相关属性读出来,然后用stat模块来处理,处理方式有多重,就要看看stat提供了什么了
    import fcntl
    import stat

    try:
        # os.open()相关文档 https://www.runoob.com/python/os-open.html
        # 打开或者创建一个存放进程pid的文件,并且设置权限,如果失败抛出异常
        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:
        # os.read() 方法用于从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串
        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对应的文件, 它最大不能超过文件大小。
    os.ftruncate(fd, 0)
    # os.write() 方法用于写入字符串到文件描述符 fd 中. 返回实际写入的字符串长度。
    os.write(fd, common.to_bytes(str(pid)))
    return 0
Example #41
0
    def run(self):
        events = []
        while not self._stopping:
            asap = False  # wtf ?

            # start select
            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 each socket
            # 1. resolve corresponding handler
            # note that link between socket and handler is established elsewhere
            # link is established using eventloop.add()
            # 2. handle socket according to socket event
            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)

            # call callbacks when asap or time is out
            now = time.time()
            if asap or now - self._last_time >= TIMEOUT_PRECISION:
                for callback in self._periodic_callbacks:
                    callback()
                self._last_time = now
Example #42
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()
            # note(yan): 消息里面会带上question的hostname
            # 因为整个协议是跑在UDP上的,所以结果里面必须带上问题。
            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
Example #43
0
 def _on_remote_read(self, is_remote_sock):
     # handle all remote read events
     data = None
     try:
         if self._remote_udp:
             if is_remote_sock:
                 data, addr = self._remote_sock.recvfrom(BUF_SIZE)
             else:
                 data, addr = self._remote_sock_v6.recvfrom(BUF_SIZE)
             port = struct.pack('>H', addr[1])
             try:
                 ip = socket.inet_aton(addr[0])
                 data = '\x00\x01' + ip + port + data
             except Exception as e:
                 ip = socket.inet_pton(socket.AF_INET6, addr[0])
                 data = '\x00\x04' + ip + port + data
             data = struct.pack('>H', len(data) + 2) + data
             #logging.info('UDP over TCP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1]))
         else:
             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, 10035): #errno.WSAEWOULDBLOCK
             return
     if not data:
         self.destroy()
         return
     self._server.server_transfer_dl += len(data)
     self._update_activity(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()
Example #44
0
    def _send_control_data(self, data):
        """
        根据客户端地址,向对应的客户端发送数据

        :param data: 发送数据

        :return: 如果出现错误,退出发送
        """

        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()
Example #45
0
def write_pid_file(pid_file, pid):
    """
    写pid_file,记录守护线程pid号

    :param pid_file: 记录守护线程pid号的文件

    :param pid: 守护线程pid号

    :return: 0或-1,0表示成功,-1表示失败
    """

    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
Example #46
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')
    logging.info('ShadowsocksR is 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)
Example #47
0
File: tcprelay.py Project: able8/ss
 def handle_event(self, sock, fd, event):
     logging.debug("Running in the TCPRelay class....[_handle_events]")
     # handle events and dispatch to handlers
     if sock:
         logging.debug("LOGGING fd %d %s" %
                       (fd, eventloop.EVENT_NAMES.get(event, event)))
     if not self._is_local:
         if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']):
             port_limits = json.loads(open(self._config['port_limit']).read())
             if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']:
                 logging.warn('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port)
                 self.close()
     if sock == self._server_socket:
         if event & eventloop.POLL_ERR:
             # TODO
             raise Exception('server_socket error')
             common.error_to_file("server_socket error",self._config)
         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:
         if sock:
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
             common.error_to_file('poll removed fd',self._config)
Example #48
0
    def _on_remote_read(self):
        logging.info('[%d] - [%d]: _on_remote_read 从远程读取数据' %
                     (self._local_sock.fileno(), self._remote_sock.fileno()))
        data = None

        buf_size = UP_STREAM_BUF_SIZE

        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
        logging.info('[%d] - [%d]: _on_remote_read 从远程读取数据成功' %
                     (self._local_sock.fileno(), self._remote_sock.fileno()))
        if not data:
            logging.info(
                '[%d] - [%d]: _on_remote_read 远程读取数据(%s)为空, 远程已经关闭了连接 调用销毁函数 destroy'
                %
                (self._local_sock.fileno(), self._remote_sock.fileno(), data))
            self.destroy()
            return

        self._update_activity(len(data))
        data = self._cryptor.decrypt(data)
        logging.info('[%d] - [%d]: _on_remote_read 解密从远程读取的数据(%s)' %
                     (self._local_sock.fileno(), self._remote_sock.fileno(),
                      data.replace('\r\n', ' ')))
        try:
            logging.info(
                '[%d] - [%d]: _on_remote_read try将解密过后的数据(%s)写向 _local_sock' %
                (self._local_sock.fileno(), self._remote_sock.fileno(),
                 data.replace('\r\n', ' ')))
            self._write_to_sock(data, self._local_sock)
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            self.destroy()
Example #49
0
    def run(self):
        events = []
        while not self._stopping:
            asap = False
            try:
                # 这里调用的是自定义的poll函数,它返回一个三元组的list,在fd和event之前增
                # 加了一个socket对象
                # 若超时,则events为[],直接执行到now = time.time()语句
                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就是相关处理类(比如TCPRelay, DNSResolver等)的实例
                    handler = handler[1]
                    try:
                        handler.handle_event(sock, fd, event)
                    except (OSError, IOError) as e:
                        shell.print_exception(e)
            now = time.time()
            # 超时处理
            # 从__init__函数可知_last_time一开始是eventloop初始化的时间
            if asap or now - self._last_time >= TIMEOUT_PRECISION:
                # 所有的socket注册到loop中时都会将自己的超时处理函数添加到
                # _periodic_callbacks列表中
                for callback in self._periodic_callbacks:
                    callback()
                self._last_time = now
Example #50
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))
     # 判断该socket是客户端第一次连接还是客户端连接之后发送的请求
     # 如果是 TCPRelay 的 socket
     # 这时候说明有 TCP 连接,创建 TCPRelayHandler 并封装
     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来管理客户端
             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触发的,
         # 且sock是有效的
         if sock:
             # 根据fd查找到对应的handler
             handler = self._fd_to_handlers.get(fd, None)
             if handler:
                 # 调用handler.handle_event来处理读写事件
                 handler.handle_event(sock, event)
         else:
             logging.warn('poll removed fd')
Example #51
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)
Example #52
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

                    # EPIPE: 当客户关闭连接时触发
                    # EINTR: 收到信号时触发
                    # 尽可能触发
                    asap = True
                    logging.debug('poll:%s', e)
                else:
                    logging.error('poll:%s', e)
                    traceback.print_exc()
                    continue
            #找到对应事件的handler并将事件交给handler处理
            for sock, fd, event in events:
                handler = self._fdmap.get(fd, None)
                if handler is not None:
                    handler = handler[1]
                    try:
                        # handler 可能是 TCPRelay、UDPRelay 或 DNSResolver
                        handler.handle_event(sock, fd, event)
                    except (OSError, IOError) as e:
                        shell.print_exception(e)
            # 计时器。每隔 10s 调用注册的 handle_periodic 函数处理超时或清除缓存
            now = time.time()
            if asap or now - self._last_time >= TIMEOUT_PRECISION:
                for callback in self._periodic_callbacks:
                    callback()
                self._last_time = now
Example #53
0
    def _write_to_sock(self, data, sock):
        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:
            errno_no = eventloop.errno_from_exception(e)
            if errno_no in (errno.EAGAIN, errno.EINPROGRESS,
                            errno.EWOULDBLOCK):
                uncomplete = True
            else:
                shell.print_exception(e)
                self.destory()
                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
Example #54
0
 def destroy(self):
     # destroy the handler and release any resources
     # promises:
     # 1. destroy won't make another destroy() call inside
     # 2. destroy releases resources so it prevents future call to destroy
     # 3. destroy won't raise any exceptions
     # if any of the promises are broken, it indicates a bug has been
     # introduced! mostly likely memory leaks, etc
     try:
         if self._stage == STAGE_DESTROYED:
             # this couldn't happen
             logging.debug('already destroyed')
             return
         self._stage = STAGE_DESTROYED
         if self._remote_address:
             logging.info('DESTROY: %s' % str(self._remote_address))
         else:
             logging.debug('destroy')
         if self._remote_sock:
             logging.debug('destroying remote')
             self._loop.remove(self._remote_sock)
             with self._server_lock:
                 del self._fd_to_handlers[self._remote_sock.fileno()]
             self._remote_sock.close()
             self._remote_sock = None
         if self._local_sock:
             logging.debug('destroying local')
             self._loop.remove(self._local_sock)
             with self._server_lock:
                 del self._fd_to_handlers[self._local_sock.fileno()]
             self._local_sock.close()
             self._local_sock = None
         self._dns_resolver.remove_callback(self._handle_dns_resolved)
         self._server.remove_handler(self)
     except Exception as e:
         shell.print_exception(e)
         if self._config['verbose']:
             traceback.print_exc()
    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

            handle = False
            for sock, fd, event in events:
                handler = self._fdmap.get(fd, None)
                if handler is not None:
                    handler = handler[1]
                    try:
                        handle = handler.handle_event(sock, fd,
                                                      event) or handle
                    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
            if events and not handle:
                time.sleep(0.001)
        print("stop!")
Example #56
0
File: tcprelay.py Project: able8/ss
 def _handle_stage_connecting(self, data):
     logging.debug("Running in the TCPRelayHandler class. [_handle_stage_connecting]")
     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, 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')
                 common.error_to_file('fast open not supported on this OS',self._config)
                 self._config['fast_open'] = False
                 self.destroy()
             else:
                 shell.print_exception(e)
                 if self._config['verbose']:
                     traceback.print_exc()
                 self.destroy()
Example #57
0
    def run(self):
        events = []
        logging.info("start running .....")
        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)
                    traceback.print_exc()
                    continue

            for sock, fd, event in events:
                handler = self._fdmap.get(fd, None)
                if handler is not None:
                    logging.info("fd:%d handler:%s" % (fd, str(handler)))
                    handler = handler[1]
                    try:
                        handler.handle_event(sock, fd, event)
                    except (OSError, IOError) as e:
                        shell.print_exception(e)
                else:
                    logging.error("handler is null.fd:%d", fd)
            now = time.time()
            if asap or now - self._last_time >= TIMEOUT_PRECISION:
                for callback in self._periodic_callbacks:
                    callback()
                self._last_time = now

        logging.info("stop running .....")
    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):
                    asap = True
                    logging.debug('poll: %s', e)
                else:
                    logging.error('poll: %s', e)
                    traceback.print_exc()
                    continue

            for sock, fd, eventMode in events:
                handler = self._fdmap.get(fd, None)

                if handler is not None:
                    handler = handler[1]
                    try:
                        handler.handle_event(sock, fd, eventMode)
                    except (OSError, IOError) as e:
                        shell.print_exception(e)
Example #59
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
    # fcntl函数出错时返回-1
    # F_GETFD表示获取文件描述符标志,Unix只定义了一个文件描述符标志,
    # 就是FD_CLOEXEC(执行时关闭)
    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:
        # lockf实现了fcntl函数的记录锁动作,具体参照apue14.3和python fcntl模块
        # 此处的lockf以不阻塞的方式获取一个排他的写锁
        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB, 0, 0, os.SEEK_SET)
    except IOError:
        # lockf抛出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
Example #60
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)
            common.connect_log('UDP data from %s:%d', common.to_str(r_addr[0]), r_addr[1])

            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))
            common.connect_log('UDP data remote to %s:%d', common.to_str(server_addr), server_port)
            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)