class HttpStream(object): """ An HTTP parser providing higher-level access to a readable, sequential io.RawIOBase object. You can use implementions of http_parser.reader (IterReader, StringReader, SocketReader) or create your own. """ def __init__(self, stream, kind=HTTP_BOTH, decompress=False): """ constructor of HttpStream. :attr stream: an io.RawIOBase object :attr kind: Int, could be 0 to parseonly requests, 1 to parse only responses or 2 if we want to let the parser detect the type. """ self.parser = HttpParser(kind=kind, decompress=decompress) self.stream = stream def _check_headers_complete(self): if self.parser.is_headers_complete(): return while True: try: data = self.next() except StopIteration: if self.parser.is_headers_complete(): return raise NoMoreData() if self.parser.is_headers_complete(): return def url(self): """ get full url of the request """ self._check_headers_complete() return self.parser.get_url() def path(self): """ get path of the request (url without query string and fragment """ self._check_headers_complete() return self.parser.get_path() def query_string(self): """ get query string of the url """ self._check_headers_complete() return self.parser.get_query_string() def fragment(self): """ get fragment of the url """ self._check_headers_complete() return self.parser.get_fragment() def version(self): self._check_headers_complete() return self.parser.get_version() def status_code(self): """ get status code of a response as integer """ self._check_headers_complete() return self.parser.get_status_code() def status(self): """ return complete status with reason """ status_code = self.status_code() reason = status_reasons.get(int(status_code), 'unknown') return "%s %s" % (status_code, reason) def method(self): """ get HTTP method as string""" self._check_headers_complete() return self.parser.get_method() def headers(self): """ get request/response headers, headers are returned in a OrderedDict that allows you to get value using insensitive keys.""" self._check_headers_complete() return self.parser.get_headers() def should_keep_alive(self): """ return True if the connection should be kept alive """ self._check_headers_complete() return self.parser.should_keep_alive() def is_chunked(self): """ return True if Transfer-Encoding header value is chunked""" self._check_headers_complete() return self.parser.is_chunked() def wsgi_environ(self, initial=None): """ get WSGI environ based on the current request. :attr initial: dict, initial values to fill in environ. """ self._check_headers_complete() return self.parser.get_wsgi_environ() def body_file(self, buffering=None, binary=True, encoding=None, errors=None, newline=None): """ return the body as a buffered stream object. If binary is true an io.BufferedReader will be returned, else an io.TextIOWrapper. """ self._check_headers_complete() if buffering is None: buffering = -1 if buffering < 0: buffering = DEFAULT_BUFFER_SIZE raw = HttpBodyReader(self) buffer = BufferedReader(raw, buffering) if binary: return buffer text = TextIOWrapper(buffer, encoding, errors, newline) return text def body_string(self, binary=True, encoding=None, errors=None, newline=None): """ return body as string """ return self.body_file(binary=binary, encoding=encoding, newline=newline).read() def __iter__(self): return self def next(self): if self.parser.is_message_complete(): raise StopIteration # fetch data b = bytearray(DEFAULT_BUFFER_SIZE) recved = self.stream.readinto(b) if recved is None: raise NoMoreData("no more data") del b[recved:] # parse data nparsed = self.parser.execute(bytes(b), recved) if nparsed != recved and not self.parser.is_message_complete(): raise ParserError("nparsed != recved") if recved == 0: raise StopIteration return bytes(b)
class HttpStream(object): """ An HTTP parser providing higher-level access to a readable, sequential io.RawIOBase object. You can use implementions of http_parser.reader (IterReader, StringReader, SocketReader) or create your own. """ def __init__(self, stream, kind=HTTP_BOTH, decompress=False): """ constructor of HttpStream. :attr stream: an io.RawIOBase object :attr kind: Int, could be 0 to parseonly requests, 1 to parse only responses or 2 if we want to let the parser detect the type. """ self.parser = HttpParser(kind=kind, decompress=decompress) self.stream = stream def _check_headers_complete(self): if self.parser.is_headers_complete(): return while True: try: next(self) except StopIteration: if self.parser.is_headers_complete(): return raise NoMoreData("Can't parse headers") if self.parser.is_headers_complete(): return def _wait_status_line(self, cond): if self.parser.is_headers_complete(): return True data = [] if not cond(): while True: try: d = next(self) data.append(d) except StopIteration: if self.parser.is_headers_complete(): return True raise BadStatusLine(b"".join(data)) if cond(): return True return True def _wait_on_url(self): return self._wait_status_line(self.parser.get_url) def _wait_on_status(self): return self._wait_status_line(self.parser.get_status_code) def url(self): """ get full url of the request """ self._wait_on_url() return self.parser.get_url() def path(self): """ get path of the request (url without query string and fragment """ self._wait_on_url() return self.parser.get_path() def query_string(self): """ get query string of the url """ self._wait_on_url() return self.parser.get_query_string() def fragment(self): """ get fragment of the url """ self._wait_on_url() return self.parser.get_fragment() def version(self): self._wait_on_status() return self.parser.get_version() def status_code(self): """ get status code of a response as integer """ self._wait_on_status() return self.parser.get_status_code() def status(self): """ return complete status with reason """ status_code = self.status_code() reason = status_reasons.get(int(status_code), 'unknown') return "%s %s" % (status_code, reason) def method(self): """ get HTTP method as string""" self._wait_on_status() return self.parser.get_method() def headers(self): """ get request/response headers, headers are returned in a OrderedDict that allows you to get value using insensitive keys.""" self._check_headers_complete() return self.parser.get_headers() def should_keep_alive(self): """ return True if the connection should be kept alive """ self._check_headers_complete() return self.parser.should_keep_alive() def is_chunked(self): """ return True if Transfer-Encoding header value is chunked""" self._check_headers_complete() return self.parser.is_chunked() def wsgi_environ(self, initial=None): """ get WSGI environ based on the current request. :attr initial: dict, initial values to fill in environ. """ self._check_headers_complete() return self.parser.get_wsgi_environ() def body_file(self, buffering=None, binary=True, encoding=None, errors=None, newline=None): """ return the body as a buffered stream object. If binary is true an io.BufferedReader will be returned, else an io.TextIOWrapper. """ self._check_headers_complete() if buffering is None: buffering = -1 if buffering < 0: buffering = DEFAULT_BUFFER_SIZE raw = HttpBodyReader(self) buf = BufferedReader(raw, buffering) if binary: return buf text = TextIOWrapper(buf, encoding, errors, newline) return text def body_string(self, binary=True, encoding=None, errors=None, newline=None): """ return body as string """ return self.body_file(binary=binary, encoding=encoding, newline=newline).read() def __iter__(self): return self def __next__(self): if self.parser.is_message_complete(): raise StopIteration # fetch data b = bytearray(DEFAULT_BUFFER_SIZE) recved = self.stream.readinto(b) if recved is None: raise NoMoreData("no more data") del b[recved:] to_parse = bytes(b) # parse data nparsed = self.parser.execute(to_parse, recved) if nparsed != recved and not self.parser.is_message_complete(): raise ParserError("nparsed != recved (%s != %s) [%s]" % (nparsed, recved, bytes_to_str(to_parse))) if recved == 0: raise StopIteration return to_parse next = __next__
def parse(self): data = [{ 'label': '以太网帧头部 / Ethernet Headers', 'value': '', 'bold': True, 'children': [{ 'label': '目的端 MAC 地址', 'value': self.ethHeader.destMac }, { 'label': '发送端 MAC 地址', 'value': self.ethHeader.sourceMac }, { 'label': '帧类型', 'value': '%s (0x%s)' % (self.ethHeader.type, self.ethHeader.type_code) }] }] if self.protocol == 'ARP': data.append({ 'label': 'ARP 消息 / Address Resolution Protocol', 'value': '', 'bold': True, 'children': [{ 'label': '硬件类型', 'value': '%s (%s)' % (self.arpBody.hardware_type, self.arpBody.hardware_type_code) }, { 'label': '协议类型', 'value': '%s (0x%s)' % (self.arpBody.protocol_type, self.arpBody.protocol_type_code) }, { 'label': '硬件地址长度', 'value': str(self.arpBody.hardware_size) }, { 'label': '协议地址长度', 'value': str(self.arpBody.protocol_size) }, { 'label': '操作码', 'value': '%s (%s)' % (self.arpBody.operation, self.arpBody.operation_code) }, { 'label': '发送端 MAC 地址', 'value': self.arpBody.sender_mac_address }, { 'label': '发送端 IP 地址', 'value': self.arpBody.sender_ip_address }, { 'label': '目的端 MAC 地址', 'value': self.arpBody.target_mac_address }, { 'label': '目的端 IP 地址', 'value': self.arpBody.target_ip_address }] }) else: if self.ipHeader.version == 4: self.ipHeader.verifyChecksum = verifyChecksum( self.ipHeader.header_raw, [], '').verifyChecksum data.append({ 'label': 'IPv4 头部 / IPv4 Header', 'value': '', 'bold': True, 'children': [{ 'label': '协议版本', 'value': self.ipHeader.version }, { 'label': '头部长度', 'value': str(self.ipHeader.header_length) + ' Bytes' }, { 'label': '服务类型', 'value': '0x%s' % (self.ipHeader.differentiated_services) }, { 'label': '来源 IP', 'value': self.ipHeader.source_ip }, { 'label': '目标 IP', 'value': self.ipHeader.dest_ip }, { 'label': '总长度', 'value': self.ipHeader.total_length }, { 'label': '标识', 'value': '0x%s (%s)' % (self.ipHeader.identification, self.ipHeader.identification_int) }, { 'label': '标志', 'value': '%s' % (self.ipHeader.flags.raw), 'children': [{ 'label': '保留位', 'value': '%s | %s... .... .... ....' % (self.ipHeader.flags.reserved, int(self.ipHeader.flags.reserved)) }, { 'label': 'Don\'t fragment', 'value': '%s | .%s.. .... .... ....' % (self.ipHeader.flags.fragment, int(self.ipHeader.flags.fragment)) }, { 'label': 'More fragments', 'value': '%s | ..%s. .... .... ....' % (self.ipHeader.flags.more_fragment, int(self.ipHeader.flags.more_fragment)) }, { 'label': '分段偏移', 'value': '%s | ...%s' % (self.ipHeader.flags.fragment_offset, self.ipHeader.flags.fragment_offset_bin) }] }, { 'label': '生存期', 'value': self.ipHeader.time_to_live }, { 'label': '协议', 'value': '%s (%s)' % (self.ipHeader.protocol, self.ipHeader.protocol_code) }, { 'label': '校验和', 'value': '0x%s (%s)' % (self.ipHeader.origin_checksum, '校验' + { True: '通过', False: '失败' }[self.ipHeader.verifyChecksum]) }] }) else: ipv6_header = { 'label': 'IPv6 头部 / IPv6 Header', 'value': '', 'bold': True, 'children': [{ 'label': '协议版本', 'value': self.ipHeader.version }, { 'label': '通信分类', 'value': '0x%s' % (self.ipHeader._class) }, { 'label': '流标签', 'value': '0x%s' % (self.ipHeader.float_label) }, { 'label': '有效载荷长度', 'value': self.ipHeader.payload_length }, { 'label': '下一头部类型', 'value': '%s (%s)' % (self.ipHeader.next_header, self.ipHeader.next_header_code) }, { 'label': '跳数限制', 'value': self.ipHeader.hop_limit }, { 'label': '源 IP', 'value': self.ipHeader.source_ip }, { 'label': '目的 IP', 'value': self.ipHeader.dest_ip }] } for option in self.ipHeader.options: ipv6_header['children'].append({ 'label': consts.protocol_types[str(option['code'])], 'value': '0x' + option['value'], 'children': [{ 'label': '下一头部类型', 'value': '%s (%s)' % (consts.protocol_types[str( option['next_header'])], option['next_header']) }] }) data.append(ipv6_header) if self.ipHeader.version == 4 and self.ipHeader.flags.more_fragment == True: # print('Waiting for more fragments.') ids = self.ip_ids[self.ipHeader.identification_int] slicing = { 'label': 'IP 分片', 'value': '共 %s 个数据包' % len(ids), 'bold': True, 'children': [] } for id in ids: slicing['children'].append({ 'label': '#%s' % id, 'value': '%s Bytes' % (self.ip_packets[id].length / 8) }) data.append(slicing) else: if self.ipHeader.protocol == 'TCP': self.ipBody.tcpHeader.verifyChecksum = verifyChecksum( self.ipBody.parameters[0], self.ipBody.parameters[1], self.ipHeader.protocol).verifyChecksum self.ipBody.tcpHeader.options = tcpOptions( BitArray(self.ipBodyRaw) [160:self.ipBody.tcpHeader.header_length * 8]).options tcp_header = { 'label': 'TCP 头部 / Transmission Control Protocol Header', 'value': '', 'bold': True, 'children': [{ 'label': '源端口', 'value': self.ipBody.tcpHeader.source_port }, { 'label': '目的端口', 'value': self.ipBody.tcpHeader.destination_port }, { 'label': '数据序号 (seq)', 'value': self.ipBody.tcpHeader.sequence_number }, { 'label': '确认序号 (ack)', 'value': self.ipBody.tcpHeader.acknowledge_number }, { 'label': '首部长度', 'value': self.ipBody.tcpHeader.header_length }, { 'label': '标志位', 'value': '0x' + self.ipBody.tcpHeader.flags_raw, 'children': [{ 'label': 'Reserved', 'value': '%s | %s. .... ....' % (self.ipBody.tcpHeader.flags.reserved.uint, self.ipBody.tcpHeader.flags.reserved.bin) }, { 'label': 'Nonce', 'value': '%s | ...%d .... ....' % (self.ipBody.tcpHeader.flags.nonce, self.ipBody.tcpHeader.flags.nonce) }, { 'label': 'Congestion Window Reduced', 'value': '%s | .... %d... ....' % (self.ipBody.tcpHeader.flags.cwr, self.ipBody.tcpHeader.flags.cwr) }, { 'label': 'ECN-Echo', 'value': '%s | .... .%d.. ....' % (self.ipBody.tcpHeader.flags.ecn_echo, self.ipBody.tcpHeader.flags.ecn_echo) }, { 'label': 'Urgent', 'value': '%s | .... ..%d. ....' % (self.ipBody.tcpHeader.flags.urgent, self.ipBody.tcpHeader.flags.urgent) }, { 'label': 'Acknowledgment', 'value': '%s | .... ...%d ....' % (self.ipBody.tcpHeader.flags.acknowledgement, self.ipBody.tcpHeader.flags.acknowledgement) }, { 'label': 'Push', 'value': '%s | .... .... %d...' % (self.ipBody.tcpHeader.flags.push, self.ipBody.tcpHeader.flags.push) }, { 'label': 'Reset', 'value': '%s | .... .... .%d..' % (self.ipBody.tcpHeader.flags.reset, self.ipBody.tcpHeader.flags.reset) }, { 'label': 'Syn', 'value': '%s | .... .... ..%d.' % (self.ipBody.tcpHeader.flags.syn, self.ipBody.tcpHeader.flags.syn) }, { 'label': 'Fin', 'value': '%s | .... .... ...%d' % (self.ipBody.tcpHeader.flags.fin, self.ipBody.tcpHeader.flags.fin) }] }, { 'label': '窗口大小', 'value': self.ipBody.tcpHeader.window_size }, { 'label': '校验和', 'value': '0x%s (%s)' % (self.ipBody.tcpHeader.checksum, '校验' + { True: '通过', False: '失败' }[self.ipBody.tcpHeader.verifyChecksum]) }] } options = [] if self.ipBody.tcpHeader.options: for idx in range(len(self.ipBody.tcpHeader.options)): option = { 'label': self.ipBody.tcpHeader.options[idx][0]['label'], 'value': '(%s)' % self.ipBody.tcpHeader.options[idx][0]['value'], 'children': self.ipBody.tcpHeader.options[idx][1:] } options.append(option) if options: tcp_header['children'].append({ 'label': '选项', 'value': '', 'children': options }) data.append(tcp_header) print(self.id) print(tcp_bodies) if self.id in packet_id_struct: tmp = [] http_payload = None for p_id in packet_id_struct[self.id]: tmp.append({'value': '', 'label': '#%s' % p_id}) if self.id in tcp_bodies: # print(tcp_bodies[self.id]['data'].decode('utf-8', 'ignore')) children = [{ 'label': '该包是 TCP 分段的最后一段, 可以通过右下角按钮「导出 TCP 分段数据」.', 'value': '', 'bold': True }, { 'label': '共 %s 个分段' % len(tmp), 'value': '', 'bold': True, 'children': tmp }] try: p = HttpParser() recved = len(tcp_bodies[self.id]['data']) nparsed = p.execute( tcp_bodies[self.id]['data'], recved) assert nparsed == recved headers = [] for header in p.get_headers(): headers.append({ 'label': header, 'value': p.get_headers()[header] }) print(p.get_path(), p.get_url(), p.get_fragment(), p.get_method(), p.get_query_string(), p.get_status_code(), p.get_wsgi_environ()) http_payload = [{ 'label': 'HTTP 版本', 'value': '%s.%s' % (p.get_version()[0], p.get_version()[1]) }, { 'label': 'HTTP 头部', 'value': '', 'children': headers }] if len(p.get_url()) != 0: http_payload.append({ 'label': '请求方式', 'value': p.get_method() }) http_payload.append({ 'label': '路径', 'value': p.get_url() }) http_payload.append({ 'label': '请求参数', 'value': p.get_query_string() }) http_payload.append({ 'label': '主机名', 'value': p.get_wsgi_environ()['HTTP_HOST'] }) else: http_payload.append({ 'label': '状态码', 'value': p.get_status_code() }) except AssertionError: pass else: children = [{ 'label': '共 %s 个分段' % len(tmp), 'value': '', 'bold': True, 'children': tmp }] data.append({ 'label': 'TCP 数据 / TCP Payload', 'value': '', 'bold': True, 'children': children }) if http_payload != None: data.append({ 'label': 'HTTP 数据 / HTTP Data', 'value': '', 'bold': True, 'children': http_payload }) ''' if self.ipBody.tcpBody.has_body: try: p = HttpParser() recved = len(self.ipBody.tcpBody.buf) nparsed = p.execute(self.ipBody.tcpBody.buf, recved) assert nparsed == recved print(p.get_headers()) except AssertionError: print('NOT HTTP') data.append({ 'label': 'TCP 数据 / Data', 'value': '', 'bold': True, 'children': [ { 'label': '数据', 'value': self.ipBody.tcpBody.raw } ] }) ''' elif self.ipHeader.protocol == 'UDP': self.ipBody.udpHeader.verifyChecksum = verifyChecksum( self.ipBody.parameters[0], self.ipBody.parameters[1], self.ipHeader.protocol).verifyChecksum data.append({ 'label': 'UDP 头部 / User Datagram Protocol Header', 'value': '', 'bold': True, 'children': [{ 'label': '源端口', 'value': self.ipBody.udpHeader.source_port }, { 'label': '目的端口', 'value': self.ipBody.udpHeader.destination_port }, { 'label': '长度', 'value': self.ipBody.udpHeader.length }, { 'label': '校验和', 'value': '0x%s (%s)' % (self.ipBody.udpHeader.checksum, '校验' + { True: '通过', False: '失败' }[self.ipBody.udpHeader.verifyChecksum]) }] }) if self.ipBody.udpHeader.source_port == 53 or self.ipBody.udpHeader.destination_port == 53: # DNS children = [{ 'label': '会话标识', 'value': self.ipBody.dnsBody.transaction_id }, { 'label': '标志', 'value': '0x' + self.ipBody.dnsBody.transaction_id }, { 'label': '问题数', 'value': self.ipBody.dnsBody.questions }, { 'label': '回答资源记录数', 'value': self.ipBody.dnsBody.answer_rrs }, { 'label': '授权资源记录数', 'value': self.ipBody.dnsBody.authority_rrs }, { 'label': '附加资源记录数', 'value': self.ipBody.dnsBody.additional_rrs }] if len(self.ipBody.dnsBody.queries) > 0: queries = [] for query in self.ipBody.dnsBody.queries: queries.append({ 'label': str(query.qname), 'value': '', 'bold': True, 'children': [{ 'label': '域名', 'value': str(query.qname) }, { 'label': 'Type', 'value': '%s (%s)' % (consts.dns_types[query.qtype], query.qtype) }, { 'label': 'Class', 'value': '%s (%s)' % (consts.dns_classes[query.qclass], query.qclass) }] }) children.append({ 'label': '查询问题', 'value': '', 'bold': True, 'children': queries }) if len(self.ipBody.dnsBody.answers) > 0: answers = [] for answer in self.ipBody.dnsBody.answers: answers.append({ 'label': str(answer.rname), 'value': '', 'bold': True, 'children': [{ 'label': '域名', 'value': str(answer.rname) }, { 'label': 'Type', 'value': '%s (%s)' % (consts.dns_types[answer.rtype], answer.rtype) }, { 'label': 'Class', 'value': '%s (%s)' % (consts.dns_classes[answer.rclass], answer.rclass) }, { 'label': '生存时间 (ttl)', 'value': str(answer.ttl) }, { 'label': '数据', 'value': str(answer.rdata) }] }) children.append({ 'label': '回答', 'value': '', 'bold': True, 'children': answers }) data.append({ 'label': 'DNS / Domain Name System', 'value': '', 'bold': True, 'children': children }) elif 'ICMP' in self.ipHeader.protocol: if 'IPv6' in self.ipHeader.protocol: self.ipBody.icmpHeader.verifyChecksum = verifyChecksum( self.ipBody.parameters[0], self.ipBody.parameters[1], self.ipHeader.protocol).verifyChecksum else: self.ipBody.icmpHeader.verifyChecksum = verifyChecksum( self.ipBody.parameters, [], '').verifyChecksum data.append({ 'label': 'ICMP 头部 / Internet Control Message Protocol Headers', 'value': '', 'bold': True, 'children': [{ 'label': '类型', 'value': '%s (%s)' % (self.ipBody.icmpHeader.type, self.ipBody.icmpHeader.type_name) }, { 'label': '代码', 'value': self.ipBody.icmpHeader.code }, { 'label': '校验和', 'value': '0x%s (%s)' % (self.ipBody.icmpHeader.checksum, '校验' + { True: '通过', False: '失败' }[self.ipBody.icmpHeader.verifyChecksum]) }] }) elif 'IGMP' in self.ipHeader.protocol: if self.ipHeader.payload_length == 8: self.ipBody.igmpHeader.verifyChecksum = verifyChecksum( self.ipBody.parameters, [], '').verifyChecksum data.append({ 'label': 'IGMP 头部 / Internet Group Management Protocol Headers', 'value': '', 'bold': True, 'children': [{ 'label': '类型', 'value': '0x%s(%s)' % (self.ipBody.igmpHeader.type, self.ipBody.igmpHeader.type_name) }, { 'label': '最大响应时延', 'value': '%s 秒(0x%s)' % (self.ipBody.igmpHeader.maxRespTime, self.ipBody.igmpHeader.maxRespTimeHex) }, { 'label': '校验和', 'value': '0x%s(%s)' % (self.ipBody.igmpHeader.checksum, '校验' + { True: '通过', False: '失败' }[self.ipBody.igmpHeader.verifyChecksum]) }, { 'label': '组地址', 'value': self.ipBody.igmpHeader.groupAddress }] }) else: self.ipBody.igmpv3Header.verifyChecksum = verifyChecksum( self.ipBody.parameters, [], '').verifyChecksum data.append({ 'label': 'IGMPv3 头部 / Internet Group Management Protocol Version 3 Headers', 'value': '', 'bold': True, 'children': [{ 'label': '类型', 'value': '0x%s' % self.ipBody.igmpv3Header.type }, { 'label': '校验和', 'value': '0x%s(%s)' % (self.ipBody.igmpv3Header.checksum, '校验' + { True: '通过', False: '失败' }[self.ipBody.igmpv3Header.verifyChecksum]) }] }) return data