Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    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