Example #1
0
    def unpack(self, buf):
        # TPKT header
        self.tpkt = tpkt.TPKT(buf)
        if self.tpkt.v != 3:
            raise dpkt.UnpackError('invalid TPKT version')
        if self.tpkt.rsvd != 0:
            raise dpkt.UnpackError('invalid TPKT reserved value')
        n = self.tpkt.len - self.tpkt.__hdr_len__
        if n > len(self.tpkt.data):
            raise dpkt.UnpackError('invalid TPKT length')
        buf = self.tpkt.data

        # Q.931 payload
        dpkt.Packet.unpack(self, buf)
        buf = buf[self.__hdr_len__:]
        self.ref_val = buf[:self.ref_len]
        buf = buf[self.ref_len:]
        self.type = struct.unpack('B', buf[:1])[0]
        buf = buf[1:]

        # Information Elements
        l = []
        while buf:
            ie = self.IE(buf)
            l.append(ie)
            buf = buf[len(ie):]
        self.data = l
Example #2
0
 def unpack(self, buf):
     if type(buf) == bytes:
         decoders = ["utf8", "ISO-8859-1", "cp1252"]
         for i, decoder in enumerate(decoders):
             try:
                 buf = buf.decode(decoder)
                 break
             except UnicodeDecodeError as e:
                 if i + 1 == len(decoders):
                     raise
     f = io.StringIO(buf)
     line = f.readline()
     l = line.strip().split()
     if len(l) < 2:
         raise dpkt.UnpackError('invalid request: %r' % line)
     if l[0] not in self.__methods:
         raise dpkt.UnpackError('invalid http method: %r' % l[0])
     if len(l) == 2:
         # HTTP/0.9 does not specify a version in the request line
         self.version = '0.9'
     else:
         if not l[2].startswith(self.__proto):
             raise dpkt.UnpackError('invalid http version: %r' % l[2])
         self.version = l[2][len(self.__proto) + 1:]
     self.method = l[0]
     self.uri = l[1]
     Message.unpack(self, f.read())
Example #3
0
def decode(buf):
    """Sleazy ASN.1 decoder.
    Return list of (id, value) tuples from ASN.1 BER/DER encoded buffer.
    """
    msg = []
    while buf:
        t = ord(buf[0])
        constructed = t & CONSTRUCTED
        tag = t & TAGMASK
        l = ord(buf[1])
        c = 0
        if constructed and l == 128:
            # XXX - constructed, indefinite length
            msg.append((t, decode(buf[2:])))
        elif l >= 128:
            c = l & 127
            if c == 1:
                l = ord(buf[2])
            elif c == 2:
                l = struct.unpack('>H', buf[2:4])[0]
            elif c == 3:
                l = struct.unpack('>I', buf[1:5])[0] & 0xfff
                c = 2
            elif c == 4:
                l = struct.unpack('>I', buf[2:6])[0]
            else:
                # XXX - can be up to 127 bytes, but...
                raise dpkt.UnpackError('excessive long-form ASN.1 length %d' %
                                       l)

        # Skip type, length
        buf = buf[2 + c:]

        # Parse content
        if constructed:
            msg.append((t, decode(buf)))
        elif tag == INTEGER:
            if l == 0:
                n = 0
            elif l == 1:
                n = ord(buf[0])
            elif l == 2:
                n = struct.unpack('>H', buf[:2])[0]
            elif l == 3:
                n = struct.unpack('>I', buf[:4])[0] >> 8
            elif l == 4:
                n = struct.unpack('>I', buf[:4])[0]
            else:
                raise dpkt.UnpackError('excessive integer length > %d bytes' %
                                       l)
            msg.append((t, n))
        elif tag == UTC_TIME:
            msg.append((t, utctime(buf[:l])))
        else:
            msg.append((t, buf[:l]))

        # Skip content
        buf = buf[l:]
    return msg
Example #4
0
 def unpack(self, buf):
     dpkt.Packet.unpack(self, buf)
     if self.ast != 0x2a:
         raise dpkt.UnpackError('invalid FLAP header')
     if len(self.data) < self.len:
         raise dpkt.NeedData('%d left, %d needed' %
                             (len(self.data), self.len))
Example #5
0
 def unpack(self, buf):
     dpkt.Packet.unpack(self, buf)
     ol = ((self._off >> 4) << 2) - self.__hdr_len__
     if ol < 0:
         raise dpkt.UnpackError('invalid header length')
     self.opts = buf[self.__hdr_len__:self.__hdr_len__ + ol]
     self.data = buf[self.__hdr_len__ + ol:]
Example #6
0
 def unpack_rdata(self, buf, off):
     if self.type == DNS_A:
         self.ip = self.rdata
     elif self.type == DNS_NS:
         self.nsname, off = unpack_name(buf, off)
     elif self.type == DNS_CNAME:
         self.cname, off = unpack_name(buf, off)
     elif self.type == DNS_PTR:
         self.ptrname, off = unpack_name(buf, off)
     elif self.type == DNS_SOA:
         self.mname, off = unpack_name(buf, off)
         self.rname, off = unpack_name(buf, off)
         self.serial, self.refresh, self.retry, self.expire, \
         self.minimum = struct.unpack('>IIIII', buf[off:off + 20])
     elif self.type == DNS_MX:
         self.preference = struct.unpack('>H', self.rdata[:2])
         self.mxname, off = unpack_name(buf, off + 2)
     elif self.type == DNS_TXT or self.type == DNS_HINFO:
         self.text = []
         buf = self.rdata
         while buf:
             n = ord(buf[0])
             self.text.append(buf[1:1 + n])
             buf = buf[1 + n:]
     elif self.type == DNS_AAAA:
         self.ip6 = self.rdata
     elif self.type == DNS_SRV:
         self.priority, self.weight, self.port = struct.unpack('>HHH', self.rdata[:6])
         self.srvname, off = unpack_name(buf, off + 6)
     elif self.type == DNS_OPT:
         pass  # RFC-6891: OPT is a pseudo-RR not carrying any DNS data
     else:
         raise dpkt.UnpackError('RR type %s is not supported' % self.type)
Example #7
0
def parse_headers(f):
    """Return dict of HTTP headers parsed from a file object."""
    d = {}
    while 1:
        # The following logic covers two kinds of loop exit criteria.
        # 1) If the header is valid, when we reached the end of the header,
        #    f.readline() would return with '\r\n', then after strip(),
        #    we can break the loop.
        # 2) If this is a weird header, which do not ends with '\r\n',
        #    f.readline() would return with '', then after strip(),
        #    we still get an empty string, also break the loop.
        line = f.readline().strip()
        if not line:
            break
        l = line.split(':', 1)
        if len(l[0].split()) != 1:
            raise dpkt.UnpackError('invalid header: %r' % line)
        k = l[0].lower()
        v = len(l) != 1 and l[1].lstrip() or ''
        if k in d:
            if not type(d[k]) is list:
                d[k] = [d[k]]
            d[k].append(v)
        else:
            d[k] = v
    return d
Example #8
0
def parse_body(f, headers):
    """Return HTTP body parsed from a file object, given HTTP header dict."""
    if headers.get('transfer-encoding', '').lower() == 'chunked':
        l = []
        found_end = False
        while 1:
            try:
                sz = f.readline().split(None, 1)[0]
            except IndexError:
                raise dpkt.UnpackError('missing chunk size')
            n = int(sz, 16)
            if n == 0:
                found_end = True
            buf = f.read(n)
            if f.readline().strip():
                break
            if n and len(buf) == n:
                l.append(buf)
            else:
                break
        if not found_end:
            raise dpkt.NeedData('premature end of chunked body')
        body = ''.join(l)
    elif 'content-length' in headers:
        n = int(headers['content-length'])
        body = f.read(n)
        if len(body) != n:
            raise dpkt.NeedData('short body (missing %d bytes)' %
                                (n - len(body)))
    elif 'content-type' in headers:
        body = f.read()
    else:
        # XXX - need to handle HTTP/0.9
        body = ''
    return body
Example #9
0
def unpack_xdrlist(cls, buf):
    l = []
    while buf:
        if buf.startswith('\x00\x00\x00\x01'):
            p = cls(buf[4:])
            l.append(p)
            buf = p.data
        elif buf.startswith('\x00\x00\x00\x00'):
            break
        else:
            raise dpkt.UnpackError('invalid XDR list')
    return l
Example #10
0
 def unpack(self, buf):
     dpkt.Packet.unpack(self, buf)
     ol = ((self._v_hl & 0xf) << 2) - self.__hdr_len__
     if ol < 0:
         raise dpkt.UnpackError('invalid header length')
     self.opts = buf[self.__hdr_len__:self.__hdr_len__ + ol]
     if self.len:
         buf = buf[self.__hdr_len__ + ol:self.len]
     else:  # very likely due to TCP segmentation offload
         buf = buf[self.__hdr_len__ + ol:]
     try:
         self.data = self._protosw[self.p](buf)
         setattr(self, self.data.__class__.__name__.lower(), self.data)
     except (KeyError, dpkt.UnpackError):
         self.data = buf
Example #11
0
def unpack_name(buf, off):
    name = ''
    saved_off = 0
    for _ in range(100):  # XXX
        n = ord(buf[off])
        if n == 0:
            off += 1
            break
        elif (n & 0xc0) == 0xc0:
            ptr = struct.unpack('>H', buf[off:off + 2])[0] & 0x3fff
            off += 2
            if not saved_off:
                saved_off = off
            # XXX - don't use recursion!@#$
            name = name + unpack_name(buf, ptr)[0] + '.'
            break
        else:
            off += 1
            name = name + buf[off:off + n] + '.'
            if len(name) > 255:
                raise dpkt.UnpackError('name longer than 255 bytes')
            off += n
    return name.strip('.'), off
Example #12
0
 def unpack(self, buf):
     f = io.StringIO(buf)
     line = f.readline()
     l = line.strip().split(None, 2)
     if len(l) < 2 or not l[0].startswith(
             self.__proto) or not l[1].isdigit():
         raise dpkt.UnpackError('invalid response: %r' % line)
     self.version = l[0][len(self.__proto) + 1:]
     self.status = l[1]
     self.reason = l[2] if len(l) > 2 else ''
     # RFC Sec 4.3.
     # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3.
     # For response messages, whether or not a message-body is included with
     # a message is dependent on both the request method and the response
     # status code (section 6.1.1). All responses to the HEAD request method
     # MUST NOT include a message-body, even though the presence of entity-
     # header fields might lead one to believe they do. All 1xx
     # (informational), 204 (no content), and 304 (not modified) responses
     # MUST NOT include a message-body. All other responses do include a
     # message-body, although it MAY be of zero length.
     is_body_allowed = int(self.status) >= 200 and 204 != int(
         self.status) != 304
     Message.unpack(self, f.read(), is_body_allowed)