def _decode(self, msg, query): msg = BitStream(msg) header = msg[:self.HEADER_SIZE].unpack(self.HDR_FMT) id, ctl, qc, rc, _, ac = header ctl = BitStream(bin(ctl)) _, opcode, aa, tc, rd, ra, _, rcode = ctl.unpack(self.CTL_FMT) if rcode == 1: raise FormatError(self.raw_msg) elif rcode == 2: raise ServerError(self.raw_msg) elif rcode == 3: raise InvalidNameError(self.raw_msg) elif rcode == 5: raise ServerRefusedError(self.raw_msg) if tc == 1: raise ResponseTruncatedError(self.raw_msg) self.ra = ra self.aa = aa self.rc = rc self.ac = ac question = msg[96:] for _ in range(qc): _, question = decode_name(msg, question) question = question[32:] # Move past QTYPE and QCLASS resp = question name = True names = [] for _ in range(rc): name, answer, rtype, ttl, resp = seek_response(resp, msg) self.responses.append((name, answer, rtype, ttl)) for _ in range(ac): name, answer, rtype, ttl, resp = seek_response(resp, msg) self.additional.append((name, answer, rtype, ttl))
def from_bytes(buf): bs = BitStream(bytes=buf) pkt = IPv4Packet() pkt.version = bs.read('uint:4') pkt.ihl = bs.read('uint:4') pkt.dscp = bs.read('uint:6') pkt.ecn = bs.read('uint:2') pkt.total_length = bs.read('uint:16') pkt.ident = bs.read('uint:16') pkt.flag_reserved = bs.read('bool') pkt.flag_dont_fragment = bs.read('bool') pkt.flag_more_fragments = bs.read('bool') pkt.fragment_offset = bs.read('uint:13') pkt.time_to_live = bs.read('uint:8') pkt.protocol = bs.read('uint:8') # TODO The checksum field is the 16 bit one's complement of the one's # complement sum of all 16 bit words in the header. For purposes of # computing the checksum, the value of the checksum field is zero. pkt.header_checksum = bs.read('uint:16') pkt.source = ipaddress.IPv4Address(bs.read('uint:32')) pkt.destination = ipaddress.IPv4Address(bs.read('uint:32')) if pkt.ihl == 5: pkt.options = None elif pkt.ihl >= 6 and pkt.ihl <= 15: pkt.options = [] while (True): if bs.bytepos >= pkt.ihl * 4: break #TODO padding (always ends on 32 bit boundary; implicit end of list) option = {} option['copy'] = bs.read('bool') option['class'] = bs.read('uint:2') option['number'] = bs.read('uint:5') if option['class'] == IPv4Packet.CLASS_CONTROL: if option[ 'number'] == IPv4Packet.NUMBER_END_OF_OPTION_LIST: # end of options list # no length or data break elif option['number'] == IPv4Packet.NUMBER_NO_OPERATION: # no operation # no length or data pass elif option['number'] == IPv4Packet.NUMBER_SECURITY: # Security RFC 791 # 11 octet length option['length'] = bs.unpack('uint:8') if option['length'] != 11: raise RuntimeError( 'Security IP Option with length other than 11') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) elif option[ 'number'] == IPv4Packet.NUMBER_LOOSE_SOURCE_ROUTING: # Loose Source Routing # var octet length option['length'] = bs.unpack('uint:8') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) elif option['number'] == IPv4Packet.NUMBER_RECORD_ROUTE: # Record Route # var octet length option['length'] = bs.unpack('uint:8') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) elif option['number'] == IPv4Packet.NUMBER_STREAM_ID: # Stream ID # 4 octet length option['length'] = bs.unpack('uint:8') if option['length'] != 4: raise RuntimeError( 'Stream ID IP Option with length other than 4') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) elif option[ 'number'] == IPv4Packet.NUMBER_STRICT_SOURCE_ROUTING: # Strict Source Routing # var octet length option['length'] = bs.unpack('uint:8') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) else: raise RuntimeError('Unknown IP option: ' \ + 'class: ' + str(option['class'] \ + ', number: ' + str(option['number']))) elif option['class'] == IPv4Packet.CLASS_DEBUG_MEASURE: if option[ 'number'] == IPv4Packet.NUMBER_INTERNET_TIMESTAMP: # Internet Timestamp # var octet length option['length'] = bs.unpack('uint:8') option['data'] = bs.unpack('bytes:' + str(option['length'] - 2)) else: raise RuntimeError('Unknown IP option: ' \ + 'class: ' + str(option['class'] \ + ', number: ' + str(option['number']))) else: raise RuntimeError('Unknown IP option class: ' + str(option['class'])) else: raise RuntimeError('Invalid IHL value for packet: ' + str(pkt.ihl)) pkt.data = buf[(pkt.ihl * 4):] return pkt