def parse(bytedata: bytes) -> tuple: """ :param bytedata data, from the dns packet stream :return: tuple(AnswerItem, rest of bytedata) :rtype AnswerItem, bytes """ name_field, bytedata = bread(bytedata, 2) name_field = int.from_bytes(name_field, byteorder="big") # 0bXY00000000000000 - X: 1 Y: 1 -> 11, X:0 Y:1 -> 1, X:1 Y:0 -> 10 name_type = 10 * ((name_field >> 15) & 0b1) + ((name_field >> 14) & 0b1) name_offset = name_field & 0b001111111111111 assert name_type == 11 _type, bytedata = bread(bytedata, 2) _type = int.from_bytes(_type, byteorder="big") _class, bytedata = bread(bytedata, 2) _class = int.from_bytes(_class, byteorder="big") _ttl, bytedata = bread(bytedata, 4) _ttl = int.from_bytes(_ttl, byteorder="big") rdlen, bytedata = bread(bytedata, 2) rdlen = int.from_bytes(rdlen, byteorder="big") rddata, bytedata = bread(bytedata, rdlen) rddata = QuestionTypes.unpack(_type, rddata) return AnswerItem(QuestionItem(name_offset, _type, _class), _type, rddata, _ttl), bytedata
def __init__(self, qname, qtype: int, qclass: int): """ :param qname: question subject :param qtype: question type :param qclass: question class :return: """ if isinstance(qname, str) and qtype == 1: qname = qname.split(".") self._qname = qname self._qtype = int(qtype) self._qclass = qclass self._qtype_str = QuestionTypes.get(qtype).qname
def raw(self, offset): """ :param offset: offset from begin of the message for the name label :return: """ body = b"" if offset < 1: offset = 0 body += struct.pack(u16bit, 0b1100000000000000 + offset) # 16 bytes record, type 11, start 2 bytes body += struct.pack(u16bit, self._type) body += struct.pack(u16bit, self._class) body += struct.pack(u32bit, self._ttl) ipdata, size = QuestionTypes.pack(self._rtype, self._data) if ipdata is None: return None body += struct.pack(u16bit, size) body += ipdata return body
def unpack_a_response(data: bytes) -> list: ret = [-1] * 4 for i in range(0, 4): octet, data = bread(data, 1, data_fx=lambda x: int.from_bytes(x, byteorder="big")) ret[i] = octet return ret def unpack_ptr_response(data: bytes) -> str: size = -1 _str = [] while size != 0: # ToDo: add check if packet is malformed and no zero flag at the end size, data = bread(data, 1, data_fx=lambda x: int.from_bytes(x, byteorder="big")) if size != 0: lbl, data = bread(data, size) try: _str.append(lbl.decode(encoding="utf-8")) except UnicodeDecodeError: _str.append("<invalid format>") return ".".join(_str) # register packer/unpacker QuestionTypes.set_fx("A", pack_a_response, unpack_a_response) QuestionTypes.set_fx("PTR", pack_ptr_response, unpack_ptr_response) QuestionTypes.set_fx("NS", pack_ptr_response, unpack_ptr_response)