Exemplo n.º 1
0
 def xor(cls, data: Data, factor: Data) -> Optional[Data]:
     if data.get_byte(0) != 0:
         return None
     data_buffer = data._buffer
     data_offset = data._offset
     data_length = data._length
     fact_buffer = factor._buffer
     fact_offset = factor._offset
     fact_length = factor._length
     assert data_length == 8 or data_length == 20, 'address error: %s' % data
     assert fact_length == 16, 'factor should be the "magic code" + "(96-bits) transaction ID": %s' % factor
     array = bytearray(data_length)
     # family
     array[1] = data_buffer[data_offset + 1]
     # X-Port
     array[2] = data_buffer[data_offset + 2] ^ fact_buffer[fact_offset + 0]
     array[3] = data_buffer[data_offset + 3] ^ fact_buffer[fact_offset + 1]
     # X-Address
     a_pos = 4
     f_pos = 0
     while a_pos < data_length:
         array[a_pos] = data_buffer[data_offset +
                                    a_pos] ^ fact_buffer[fact_offset +
                                                         f_pos]
         a_pos += 1
         f_pos += 1
     return Data(data=array)
Exemplo n.º 2
0
 def parse(cls, data: Data):
     if data.length < 2 or (data.get_byte(index=1) & 0x03) != 0:
         # format: xxxx xxxx, xxxx xx00
         return None
     elif data.length > 2:
         data = data.slice(end=2)
     return cls(data=data)
Exemplo n.º 3
0
 def data_to_ipv4(cls, address: Data) -> str:
     # IPv4
     assert address.length == 4, 'IPv4 data error: %s' % address
     return '.'.join([
         str(address.get_byte(index=0)),
         str(address.get_byte(index=1)),
         str(address.get_byte(index=2)),
         str(address.get_byte(index=3)),
     ])
Exemplo n.º 4
0
 def parse(cls, data: Data):
     if data.length < 2:
         return None
     elif data.length > 2:
         data = data.slice(end=2)
     value = data.get_uint16_value()
     t = cls.__attribute_types.get(value)
     if t is None:
         return cls(value=value, data=data)
     else:
         return t
Exemplo n.º 5
0
 def parse(cls, data: Data):
     if data.length < 2 or (data.get_byte(index=0) & 0xC0) != 0:
         # format: 00xx xxxx, xxxx xxxx
         return None
     elif data.length > 2:
         data = data.slice(end=2)
     value = data.get_uint16_value()
     t = cls.__message_types.get(value)
     if t is None:
         # name = 'MessageType-0x%04X' % value
         # t = cls(value=value, data=data, name=name)
         raise LookupError('msg type error: %d' % value)
     return t
Exemplo n.º 6
0
 def parse(cls,
           data: Data,
           tag: AttributeType,
           length: AttributeLength = None):
     # checking head byte
     if data.get_byte(index=0) != 0:
         raise ValueError('mapped-address error: %s' % data)
     family = data.get_byte(index=1)
     if family == cls.family_ipv4:
         # IPv4
         if length.value == 8:
             port = data.get_uint16_value(2)
             ip = cls.data_to_ipv4(address=data.slice(start=4))
             return cls(data=data, ip=ip, port=port, family=family)
Exemplo n.º 7
0
 def send_msg(self, msg: str):
     data = msg.encode('utf-8')
     data = Data(data=data)
     address = self.server_address
     print('sending msg (%d bytes): "%s" to %s' %
           (data.length, msg, address))
     self.send_message(msg=data, destination=address)
Exemplo n.º 8
0
 def send_cmd(self, cmd: str):
     data = cmd.encode('utf-8')
     data = Data(data=data)
     address = self.server_address
     print('sending cmd (%d bytes): "%s" to %s' %
           (data.length, cmd, address))
     self.send_command(cmd=data, destination=address)
Exemplo n.º 9
0
 def parse(cls, data: Data):
     if data.length < 16:
         # raise ValueError('transaction ID length error: %d' % data.length)
         return None
     elif data.length > 16:
         data = data.slice(end=16)
     # assert data.get_bytes(end=4) == MagicCookie, 'transaction ID not starts with magic cookie'
     return cls(data=data)
Exemplo n.º 10
0
 def parse(cls, data: Data):
     # get STUN head
     head = Header.parse(data=data)
     if head is None:
         # not a STUN message?
         return None
     # check message length
     head_len = head.length
     pack_len = head_len + head.msg_length.value
     data_len = data.length
     if data_len < pack_len:
         # raise ValueError('STUN package length error: %d, %d' % (data_len, pack_len))
         return None
     elif data_len > pack_len:
         data = data.slice(end=pack_len)
     # get attributes body
     body = data.slice(start=head_len)
     return cls(data=data, head=head, body=body)
Exemplo n.º 11
0
 def parse(cls, data: Data, tag: Tag, length: Length = None):
     # check length
     if length.value != 4:
         raise ValueError('Change-Request value error: %s' % length)
     # get value
     value = data.get_uint32_value()
     if value == ChangeIPAndPort.value:
         return ChangeIPAndPort
     elif value == ChangeIP.value:
         return ChangeIP
     elif value == ChangePort.value:
         return ChangePort
Exemplo n.º 12
0
 def parse(cls, data: Data):
     # get message type
     _type = MessageType.parse(data=data)
     if _type is None:
         return None
     pos = _type.length
     # get message length
     _len = MessageLength.parse(data=data.slice(start=pos))
     if _len is None:
         return None
     pos += _len.length
     # get transaction ID
     _id = TransactionID.parse(data=data.slice(start=pos))
     if _id is None:
         return None
     pos += _id.length
     assert pos == 20, 'header length error: %d' % pos
     if data.length > pos:
         data = data.slice(end=pos)
     # create
     return cls(data=data, msg_type=_type, msg_length=_len, trans_id=_id)
Exemplo n.º 13
0
 def new(cls,
         msg_type: MessageType,
         trans_id: TransactionID = None,
         body: Union[Data, bytes, bytearray] = None):
     if body is None:
         body = Data.ZERO
     elif not isinstance(body, Data):
         # bytes or bytearray
         body = Data(data=body)
     msg_len = MessageLength(value=body.length)
     head = Header(msg_type=msg_type, msg_length=msg_len, trans_id=trans_id)
     return cls(head=head, body=body)
Exemplo n.º 14
0
    def send(self,
             data: Data,
             destination: tuple,
             source: Union[tuple, int] = None) -> int:
        """
        Send data to remote address

        :param data:
        :param destination: remote address
        :param source:      local address
        :return: count of sent bytes
        """
        try:
            if source is None:
                source = self.source_address
            elif isinstance(source, int):
                source = (self.source_address[0], source)
            return self.hub.send(data=data.get_bytes(),
                                 destination=destination,
                                 source=source)
        except socket.error:
            return -1
Exemplo n.º 15
0
 def __bind_request(self, remote_host: str, remote_port: int,
                    body: Data) -> Optional[dict]:
     # 1. create STUN message package
     req = Package.new(msg_type=BindRequest, body=body)
     trans_id = req.head.trans_id
     # 2. send and get response
     count = 0
     while True:
         size = self.send(data=req, destination=(remote_host, remote_port))
         if size != req.length:
             # failed to send data
             return None
         cargo = self.receive()
         if cargo is None:
             if count < self.retries:
                 count += 1
                 self.info('(%d/%d) receive nothing' %
                           (count, self.retries))
             else:
                 # failed to receive data
                 return None
         else:
             self.info('received %d bytes from %s' %
                       (len(cargo.data), cargo.source))
             break
     # 3. parse response
     context = {
         'trans_id': trans_id,
     }
     data = Data(data=cargo.data)
     if not self.parse_data(data=data, context=context):
         return None
     head = context.get('head')
     if head is None or head.type != BindResponse or head.trans_id != trans_id:
         # received package error
         return None
     return context
Exemplo n.º 16
0
 def parse(cls, data: Data, tag: Tag, length: Length = None):
     # get string
     desc = data.get_bytes().decode('utf-8').rstrip('\0')
     return cls(data=data, description=desc)
Exemplo n.º 17
0
 def received_error(self, data: Data, source: tuple, destination: tuple):
     self.info('received error (%d bytes) from %s to %s: %s' %
               (data.length, source, destination, data.get_bytes()))
Exemplo n.º 18
0
 def received_message(self, msg: Data, source: tuple,
                      destination: tuple) -> bool:
     self.info('received msg (%d bytes) from %s to %s: %s' %
               (msg.length, source, destination, msg.get_bytes()))
     return True
Exemplo n.º 19
0
 def data_received(self, data: bytes, source: tuple, destination: tuple) -> Optional[bytes]:
     task = Arrival(payload=Data(data=data), source=source, destination=destination)
     self.pool.append_arrival(task=task)
     return None
Exemplo n.º 20
0
 def send_data(self, data: Data, destination: tuple, source: tuple) -> int:
     return self.send(data=data.get_bytes(), destination=destination, source=source)
Exemplo n.º 21
0
 def received_command(self, cmd: Data, source: tuple,
                      destination: tuple) -> bool:
     self.info('received cmd (%d bytes) from %s to %s: %s' %
               (cmd.length, source, destination, cmd.get_bytes()))
     return True