Parser.py 2.72 KB
"""
 @author Georg Hopp

"""
import struct

class Parser(object):
    def __init__(self):
        self._ofs_names = {}

    def parse(self, message, data):
        self._ofs_names = {}

        message._msg_id, \
        message._flags, \
        nqueries, \
        nanswers, \
        nauthorities, \
        nadditionals = struct.unpack('!HHHHHH', data[0:12])

        ofs = 12
        ofs = self._parseQueries(message, data, ofs, nqueries)
        ofs = self._parseAnswers(message, data, ofs, nanswers)
        ofs = self._parseAuthorities(message, data, ofs, nauthorities)
        self._parseAdditionals(message, data, ofs, nadditionals)

    def _parseQueries(self, message, data, ofs, count):
        while 0 < count:
            name, ofs = self._decodeName(data, ofs)
            typ, cls  = struct.unpack('!HH', data[ofs:ofs+4])
            ofs      += 4
            count    -= 1
            message._queries.append((name, typ, cls))

        return ofs

    def _parseAnswers(self, message, data, ofs, count):
        while 0 < count:
            record, ofs = self._parseResourceRecord(message, data, ofs)
            count      -= 1
            message._answers.append(record)

        return ofs

    def _parseAuthorities(self, message, data, ofs, count):
        while 0 < count:
            record, ofs = self._parseResourceRecord(message, data, ofs)
            count      -= 1
            message._authorities.append(record)

        return ofs

    def _parseAdditionals(self, message, data, ofs, count):
        while 0 < count:
            record, ofs = self._parseResourceRecord(message, data, ofs)
            count      -= 1
            message._additionals.append(record)

        return ofs

    def _parseResourceRecord(self, message, data, ofs):
        name, ofs            = self._decodeName(data, ofs)
        typ, cls, ttl, rrlen = struct.unpack('!HHLH', data[ofs:ofs+10])
        ofs                 += 10
        record               = data[ofs:ofs+rrlen]
        ofs                 += rrlen

        return ((name, typ, cls, ttl, record), ofs)

    def _decodeName(self, data, ofs):
        idx        = ofs
        compressed = struct.unpack('!H', data[ofs:ofs+2])[0]

        if compressed & int('1100000000000000', 2):
            idx = compressed & int('0011111111111111', 2)
            name = (self._ofs_names[idx], ofs+2)
        else:
            length = struct.unpack('B', data[ofs])[0]
            parts  = []
            while 0 != length:
                parts.append(data[ofs+1:ofs+1+length])
                ofs += 1+length
                length = struct.unpack('B', data[ofs])[0]

            name = ('.'.join(parts), ofs+1)
            self._ofs_names[idx] = name[0]

        return name

# vim: set ft=python et ts=4 sw=4 sts=4: