Ejemplo n.º 1
0
def unpack_name(buf, off):
    name = []
    name_length = 0
    saved_off = 0
    start_off = off
    while True:
        if off >= len(buf):
            raise dpkt.NeedData()
        n = ord(buf[off])
        if n == 0:
            off += 1
            break
        elif (n & 0xc0) == 0xc0:
            ptr = struct.unpack('>H', buf[off:off + 2])[0] & 0x3fff
            if ptr >= start_off:
                raise dpkt.UnpackError('Invalid label compression pointer')
            off += 2
            if not saved_off:
                saved_off = off
            start_off = off = ptr
        elif (n & 0xc0) == 0x00:
            off += 1
            name.append(buf[off:off + n])
            name_length += n + 1
            if name_length > 255:
                raise dpkt.UnpackError('name longer than 255 bytes')
            off += n
        else:
            raise dpkt.UnpackError('Invalid label length %02x' % n)
    if not saved_off:
        saved_off = off
    return '.'.join(name), saved_off
Ejemplo n.º 2
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
Ejemplo n.º 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
Ejemplo n.º 4
0
 def unpack(self, buf):
     f = BytesIO(buf)
     line = f.readline().decode("ascii", "ignore")
     l = line.strip().split()
     if len(l) != 1:
         raise dpkt.UnpackError('invalid message: %r' % line)
     if l[0] not in self.__methods:
         raise dpkt.UnpackError('invalid protocol method: %r' % l[0])
     self.method = l[0]
     Message.unpack(self, f.read())
Ejemplo n.º 5
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
Ejemplo n.º 6
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)
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
def parse_headers(f):
    """Return dict of headers parsed from a file object."""
    d = OrderedDict()
    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().decode("ascii", "ignore")
        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
Ejemplo n.º 9
0
 def unpack(self, buf):
     f = cStringIO.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())
Ejemplo n.º 10
0
 def unpack(self, buf):
     f = cStringIO.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]
     Message.unpack(self, f.read())
Ejemplo n.º 11
0
 def unpack(self, buf):
     f = cStringIO.StringIO(buf)
     line = f.readline()
     l = line.strip().split()
     if len(l) != 3 or l[0] not in self.__methods or \
        not l[2].startswith(self.__proto):
         raise dpkt.UnpackError('invalid request: %r' % line)
     self.method = l[0]
     self.uri = l[1]
     self.version = l[2][len(self.__proto) + 1:]
     Message.unpack(self, f.read())
 def unpack(self, buf):
     #f = io.StringIO(str(buf)[2:-1])
     f = io.BytesIO(buf)
     line = f.readline()
     line = line.decode('utf-8')
     l = line.strip().split(None, 2)
     if len(l) < 3 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]
     parse_message(self, f)
 def unpack(self, buf):
     #f = io.StringIO(str(buf)[2:-1])
     f = io.BytesIO(buf)
     line = f.readline()
     line = line.decode('utf-8')
     l = line.strip().split()
     if len(l) != 3 or l[0] not in self.__methods or \
        not l[2].startswith(self.__proto):
         raise dpkt.UnpackError('invalid request: %r' % line)
     self.method = l[0]
     self.uri = l[1]
     self.version = l[2][len(self.__proto) + 1:]
     parse_message(self, f)
    def unpack(self, buf):
        f = BytesIO(buf)
        line = f.readline().decode("ascii", "ignore")
        if line.startswith('HTTP/'):
            # Work around needed to process pages where HTTP method is not specified. Mainly GET requests.
            line = 'GET * ' + line

        line = line.strip().split()
        if len(line) < 2:
            raise dpkt.UnpackError('invalid request: %r' % line)
        if line[0] not in self.__methods:
            raise dpkt.UnpackError('invalid http method: %r' % line[0])
        if len(line) == 2:
            # HTTP/0.9 does not specify a version in the request line
            self.version = '0.9'
        else:
            if not line[2].startswith(self.__proto):
                raise dpkt.UnpackError('invalid http version: %r' % line[2])
            self.version = line[2][len(self.__proto) + 1:]
        self.method = line[0]
        self.uri = line[1]
        Message.unpack(self, f.read())
def parse_body(f, version, 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 = parse_length(sz, 16)
            if n == 0:  # may happen if sz is invalid
                found_end = True
            buf = f.read(n)
            if f.readline().strip():
                break
            if n and len(buf) == n:
                l.append(buf)
            else:
                break
        if settings.strict_http_parse_body and not found_end:
            raise dpkt.NeedData('premature end of chunked body')
        body = ''.join(l)
    elif 'content-length' in headers:
        # Ethan K B: Have observed malformed 0,0 content lengths
        n = parse_length(headers['content-length'])
        body = f.read(n)
        if len(body) != n:
            logging.warn('HTTP content-length mismatch: expected %d, got %d', n,
                         len(body))
            if settings.strict_http_parse_body:
                raise dpkt.NeedData('short body (missing %d bytes)' % (n - len(body)))
    else:
        # XXX - need to handle HTTP/0.9
        # BTW, this function is not called if status code is 204 or 304
        if version == '1.0':
            # we can assume that there are no further
            # responses on this stream, since 1.0 doesn't
            # support keepalive
            body = f.read()
        elif (version == '1.1' and
              headers.get('connection', None) == 'close'):
            # sender has said they won't send anything else.
            body = f.read()
        # there's also the case where other end sends connection: close,
        # but we don't have the architecture to handle that.
        else:
            # we don't really know what to do
            #print 'returning body as empty string:', version, headers
            body = ''
    return body
Ejemplo n.º 16
0
def _read_chunked(rfile):
    """
    Read a HTTP body with chunked transfer encoding.

    (adapted from mitmproxy's netlib.http.http1)
    """
    while True:
        line = rfile.readline(128)
        if line == b"":
            raise dpkt.NeedData("premature end of chunked body")
        if line != b"\r\n" and line != b"\n":
            try:
                length = int(line, 16)
            except ValueError:
                raise dpkt.UnpackError("Invalid chunked encoding length: %s" %
                                       line)
            chunk = rfile.read(length)
            suffix = rfile.readline(5)
            if suffix != b"\r\n":
                raise dpkt.UnpackError("Malformed chunked body")
            if length == 0:
                return
            yield chunk
Ejemplo n.º 17
0
def unpack_addr(addrtype, buf, offset):
    if addrtype == IP_V4:
        addr = socket.inet_ntop(socket.AF_INET, buf[offset:(offset + 4)])
        nxt = offset + 4
    elif addrtype == IP_V6:
        addr = socket.inet_ntop(socket.AF_INET6, buf[offset:(offset + 16)])
        nxt = offset + 16
    elif addrtype == DOMAIN_NAME:
        length = struct.unpack('B', buf[offset])[0]
        addr = buf[(offset + 1):(offset + 1 + length)]
        nxt = offset + 1 + length
    else:
        raise dpkt.UnpackError("Unknown address type %s" %
                               addrtype.encode('hex'))
    return addr, nxt
Ejemplo n.º 18
0
def parse_headers(f):
    """Return dict of HTTP headers parsed from a file object."""
    d = {}
    while 1:
        line = f.readline()
        if not line:
            raise dpkt.NeedData('premature end of headers')
        line = line.strip()
        if not line:
            break
        l = line.split(None, 1)
        if not l[0].endswith(':'):
            raise dpkt.UnpackError('invalid header: %r' % line)
        k = l[0][:-1].lower()
        d[k] = len(l) != 1 and l[1] or ''
    return d
Ejemplo n.º 19
0
    def parse_body(self, file, headers, fix_incomplete=False):
        """Return HTTP body parsed from a file object, given HTTP header dict

        Args:
            file: BytesIO object
            headers: HTTP request headers as dict

        Returns:
            str: body string"""

        if headers.get('transfer-encoding', '').lower() == 'chunked':
            buffer_list = []
            found_end = False
            while True:
                try:
                    size = file.readline().split(None, 1)[0]
                except IndexError:
                    raise dpkt.UnpackError('missing chunk size')
                n = int(size, 16)
                if n == 0:
                    found_end = True
                buffer = file.read(n)
                if file.readline().strip():
                    break
                if n and len(buffer) == n:
                    buffer_list.append(buffer)
                else:
                    break
            if not found_end:
                raise dpkt.NeedData('premature end of chunked body')
            body = b''.join(buffer_list)
        elif 'content-length' in headers:
            n = int(headers['content-length'])
            body = file.read(n)
            if fix_incomplete:
                headers['content-length'] = len(body)
            elif len(body) != n:
                raise dpkt.NeedData('short body (missing %d bytes)' %
                                    (n - len(body)))
        elif 'content-type' in headers:
            body = file.read()
        else:
            # XXX - need to handle HTTP/0.9
            body = b''
        return body
Ejemplo n.º 20
0
    def unpack(self, buf):
        """Unpacks a bytes object into component attributes.
        This function is called when an instance of this class is created
        by passing a bytes object to the constructor
        """
        super().unpack(buf)  # unpacks _hdr

        if self.hdr_type != APv6Udp.HDR_TYPE:
            raise dpkt.UnpackError(
                "Unpacking compressed UDP, but encountered wrong type value")

        if self.hdr_co == 0:
            if len(self.data) < 2:
                raise dpkt.NeedData("for UDP checksum")
            self.chksum = struct.unpack("!H", self.data[0:2])[0]
            self.data = self.data[2:]

        p = self.hdr_ports
        if p == APv6Udp.HDR_PORTS_SRC_INLN_DST_INLN:
            if len(self.data) < 4:
                raise dpkt.NeedData("for UDP ports")
            self.src_port = struct.unpack("!H", self.data[0:2])[0]
            self.dst_port = struct.unpack("!H", self.data[2:4])[0]
            self.data = self.data[4:]
        elif p == APv6Udp.HDR_PORTS_SRC_INLN_DST_F0XX:
            if len(self.data) < 3:
                raise dpkt.NeedData("for UDP ports")
            self.src_port = struct.unpack("!H", self.data[0:2])[0]
            self.dst_port = 0xf000 | self.data[2]
            self.data = self.data[3:]
        elif p == APv6Udp.HDR_PORTS_SRC_F0XX_DST_INLN:
            if len(self.data) < 3:
                raise dpkt.NeedData("for UDP ports")
            self.src_port = 0xf000 | self.data[0]
            self.dst_port = struct.unpack("!H", self.data[1:3])[0]
            self.data = self.data[3:]
        elif p == APv6Udp.HDR_PORTS_SRC_F0BX_DST_F0BX:
            if len(self.data) < 1:
                raise dpkt.NeedData("for UDP ports")
            d = self.data[0]
            self.src_port = 0xf0b0 | ((d >> 4) & 0b1111)
            self.dst_port = 0xf0b0 | (d & 0b1111)
            self.data = self.data[1:]
def parse_headers(f):
    """Return dict of HTTP headers parsed from a file object."""
    d = {}
    while 1:
        line = f.readline()
        # regular dpkt checks for premature end of headers
        # but that's too picky
        line = line.strip()
        if not line:
            break
        l = line.split(None, 1)
        if not l[0].endswith(':'):
            raise dpkt.UnpackError('invalid header: %r' % line)
        k = l[0][:-1].lower()
        v = len(l) != 1 and l[1] or ''
        if k in d:
            d[k] += ','+v
        else:
            d[k] = v
    return d
Ejemplo n.º 22
0
    def _do_unpack_options(self, buf, oo=None):
        self.opts = []
        self.data = ''
        oo = oo or self.__hdr_len__ - 4  # options offset
        ol = self.len - oo - 4  # length

        opts_buf = buf[oo:oo + ol]
        while opts_buf:
            opt = (PcapngOptionLE(opts_buf)
                   if self.__hdr_fmt__[0] == '<' else PcapngOption(opts_buf))
            self.opts.append(opt)

            opts_buf = opts_buf[len(opt):]
            if opt.code == PCAPNG_OPT_ENDOFOPT:
                break

        # duplicate total length field
        self._len = struct_unpack(self.__hdr_fmt__[0] + 'I', buf[-4:])[0]
        if self._len != self.len:
            raise dpkt.UnpackError('length fields do not match')
Ejemplo n.º 23
0
 def unpack(self, buf):
     f = cStringIO.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)
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 settings.strict_http_parse_body and not found_end:
            raise dpkt.NeedData('premature end of chunked body')
        body = ''.join(l)
    elif 'content-length' in headers:
        # Have observed malformed 0,0 content lengths
        if headers['content-length'] == '0,0':
            n = 0
        else:
            n = int(headers['content-length'])
        body = f.read(n)
        if len(body) != n:
            logging.warn('HTTP content-length mismatch: expected %d, got %d',
                         n, len(body))
            if settings.strict_http_parse_body:
                raise dpkt.NeedData('short body (missing %d bytes)' %
                                    (n - len(body)))
    else:
        # XXX - need to handle HTTP/0.9
        body = ''
    return body
Ejemplo n.º 25
0
def parse_headers(f):
    """Return dict of HTTP headers parsed from a file object."""
    d = {}
    while 1:
        line = f.readline()
        if not line:
            raise dpkt.NeedData('premature end of headers')
        line = line.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
Ejemplo n.º 26
0
def unpack_name(buf, off):
    name = ''
    saved_off = 0
    for i 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