Beispiel #1
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         data = encrypt.encrypt_all(self._password, self._method, 0,
                                    data)
         if not data:
             return
         header_result = parse_header(data)
         if header_result is None:
             return
         # connecttype, dest_addr, dest_port, header_length = header_result
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
Beispiel #2
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if self._stat_callback:
         self._stat_callback(self._listen_port, len(data))
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         data = encrypt.encrypt_all(self._password, self._method, 0,
                                    data)
         if not data:
             return
         header_result = parse_header(data)
         if header_result is None:
             return
         addrtype, dest_addr, dest_port, header_length = header_result
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        # 如果是服务端接收到的udp,(例如来自youtube)
        if not self._is_local:
            addrlen = len(r_addr[0])
            # 域名规范:域名不能超过255个字符。其中顶级域名不能超过63字符
            if addrlen > 255:
                # drop
                return
            # pack_addr(r_addr[0]):把r_addr[0]打包成shadowvpn的专用的地址header,追加到r_addr[0]头部。
            # struct.pack('>H', r_addr[1]):打包成Big-Endian格式
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # 加密
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return
            
        # 本地端收到服务端发来的加密udp
        else:
            # 解密
            data = encrypt.encrypt_all(self._password, self._method, 0,
                                       data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            # 还原为标准的udp数据报格式,加上首3个字节
            response = b'\x00\x00\x00' + data
            # data: raw data
            # +------+----------+----------+----------+
            # | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +------+----------+----------+----------+
            # |  1   | Variable |    2     | Variable |
            # +------+----------+----------+----------+
            # response: true udp packet
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            # | 2  |  1   |  1   | Variable |    2     | Variable |
            # +----+------+------+----------+----------+----------+

        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            # 同样的,完美无瑕。。
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #4
0
    def _handle_client(self, sock):

        # receive data from given sock
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        # server prepares response to relay
        # response is composed by data received
        # a remote server relays response to local server
        # 1. use common.pack_addr() to compose udp request header
        # this is because 'Each UDP datagram carries a UDP request header with it'
        # 2. add header before data to compose response
        # 3. encrypt all
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return

        # a local server relays response to local client
        # 1. decrypt data
        # 2. add first 3 bytes to compose a complete udp request header so as to compose response
        # this is because 'Each UDP datagram carries a UDP request header with it'
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0,
                                       data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            response = b'\x00\x00\x00' + data

        # relay the response
        # note how self._client_fd_to_server_addr is composed in _handle_server()
        # to conclude, client_addr is where a server receives request from
        # a local server receives request from local client
        # a remote server receives request from local server
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #5
0
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        # 如果是服务端接收到的udp,(例如来自youtube)
        if not self._is_local:
            addrlen = len(r_addr[0])
            # 域名规范:域名不能超过255个字符。其中顶级域名不能超过63字符
            if addrlen > 255:
                # drop
                return
            # pack_addr(r_addr[0]):把r_addr[0]打包成shadowvpn的专用的地址header,追加到r_addr[0]头部。
            # struct.pack('>H', r_addr[1]):打包成Big-Endian格式
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # 加密
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return

        # 本地端收到服务端发来的加密udp
        else:
            # 解密
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            # 还原为标准的udp数据报格式,加上首3个字节
            response = b'\x00\x00\x00' + data
            # data: raw data
            # +------+----------+----------+----------+
            # | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +------+----------+----------+----------+
            # |  1   | Variable |    2     | Variable |
            # +------+----------+----------+----------+
            # response: true udp packet
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            # | 2  |  1   |  1   | Variable |    2     | Variable |
            # +----+------+------+----------+----------+----------+

        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            # 同样的,完美无瑕。。
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #6
0
    def _handle_client(self, sock):

        # receive data from given sock
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        # server prepares response to relay
        # response is composed by data received
        # a remote server relays response to local server
        # 1. use common.pack_addr() to compose udp request header
        # this is because 'Each UDP datagram carries a UDP request header with it'
        # 2. add header before data to compose response
        # 3. encrypt all
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return

        # a local server relays response to local client
        # 1. decrypt data
        # 2. add first 3 bytes to compose a complete udp request header so as to compose response
        # this is because 'Each UDP datagram carries a UDP request header with it'
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            response = b'\x00\x00\x00' + data

        # relay the response
        # note how self._client_fd_to_server_addr is composed in _handle_server()
        # to conclude, client_addr is where a server receives request from
        # a local server receives request from local client
        # a remote server receives request from local server
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #7
0
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        # ssserver
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            # |    pack_addr    |   pack   |
            # .                 .          .
            # +------+----------+----------+----------+
            # | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +------+----------+----------+----------+
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # `1` 表示加密
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return
        #sslocal
        else:
            # `0` 表示解密
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            addrtype, dest_addr, dest_port, header_length = header_result

            # \x00\x00\x00
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            #             .                                       .
            #             |<--------------- data ---------------->|
            response = b'\x00\x00\x00' + data
        # 这里的 sock 就是 _handle_server 中的 client
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        # 通过 _server_socket 将数据发送到 client 对应的地址
        if client_addr:
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        # If it is from remote
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # Encrypt the data
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return
        else:
            # Decrypt the data
            data = encrypt.encrypt_all(self._password, self._method, 0,
                                       data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            response = b'\x00\x00\x00' + data

# 两个报文差3个字节的数据怎么办?加上去!客户端是有构造和识别SOCK5报文的能力的
# If the the message lost 3 bytes data, the client will add it.
# Because the client has the ability to recognize and construct SOCKS5 message
# +----+------+------+----------+----------+----------+
# |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +----+------+------+----------+----------+----------+
# | 2  |  1   |  1   | Variable |    2     | Variable |
# +----+------+------+----------+----------+----------+
# +------+----------+----------+----------+
# | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +------+----------+----------+----------+
# |  1   | Variable |    2     | Variable |
# +------+----------+----------+----------+

            # Here is the real data
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        # 如果是远程
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # 加密内容
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return
        else:
            # 解密
            data = encrypt.encrypt_all(self._password, self._method, 0,
                                       data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            response = b'\x00\x00\x00' + data

# 两个报文差3个字节的数据怎么办?加上去!客户端是有构造和识别SOCK5报文的能力的
# +----+------+------+----------+----------+----------+
# |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +----+------+------+----------+----------+----------+
# | 2  |  1   |  1   | Variable |    2     | Variable |
# +----+------+------+----------+----------+----------+
# +------+----------+----------+----------+
# | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +------+----------+----------+----------+
# |  1   | Variable |    2     | Variable |
# +------+----------+----------+----------+

            # 这里是真正的数据 
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            # 同样的,完美无瑕。。
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #10
0
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        # 如果是远程
        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            # 加密内容
            response = encrypt.encrypt_all(self._password, self._method, 1,
                                           data)
            if not response:
                return
        else:
            # 解密
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            if not data:
                return
            header_result = parse_header(data)
            if header_result is None:
                return
            # addrtype, dest_addr, dest_port, header_length = header_result
            response = b'\x00\x00\x00' + data

# 两个报文差3个字节的数据怎么办?加上去!客户端是有构造和识别SOCK5报文的能力的
# +----+------+------+----------+----------+----------+
# |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +----+------+------+----------+----------+----------+
# | 2  |  1   |  1   | Variable |    2     | Variable |
# +----+------+------+----------+----------+----------+
# +------+----------+----------+----------+
# | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +------+----------+----------+----------+
# |  1   | Variable |    2     | Variable |
# +------+----------+----------+----------+

# 这里是真正的数据
        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        if client_addr:
            # 同样的,完美无瑕。。
            self._server_socket.sendto(response, client_addr)
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #11
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         data = encrypt.encrypt_all(self._password, self._method, 0, data)
         if not data:
             return
         header_result = parse_header(data, self._config)
         if header_result is None:
             return
         # addrtype, dest_addr, dest_port, header_length = header_result
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
         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:
                     port_limits['%s' %
                                 self._listen_port]['used'] = port_limits[
                                     '%s' %
                                     self._listen_port]['used'] + len(
                                         response) + BUF_SIZE
                     open('%s' % self._config['port_limit'],
                          "w").write("%s" % json.dumps(port_limits,
                                                       indent=4,
                                                       ensure_ascii=False,
                                                       sort_keys=True))
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
Beispiel #12
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if self._stat_callback:
         self._stat_callback(self._listen_port, len(data))
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         data = encrypt.encrypt_all(self._password, self._method, 0,
                                    data)
         if not data:
             return
         header_result = parse_header(data)
         if header_result is None:
             return
         addrtype, dest_addr, dest_port, header_length = header_result
         # spec https://shadowsocks.org/en/spec/one-time-auth.html
         if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH:
             if len(data) < header_length + ONETIMEAUTH_BYTES:
                 logging.warn('one time auth header is too short')
                 return None
             if onetimeauth_verify(data[-ONETIMEAUTH_BYTES:],
                                   data[header_length: -ONETIMEAUTH_BYTES],
                                   self._encryptor.decipher_iv + self._encryptor.key) is False:
                 logging.warn('one time auth fail')
                 return None
             self._one_time_authed = True
             header_length += ONETIMEAUTH_BYTES
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
Beispiel #13
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if self._stat_callback:
         self._stat_callback(self._listen_port, len(data))
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         # note(yan): 这里data就是udp data, 没有任何结构
         # 先变成为ss udp response, 然后encrypt it.
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         # note(yan): 如果是local的话,那么收到的是remote传过来的
         # ss encrypted data -> ss udp response. 然后加上\x00\x00\x00
         # 变为socks5 udp response.
         data = encrypt.encrypt_all(self._password, self._method, 0, data)
         if not data:
             return
         header_result = parse_header(data)
         if header_result is None:
             return
         # addrtype, dest_addr, dest_port, header_length = header_result
         # note(yan): socks5 UDP response
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
Beispiel #14
0
 def _handle_client(self, sock):
     data, r_addr = sock.recvfrom(BUF_SIZE)
     if not data:
         logging.debug('UDP handle_client: data is empty')
         return
     if not self._is_local:
         addrlen = len(r_addr[0])
         if addrlen > 255:
             # drop
             return
         data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
         response = encrypt.encrypt_all(self._password, self._method, 1,
                                        data)
         if not response:
             return
     else:
         data = encrypt.encrypt_all(self._password, self._method, 0,
                                    data)
         if not data:
             return
         header_result = parse_header(data,self._config)
         if header_result is None:
             return
         # addrtype, dest_addr, dest_port, header_length = header_result
         response = b'\x00\x00\x00' + data
     client_addr = self._client_fd_to_server_addr.get(sock.fileno())
     if client_addr:
         self._server_socket.sendto(response, client_addr)
         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:
                     port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._listen_port]['used'] + len(response) + BUF_SIZE
                     open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True))
     else:
         # this packet is from somewhere else we know
         # simply drop that packet
         pass
Beispiel #15
0
 def _handle_local(self, sock):
     data, addr = sock.recvfrom(BUF_SIZE)
     header = asyncdns.parse_header(data)
     if header:
         try:
             req_id = header[0]
             req = asyncdns.parse_response(data)
             self._id_to_addr[req_id] = addr
             data = self._address_to_send + data
             data = encrypt.encrypt_all(self._config['password'],
                                        self._config['method'], 1, data)
             self._remote_sock.sendto(data, self._remote_addr)
             logging.info('request %s', req.hostname)
         except Exception as e:
             import traceback
             traceback.print_exc()
             logging.error(e)
Beispiel #16
0
 def _handle_local(self, sock):
     data, addr = sock.recvfrom(BUF_SIZE)
     header = asyncdns.parse_header(data)
     if header:
         try:
             req_id = header[0]
             req = asyncdns.parse_response(data)
             self._id_to_addr[req_id] = addr
             data = self._address_to_send + data
             data = encrypt.encrypt_all(self._config['password'],
                                        self._config['method'], 1, data)
             self._remote_sock.sendto(data, self._remote_addr)
             logging.info('request %s', req.hostname)
         except Exception as e:
             import traceback
             traceback.print_exc()
             logging.error(e)
Beispiel #17
0
 def _handle_remote(self, sock):
     data, addr = sock.recvfrom(BUF_SIZE)
     if data:
         try:
             data = encrypt.encrypt_all(self._config['password'],
                                        self._config['method'], 0, data)
             header_result = parse_header(data)
             if header_result is None:
                 return None, None
             addrtype, dest_addr, dest_port, header_length = header_result
             data = data[header_length:]
             header = asyncdns.parse_header(data)
             if header:
                 req_id = header[0]
                 res = asyncdns.parse_response(data)
                 addr = self._id_to_addr.get(req_id, None)
                 if addr:
                     self._local_sock.sendto(data, addr)
                     del self._id_to_addr[req_id]
                 logging.info('response %s', res)
         except Exception as e:
             import traceback
             traceback.print_exc()
             logging.error(e)
Beispiel #18
0
 def _handle_remote(self, sock):
     data, addr = sock.recvfrom(BUF_SIZE)
     if data:
         try:
             data = encrypt.encrypt_all(self._config['password'],
                                        self._config['method'], 0, data)
             header_result = parse_header(data)
             if header_result is None:
                 return None, None
             addrtype, dest_addr, dest_port, header_length = header_result
             data = data[header_length:]
             header = asyncdns.parse_header(data)
             if header:
                 req_id = header[0]
                 res = asyncdns.parse_response(data)
                 addr = self._id_to_addr.get(req_id, None)
                 if addr:
                     self._local_sock.sendto(data, addr)
                     del self._id_to_addr[req_id]
                 logging.info('response %s', res)
         except Exception as e:
             import traceback
             traceback.print_exc()
             logging.error(e)
Beispiel #19
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return

        if not self._is_local:
            data = pre_parse_header(data)
            if data is None:
                return

        header_result = parse_header(data)
        if header_result is None:
            return
        connecttype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            server_addr, server_port = self._get_a_server()
            key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        else:
            server_addr, server_port = dest_addr, dest_port
            addrs = socket.getaddrinfo(dest_addr, dest_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                key = client_key(r_addr[0], r_addr[1], af, 0)
            else:
                key = None

        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            #logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port))
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                if self._forbidden_iplist:
                    if common.to_str(sa[0]) in self._forbidden_iplist:
                        logging.debug('IP %s is in forbidden list, drop' %
                                      common.to_str(sa[0]))
                        # drop
                        return
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN)

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #20
0
    def _handle_client(self, sock):
        data, r_addr = sock.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_client: data is empty')
            return
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        client_addr = self._client_fd_to_server_addr.get(sock.fileno())
        client_uid = None
        if client_addr:
            key = client_key(client_addr[0], client_addr[1])
            client_pair = self._cache.get(key, None)
            client_dns_pair = self._cache_dns_client.get(key, None)
            if client_pair:
                client, client_uid = client_pair
            elif client_dns_pair:
                client, client_uid = client_dns_pair

        if not self._is_local:
            addrlen = len(r_addr[0])
            if addrlen > 255:
                # drop
                return
            data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
            try:
                ref_iv = [encrypt.encrypt_new_iv(self._method)]
                self._protocol.obfs.server_info.iv = ref_iv[0]
                data = self._protocol.server_udp_pre_encrypt(data, client_uid)
                response = encrypt.encrypt_all(self._password, self._method,
                                               data)
            except Exception:
                logging.debug("UDP handle_client: encrypt data failed")
                return
            if not response:
                return
        else:
            try:
                data, key, ref_iv = encrypt.decrypt_all(
                    self._password, self._method, data)
            except Exception:
                logging.debug('UDP handle_client: decrypt data failed')
                return
            if not data:
                return
            self._protocol.obfs.server_info.recv_iv = ref_iv[0]
            data = self._protocol.client_udp_post_decrypt(data)
            header_result = parse_header(data)
            if header_result is None:
                return
            #connecttype, dest_addr, dest_port, header_length = header_result
            #logging.debug('UDP handle_client %s:%d to %s:%d' % (common.to_str(r_addr[0]), r_addr[1], dest_addr, dest_port))

            response = b'\x00\x00\x00' + data

        if client_addr:
            if client_uid:
                self.add_transfer_d(client_uid, len(response))
            else:
                self.server_transfer_dl += len(response)
            self.write_to_server_socket(response, client_addr[0])
            if client_dns_pair:
                logging.debug("remove dns client %s:%d" %
                              (client_addr[0][0], client_addr[0][1]))
                del self._cache_dns_client[key]
                self._close_client(client_dns_pair[0])
        else:
            # this packet is from somewhere else we know
            # simply drop that packet
            pass
Beispiel #21
0
def test():
    import time
    import threading
    import struct
    from shadowsocks import encrypt

    logging.basicConfig(level=5,
                        format='%(asctime)s %(levelname)-8s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    enc = []
    eventloop.TIMEOUT_PRECISION = 1

    def run_server():
        config = {
            'server': '127.0.0.1',
            'local_port': 1081,
            'port_password': {
                '8381': 'foobar1',
                '8382': 'foobar2'
            },
            'method': 'aes-256-cfb',
            'manager_address': '127.0.0.1:6001',
            'timeout': 60,
            'fast_open': False,
            'verbose': 2
        }
        manager = Manager(config)
        enc.append(manager)
        manager.run()

    t = threading.Thread(target=run_server)
    t.start()
    time.sleep(1)
    manager = enc[0]
    cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    cli.connect(('127.0.0.1', 6001))

    # test add and remove
    time.sleep(1)
    cli.send(b'add: {"server_port":7001, "password":"******"}')
    time.sleep(1)
    assert 7001 in manager._relays
    data, addr = cli.recvfrom(1506)
    assert b'ok' in data

    cli.send(b'remove: {"server_port":8381}')
    time.sleep(1)
    assert 8381 not in manager._relays
    data, addr = cli.recvfrom(1506)
    assert b'ok' in data
    logging.info('add and remove test passed')

    # test statistics for TCP
    header = common.pack_addr(b'google.com') + struct.pack('>H', 80)
    data = encrypt.encrypt_all(b'asdfadsfasdf', 'aes-256-cfb', 1,
                               header + b'GET /\r\n\r\n')
    tcp_cli = socket.socket()
    tcp_cli.connect(('127.0.0.1', 7001))
    tcp_cli.send(data)
    tcp_cli.recv(4096)
    tcp_cli.close()

    data, addr = cli.recvfrom(1506)
    data = common.to_str(data)
    assert data.startswith('stat: ')
    data = data.split('stat:')[1]
    stats = shell.parse_json_in_str(data)
    assert '7001' in stats
    logging.info('TCP statistics test passed')

    # test statistics for UDP
    header = common.pack_addr(b'127.0.0.1') + struct.pack('>H', 80)
    data = encrypt.encrypt_all(b'foobar2', 'aes-256-cfb', 1, header + b'test')
    udp_cli = socket.socket(type=socket.SOCK_DGRAM)
    udp_cli.sendto(data, ('127.0.0.1', 8382))
    tcp_cli.close()

    data, addr = cli.recvfrom(1506)
    data = common.to_str(data)
    assert data.startswith('stat: ')
    data = data.split('stat:')[1]
    stats = json.loads(data)
    assert '8382' in stats
    logging.info('UDP statistics test passed')

    manager._loop.stop()
    t.join()
Beispiel #22
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('UDP drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH:
                if len(data) < header_length + ONETIMEAUTH_BYTES:
                    logging.warn('UDP one time auth header is too short')
                    return
                _hash = data[-ONETIMEAUTH_BYTES:]
                _data = data[header_length:-ONETIMEAUTH_BYTES]
                _key = self._encryptor.decipher_iv + self._encryptor.key
                if onetimeauth_verify(_hash, _data, _key) is False:
                    logging.warn('UDP one time auth fail')
                    return
                self._one_time_authed = True
                header_length += ONETIMEAUTH_BYTES
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

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

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

        if self._is_local:
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable:
                data = self._one_time_auth_chunk_data_gen(data)
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #23
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('UDP drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug(
                    'UDP handle_server: data is empty after decrypt'
                )
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH:
                if len(data) < header_length + ONETIMEAUTH_BYTES:
                    logging.warn('UDP one time auth header is too short')
                    return
                _hash = data[-ONETIMEAUTH_BYTES:]
                _data = data[header_length: -ONETIMEAUTH_BYTES]
                _key = self._encryptor.decipher_iv + self._encryptor.key
                if onetimeauth_verify(_hash, _data, _key) is False:
                    logging.warn('UDP one time auth fail')
                    return
                self._one_time_authed = True
                header_length += ONETIMEAUTH_BYTES
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs

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

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

        if self._is_local:
            # spec https://shadowsocks.org/en/spec/one-time-auth.html
            if self._one_time_auth_enable:
                data = self._one_time_auth_chunk_data_gen(data)
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #24
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        # note(yan): server接受到数据
        if self._is_local:
            # note(yan): 如果是local的话,收到的是SOCKS5 UDP request.
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            # note(yan): 否则,收到的是shadowsocks encrypted udp request.
            # 注意ss udp request的后半段,和socks5 udp request完全一致
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        # note(yan): 如果是local的话,那么dest_addr/port在配置中
        # 否则dest_addr/port在请求里面
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port

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

        af, socktype, proto, canonname, sa = addrs[0]
        # note(yan): 找到对应的proxy client. 所有的proxy都需要管理
        # <c, c>这样的pair集合
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

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

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #25
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                common.error_to_file('drop a message since frag is not 0',self._config)
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data,self._config)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

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

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

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)

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

            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN, self)
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
            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:
                        port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._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 IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #26
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            # 如果是local收到,那就是
            frag = common.ord(data[2])
            # this is no classic UDP
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            # | 2  |  1   |  1   | Variable |    2     | Variable |
            # +----+------+------+----------+----------+----------+
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
                # [3:]之后变成
# +------+----------+----------+----------+
# | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +------+----------+----------+----------+
# |  1   | Variable |    2     | Variable |
# +------+----------+----------+----------+
# 就是shadowsocks那段
        else:
            # 如果是远程收到
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            # 如果是local收到,则server_addr server_port都是远程的
            server_addr, server_port = self._get_a_server()
        else:
            # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作
            server_addr, server_port = dest_addr, dest_port

        key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            # 根据server_addr, server_port等的类型决定选用的协议类型
            # Translate the host/port argument into a sequence of 5-tuples
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                # 根据上面的server_addr, server_port建立相应的连接,一环扣一环
                # 这里是主动发出请求,所以要新建一个socket

                # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN)

        if self._is_local:
            # 如果是local,要向远程发,要过墙,所以要加密
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            # 如果是远程,要向dest发请求,所以把除数据的部分除去
            data = data[header_length:]
        if not data:
            return
        try:
            # 发送,完美无瑕。。。。
            # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                logging.error(e)
Beispiel #27
0
    def _handle_server(self):
        server = self._server_socket

        # receive request
        # note that no listen()/accept() is used as TCP
        # this is because udp doesn't require long-lived connection
        # so the server does not need to listen for and accept connections
        # It only needs to use bind() to associate its socket with a port
        # and then wait for individual messages
        # _server_socket has been bound in __init__()
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        # for a local server, request is from local client
        # if the datagram isnot standalone, drop it
        if self._is_local:

            frag = common.ord(data[2])
            # FRAG    Current fragment number
            # ord() converts it back to number
            # The FRAG field indicates whether or not this datagram is one of a number of fragments.
            # Implementation of fragmentation is optional; an implementation that
            # does not support fragmentation MUST drop any datagram whose FRAG field is other than X'00'.

            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]

        # for a remote server, request is from local server
        # decrypt it
        # note that no removal of first 3 bytes canbe found here, guess in decryption?
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return

        # for both local and remote server, analyse request header
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        # set a place where a server relays request to
        # a local server relays request to remote server
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        # a remote server relays request to dest, extracted from request header
        else:
            server_addr, server_port = dest_addr, dest_port

        # try to find send-socket from cache
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs
        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)

        # if not found in the cache, init a new send-socket
        # add it to the eventloop
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

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

        # process the request before relay
        # a local server relays request to remote server
        # so request should be encrypted
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        # a remote server relays request to dest
        # note that request has been decrypted before
        # so just relays it
        # note that udp request header is removed
        else:
            data = data[header_length:]
        if not data:
            return

        # relay the request using send-socket
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #28
0
    def _handle_server(self):
        # 客户端发给服务器的数据
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result
        logging.info("UDP to %s %s" % (str(dest_addr), str(dest_port)))
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        else:
            server_addr, server_port = dest_addr, dest_port

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

        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        open_socks5 = False
        # for socks5 transform
        # TODO: this is a bug
        if not self._is_local and self._config["socks5-relay"] and self._config["socks5-config"]:
            open_socks5 = True
        
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return

            if open_socks5:
                client = self._create_remote_socket_for_socks5relay(server_addr, server_port)
            else:
                client = socket.socket(af, socktype, proto)

            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

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

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        
        if open_socks5:
            self.thread_pool.submit(async_send_to, client, data, server_addr, server_port)
        else:       
            try:
                client.sendto(data, (server_addr, server_port))
            except IOError as e:
                err = eventloop.errno_from_exception(e)
                if err in (errno.EINPROGRESS, errno.EAGAIN):
                    pass
                else:
                    shell.print_exception(e)
    def _handle_server(self):
        """
        服务器有UDP连接
        :return:
        """
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

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

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

        af, socktype, proto, canonname, sa = addrs[0]
        # 给这个客户端返回一个唯一值而已,一个字符串
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            # 记录client的关键字
            self._cache[key] = client
            # 记录client的文件描述符对应的转发地址,若client收到响应udp包则转发到这个地址
            self._client_fd_to_server_addr[client.fileno()] = r_addr

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

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
Beispiel #30
0
    def _handle_server(self):
        server = self._server_socket
        # r_addr是发送者的地址
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')

        # 若本地端从监听1080端口收到本机应用进程(例如chrome)的数据,进行切除header
        if self._is_local:
            # ord:输入char返回Ascii
            frag = common.ord(data[2])
            # this is no classic UDP
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            # | 2  |  1   |  1   | Variable |    2     | Variable |
            # +----+------+------+----------+----------+----------+
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
                # [3:]之后变成
                # +------+----------+----------+----------+
                # | ATYP | DST.ADDR | DST.PORT |   DATA   |
                # +------+----------+----------+----------+
                # |  1   | Variable |    2     | Variable |
                # +------+----------+----------+----------+
                # 就是shadowsocks那段

        # 如果是服务端收到本地端发出的udp数据,先进行解密
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        # 处理header
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            # 如果是local收到,则server_addr server_port都是远程的
            server_addr, server_port = self._get_a_server()
        else:
            # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作
            # dest就是最终目标,例如 www.youtube.com:443
            server_addr, server_port = dest_addr, dest_port
        # r_addr[]是接收到的数据
        key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        client = self._cache.get(key, None)
        # 若callback字典中没有相关记录,进行注册字典
        if not client:
            # TODO async getaddrinfo
            # 根据server_addr, server_port等的类型决定选用的协议类型
            # Translate the host/port argument into a sequence of 5-tuples
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                # 根据上面的server_addr, server_port建立相应的连接,一环扣一环
                # 这里是主动发出请求,所以要新建一个socket
                # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            # sockets是一个set集合
            self._sockets.add(client.fileno())
            # 添加进Eventloop,标志设置为可读
            self._eventloop.add(client, eventloop.POLL_IN)

        # 如果是local,要向远程发,要过墙,所以要加密
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        # 如果是远程,要向dest发请求,所以把除数据的部分除去,即除去header。
        else:
            # data已经在上面进行数据解密了。不需要像local一样加密发送。
            # data已经被切除头的3个字节了
            data = data[header_length:]

        if not data:
            return

        try:
            # 发送,完美无瑕。。。。
            # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了
            # 调用sendto时候会自动加上那个首3个字节,貌似是x00 x00 x00
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                logging.error(e)
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            # if local receives this request, then:
            frag = common.ord(data[2])
# this is no classic UDP
# +----+------+------+----------+----------+----------+
# |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +----+------+------+----------+----------+----------+
# | 2  |  1   |  1   | Variable |    2     | Variable |
# +----+------+------+----------+----------+----------+
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
                # after [3:]
# +------+----------+----------+----------+
# | ATYP | DST.ADDR | DST.PORT |   DATA   |
# +------+----------+----------+----------+
# |  1   | Variable |    2     | Variable |
# +------+----------+----------+----------+
# 就是shadowsocks那段
        else:
            # If remote receives
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt the data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            # 如果是local收到,则server_addr server_port都是远程的
            server_addr, server_port = self._get_a_server()
        else:
            # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作
            server_addr, server_port = dest_addr, dest_port

        key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            # 根据server_addr, server_port等的类型决定选用的协议类型
            # Translate the host/port argument into a sequence of 5-tuples
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                # 根据上面的server_addr, server_port建立相应的连接,一环扣一环
                # 这里是主动发出请求,所以要新建一个socket

                # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN)

        if self._is_local:
            # 如果是local,要向远程发,要过墙,所以要加密
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            # 如果是远程,要向dest发请求,所以把除数据的部分除去
            data = data[header_length:]
        if not data:
            return
        try:
            # Send the data
            # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                logging.error(e)
Beispiel #32
0
def test():
    import time
    import threading
    import struct
    from shadowsocks import encrypt

    logging.basicConfig(level=5,
                        format='%(asctime)s %(levelname)-8s %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    enc = []
    eventloop.TIMEOUT_PRECISION = 1

    def run_server():
        config = {
            'server': '127.0.0.1',
            'local_port': 1081,
            'port_password': {
                '8381': 'foobar1',
                '8382': 'foobar2'
            },
            'method': 'aes-256-cfb',
            'manager_address': '127.0.0.1:6001',
            'timeout': 60,
            'fast_open': False,
            'verbose': 2
        }
        manager = Manager(config)
        enc.append(manager)
        manager.run()

    t = threading.Thread(target=run_server)
    t.start()
    time.sleep(1)
    manager = enc[0]
    cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    cli.connect(('127.0.0.1', 6001))

    # test add and remove
    time.sleep(1)
    cli.send(b'add: {"server_port":7001, "password":"******"}')
    time.sleep(1)
    assert 7001 in manager._relays
    data, addr = cli.recvfrom(1506)
    assert b'ok' in data

    cli.send(b'remove: {"server_port":8381}')
    time.sleep(1)
    assert 8381 not in manager._relays
    data, addr = cli.recvfrom(1506)
    assert b'ok' in data
    logging.info('add and remove test passed')

    # test statistics for TCP
    header = common.pack_addr(b'google.com') + struct.pack('>H', 80)
    data = encrypt.encrypt_all(b'asdfadsfasdf', 'aes-256-cfb', 1,
                               header + b'GET /\r\n\r\n')
    tcp_cli = socket.socket()
    tcp_cli.connect(('127.0.0.1', 7001))
    tcp_cli.send(data)
    tcp_cli.recv(4096)
    tcp_cli.close()

    data, addr = cli.recvfrom(1506)
    data = common.to_str(data)
    assert data.startswith('stat: ')
    data = data.split('stat:')[1]
    stats = shell.parse_json_in_str(data)
    assert '7001' in stats
    logging.info('TCP statistics test passed')

    # test statistics for UDP
    header = common.pack_addr(b'127.0.0.1') + struct.pack('>H', 80)
    data = encrypt.encrypt_all(b'foobar2', 'aes-256-cfb', 1,
                               header + b'test')
    udp_cli = socket.socket(type=socket.SOCK_DGRAM)
    udp_cli.sendto(data, ('127.0.0.1', 8382))
    tcp_cli.close()

    data, addr = cli.recvfrom(1506)
    data = common.to_str(data)
    assert data.startswith('stat: ')
    data = data.split('stat:')[1]
    stats = json.loads(data)
    assert '8382' in stats
    logging.info('UDP statistics test passed')

    manager._loop.stop()
    t.join()
Beispiel #33
0
    def _handle_server(self):
        server = self._server_socket
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._is_local:
            frag = common.ord(data[2])
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

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

        key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        client = self._cache.get(key, None)
        if not client:
            # TODO async getaddrinfo
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                if self._forbidden_iplist:
                    if common.to_str(sa[0]) in self._forbidden_iplist:
                        logging.debug('IP %s is in forbidden list, drop' %
                                      common.to_str(sa[0]))
                        # drop
                        return
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            self._sockets.add(client.fileno())
            self._eventloop.add(client, eventloop.POLL_IN)

        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        else:
            data = data[header_length:]
        if not data:
            return
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)
    def _handle_server(self):
        server = self._server_socket
        # r_addr是发送者的地址
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
            
        # 若本地端从监听1080端口收到本机应用进程(例如chrome)的数据,进行切除header
        if self._is_local:
            # ord:输入char返回Ascii
            frag = common.ord(data[2])
            # this is no classic UDP
            # +----+------+------+----------+----------+----------+
            # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
            # +----+------+------+----------+----------+----------+
            # | 2  |  1   |  1   | Variable |    2     | Variable |
            # +----+------+------+----------+----------+----------+
            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]
                # [3:]之后变成
                # +------+----------+----------+----------+
                # | ATYP | DST.ADDR | DST.PORT |   DATA   |
                # +------+----------+----------+----------+
                # |  1   | Variable |    2     | Variable |
                # +------+----------+----------+----------+
                # 就是shadowsocks那段
                
        # 如果是服务端收到本地端发出的udp数据,先进行解密
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)            
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return
        # 处理header
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        if self._is_local:
            # 如果是local收到,则server_addr server_port都是远程的
            server_addr, server_port = self._get_a_server()
        else:
            # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作
            # dest就是最终目标,例如 www.youtube.com:443
            server_addr, server_port = dest_addr, dest_port
        # r_addr[]是接收到的数据
        key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port)
        client = self._cache.get(key, None)
        # 若callback字典中没有相关记录,进行注册字典
        if not client:
            # TODO async getaddrinfo
            # 根据server_addr, server_port等的类型决定选用的协议类型
            # Translate the host/port argument into a sequence of 5-tuples
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if addrs:
                af, socktype, proto, canonname, sa = addrs[0]
                # 根据上面的server_addr, server_port建立相应的连接,一环扣一环
                # 这里是主动发出请求,所以要新建一个socket
                # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的
                client = socket.socket(af, socktype, proto)
                client.setblocking(False)
                self._cache[key] = client
                self._client_fd_to_server_addr[client.fileno()] = r_addr
            else:
                # drop
                return
            # sockets是一个set集合
            self._sockets.add(client.fileno())
            # 添加进Eventloop,标志设置为可读
            self._eventloop.add(client, eventloop.POLL_IN)
        
        # 如果是local,要向远程发,要过墙,所以要加密
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        # 如果是远程,要向dest发请求,所以把除数据的部分除去,即除去header。
        else:
            # data已经在上面进行数据解密了。不需要像local一样加密发送。
            # data已经被切除头的3个字节了
            data = data[header_length:]

        if not data:
            return
        
        try:
            # 发送,完美无瑕。。。。
            # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了
            # 调用sendto时候会自动加上那个首3个字节,貌似是x00 x00 x00
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                logging.error(e)
Beispiel #35
0
    def _handle_server(self):
        server = self._server_socket

        # receive request
        # note that no listen()/accept() is used as TCP
        # this is because udp doesn't require long-lived connection
        # so the server does not need to listen for and accept connections
        # It only needs to use bind() to associate its socket with a port
        # and then wait for individual messages
        # _server_socket has been bound in __init__()
        data, r_addr = server.recvfrom(BUF_SIZE)
        if not data:
            logging.debug('UDP handle_server: data is empty')
        if self._stat_callback:
            self._stat_callback(self._listen_port, len(data))

        # for a local server, request is from local client
        # if the datagram isnot standalone, drop it
        if self._is_local:

            frag = common.ord(data[2])
            # FRAG    Current fragment number
            # ord() converts it back to number
            # The FRAG field indicates whether or not this datagram is one of a number of fragments.
            # Implementation of fragmentation is optional; an implementation that
            # does not support fragmentation MUST drop any datagram whose FRAG field is other than X'00'.

            if frag != 0:
                logging.warn('drop a message since frag is not 0')
                return
            else:
                data = data[3:]

        # for a remote server, request is from local server
        # decrypt it
        # note that no removal of first 3 bytes canbe found here, guess in decryption?
        else:
            data = encrypt.encrypt_all(self._password, self._method, 0, data)
            # decrypt data
            if not data:
                logging.debug('UDP handle_server: data is empty after decrypt')
                return

        # for both local and remote server, analyse request header
        header_result = parse_header(data)
        if header_result is None:
            return
        addrtype, dest_addr, dest_port, header_length = header_result

        # set a place where a server relays request to
        # a local server relays request to remote server
        if self._is_local:
            server_addr, server_port = self._get_a_server()
        # a remote server relays request to dest, extracted from request header
        else:
            server_addr, server_port = dest_addr, dest_port

        # try to find send-socket from cache
        addrs = self._dns_cache.get(server_addr, None)
        if addrs is None:
            addrs = socket.getaddrinfo(server_addr, server_port, 0,
                                       socket.SOCK_DGRAM, socket.SOL_UDP)
            if not addrs:
                # drop
                return
            else:
                self._dns_cache[server_addr] = addrs
        af, socktype, proto, canonname, sa = addrs[0]
        key = client_key(r_addr, af)
        client = self._cache.get(key, None)

        # if not found in the cache, init a new send-socket
        # add it to the eventloop
        if not client:
            # TODO async getaddrinfo
            if self._forbidden_iplist:
                if common.to_str(sa[0]) in self._forbidden_iplist:
                    logging.debug('IP %s is in forbidden list, drop' %
                                  common.to_str(sa[0]))
                    # drop
                    return
            client = socket.socket(af, socktype, proto)
            client.setblocking(False)
            self._cache[key] = client
            self._client_fd_to_server_addr[client.fileno()] = r_addr

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

        # process the request before relay
        # a local server relays request to remote server
        # so request should be encrypted
        if self._is_local:
            data = encrypt.encrypt_all(self._password, self._method, 1, data)
            if not data:
                return
        # a remote server relays request to dest
        # note that request has been decrypted before
        # so just relays it
        # note that udp request header is removed
        else:
            data = data[header_length:]
        if not data:
            return

        # relay the request using send-socket
        try:
            client.sendto(data, (server_addr, server_port))
        except IOError as e:
            err = eventloop.errno_from_exception(e)
            if err in (errno.EINPROGRESS, errno.EAGAIN):
                pass
            else:
                shell.print_exception(e)