• ss源码学习--从协议建立到完成一次代理请求


    上一次介绍了ss源码中各个事件处理函数完成的工作,这次具体分析一下协议的建立以及请求数据的传输过程。

    因为ss的local和server共用一个类以及一系列的事件处理函数,所以看起来稍显复杂。下面来将local和server端结合分析一下。

    首先进程向local端发送发送请求协商版本和认证方法。local端对其响应05 00代表无需认证。

    # local端
    
    ...
    elif is_local and self._stage == STAGE_INIT:
        # TODO check auth method
        # 给进程发送确认信息
        self._write_to_sock(b'x050', self._local_sock)
        # 状态转移至接收地址
        self._stage = STAGE_ADDR
        return
    ...
    

    进程向local端发来请求细节,包含remote的ip和端口等信息。

    # local端
    
    ...
    
        elif cmd == CMD_CONNECT:
            # just trim VER CMD RSV
            # 只截取从第四个字节开始的数据,包含请求访问的ip地址和端口
            data = data[3:]
    ...
    # 提取出地址类型,ip地址,端口号,头部总长度等信息
    header_result = parse_header(data)
    if header_result is None:
        raise Exception('can not parse header')
    addrtype, remote_addr, remote_port, header_length = header_result
    logging.info('connecting %s:%d from %s:%d' %
                    (common.to_str(remote_addr), remote_port,
                    self._client_address[0], self._client_address[1]))
    # 要代理请求的remote地址以及端口号
    self._remote_address = (common.to_str(remote_addr), remote_port)
    # pause reading
    self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
    self._stage = STAGE_DNS
    # local
    if self._is_local:
        # 响应进程
        self._write_to_sock((b'x05x00x00x01'
                                b'x00x00x00x00x10x10'),
                            self._local_sock)
        # data数据包括请求细节,加密发送给server
        data_to_send = self._encryptor.encrypt(data)
        # 要写给server的数据
        self._data_to_write_to_remote.append(data_to_send)
        # notice here may go into _handle_dns_resolved directly
        self._dns_resolver.resolve(self._chosen_server[0],
                                    self._handle_dns_resolved)
    

    local端将进程的请求细节发送给server端

    # local端
    
        def _on_remote_write(self):
            # 进入传输阶段
            self._stage = STAGE_STREAM
            # 如果有需要写的数据
            if self._data_to_write_to_remote:
                data = b''.join(self._data_to_write_to_remote)
                self._data_to_write_to_remote = []
                # 写到server
                self._write_to_sock(data, self._remote_sock)
            else:
                # 否则,更新状态
                self._update_stream(STREAM_UP, WAIT_STATUS_READING)
    
    

    server端接受local发来的加密请求细节,并解密。

    # server端
    
    ...
    if not is_local:
        # 服务端本地sock只可能是客户端发来的请求信息
        # 将数据解密
        data = self._encryptor.decrypt(data)
        if not data:
            return
    
    ...
    
    # 客户端,等待进程发来请求信息,或者服务器端,刚初始化
    elif (is_local and self._stage == STAGE_ADDR) or 
            (not is_local and self._stage == STAGE_INIT):
        # 客户端:接受进程的请求信息,服务器:接受客户端的请求信息
        self._handle_stage_addr(data)
    ...
    ...
    
    # 提取出地址类型,ip地址,端口号,头部总长度等信息
    def _handle_stage_addr(self, data):
    # server端
    
    ...
        header_result = parse_header(data)
        if header_result is None:
            raise Exception('can not parse header')
        addrtype, remote_addr, remote_port, header_length = header_result
        logging.info('connecting %s:%d from %s:%d' %
                        (common.to_str(remote_addr), remote_port,
                        self._client_address[0], self._client_address[1]))
        # 要代理请求的remote地址以及端口号
        self._remote_address = (common.to_str(remote_addr), remote_port)
        # pause reading
        self._update_stream(STREAM_UP, WAIT_STATUS_WRITING)
        self._stage = STAGE_DNS
    
        ...
    
        else:
            # server
            if len(data) > header_length:
                self._data_to_write_to_remote.append(data[header_length:])
            # notice here may go into _handle_dns_resolved directly
            self._dns_resolver.resolve(remote_addr,
                                        self._handle_dns_resolved)
    

    server将解密后的数据发送给remote

    # server端
    
    def _on_remote_write(self):
        # 进入流传输阶段
        self._stage = STAGE_STREAM
        # 如果有需要写的数据
        if self._data_to_write_to_remote:
            data = b''.join(self._data_to_write_to_remote)
            self._data_to_write_to_remote = []
            self._write_to_sock(data, self._remote_sock)
        else:
            # 否则,更新状态
            self._update_stream(STREAM_UP, WAIT_STATUS_READING)
    

    server接收remote的响应,加密后回反给local

    # server端
    
    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))
        
        ...
    
        else:
            # 为server,说明请求信息回反,加密数据
            data = self._encryptor.encrypt(data)
        try:
            # 写到local
            self._write_to_sock(data, self._local_sock)
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            # TODO use logging when debug completed
            self.destroy()
    
    

    local接收server的加密数据,解密后响应给进程。

    # local端
     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))
        # 为client,说明server回反了数据
        if self._is_local:
            # 解密数据
            data = self._encryptor.decrypt(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()
    

    以上就是一次从协议的建立到代理请求访问远程服务器的完整过程。

    有关socks5协议相关内容可以参考:
    https://www.ietf.org/rfc/rfc1928.txt
    http://blog.csdn.net/suifengdeshitou/article/details/48782667

  • 相关阅读:
    活动的生命周期
    活动
    开始编程前的准备工作
    数组转List
    Word根据模板生成数据
    Excel根据模板生成数据
    php取年份区间
    世界 国家 省份 sql
    相册处理,php中获取一组前缀相同的元素值
    mysql添加字段
  • 原文地址:https://www.cnblogs.com/cknightx/p/7595784.html
Copyright © 2020-2023  润新知