pcap2har

概述
pcap2har: 把.pcap网络抓包文件转换为HTTP Archive file(HAR),是一个开源项目,使用python开发,依赖dpkt库( http://code.google.com/p/dpkt/),githup地址:https://github.com/andrewf/pcap2har。
可以通过简单的运行如下命令来使用该程序:
main.py  my.pcap my.har
第一个参数是pcap文件名,第二个参数是输出的har文件的名称。
HTTP Archive (HAR)文件格式说明文档:
http://groups.google.com/group/http-archive-specification/web/har-1-1-spec?hl=en

安装dpkt
下载解压dpkt后,执行其中的setup.py(python setup.py install)

结构分析
main.py
主要部分
# parse pcap file
dispatcher = pcap.EasyParsePcap(filename=inputfile)

# parse HAR stuff
session = httpsession.HttpSession(dispatcher)

logging.info('Flows=%d. HTTP pairs=%d' % (len(session.flows), len(session.entries)))

#write the HAR file
with open(outputfile, 'w') as f:
    json.dump(session, f, cls=har.JsonReprEncoder, indent=2, encoding='utf8', sort_keys=True)
主要步骤
1 调用pcap模块解析pcap文件
def EasyParsePcap(filename=None, reader=None):
    '''
    Like ParsePcap, but makes and returns a PacketDispatcher for you.
    '''
    dispatcher = PacketDispatcher()
    ParsePcap(dispatcher, filename=filename, reader=reader)
    dispatcher.finish()
    return dispatcher

该函数首先创建一个PacketDispatcher(),它的作用如其名,就是一个分包器,即按照协议把包分发给不同的模块进行处理,比如TCP包分发给TCP模块进行处理,UDP包分发给UDP模块进行处理。接着调用ParsePcap函数,该函数通过dpkt解析pcap文件,读入pcap文件,输出一个个的Packet,每个packet的格式如下:
ts = packet[0]   # 时间戳
buf = packet[1]  # 帧数据
hdr = packet[2]  # pcap文件头
实际的包数据在packet[1]中,包括了IP头、TCP/IP头、包数据。根据链路层协议的不同,读取帧数据的方式不同。

# handle SLL packets, thanks Libo
dltoff = dpkt.pcap.dltoff
if pcap.dloff == dltoff[dpkt.pcap.DLT_LINUX_SLL]:
    eth = dpkt.sll.SLL(buf)
# otherwise, for now, assume Ethernet
else:
    eth = dpkt.ethernet.Ethernet(buf)
dispatcher.add(ts, buf, eth)

如果是UDP包,可以这样取得包数据:
ip = eth.data
udppkt = ip.data
udpdata = udppkt.data

我们关心的实际上不是一个个单个的包,而是资源的加载时间等信息。单个资源的加载过程由发起请求开始,到接收完响应,这称之为一个flow,一个flow就可以抽象为几个部分,request、response、以及其它一些描述流的属性,称之为一个Entry。流是由一个个packet组成的,解析pcap文件,首先解析为一个个的packet,然后再组装为flow,最终形成一个Entry集。entries是HAR文件的重要组成部分。根据packet组成为流的过程,比较复杂,涉及到包的重组、数据解压等。

HAR文件的输出是由httpsession.py中json_repr完成的:
def json_repr(self):
        '''
        return a JSON serializable python object representation of self.
        '''
        d = {
            'log': {
                'version': '1.1',
                'creator': {
                    'name': 'pcap2har',
                    'version': '0.1'
                },
                'browser': {
                    'name': self.user_agent,
                    'version': 'mumble'
                },
                'entries': sorted(self.entries, key=lambda x: x.ts_start)
            }
        }
        if self.page_tracker:
            d['log']['pages'] = self.page_tracker
        return d

一个问题
dpkt_http_replacement.py中
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
对于一些不是严格遵从标准的响应头,会抛出dpkt.UnpackError。比如冒号“:”后面没有空白分隔符
SINA-LB:aGEuMzkuZzEuc2h4LmxiLnNpbmFub2RlLmNvbQ==

可以改为
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
        #to fix a bug of "raise error when line like this: SINA-TS:YzVmMjk0Y2UgMTMgMTUgMSAxMSA3Cg==\r\n"
       
        pos = line.find(':')
        if pos == -1:
            raise dpkt.UnpackError('invalid header: %r' % line)
        k = line[0:pos].lower()
        v = line[pos+1:].strip()
       
        if k in d:
            d[k] += ','+v
        else:
            d[k] = v
    return d

log信息
该模块执行过程中的log信息会输出到pcap2har.log中

其中的一些数据结构
response.msg.header结构
{'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'set-cookie': 'if_mid=1XgDcC; expires=Sun, 21-Sep-2014 09:42:53 GMT; path=/; domain=ifeng.com', 'vary': 'Accept-Encoding', 'server': 'IfengWeb/2.4.6', 'load-balancing': 'bjhh78', 'connection': 'close', 'date': 'Thu, 18 Sep 2014 09:42:53 GMT', 'content-type': 'text/html'}

request.msg结构
GET / HTTP/1.1
x-ucbrowser-ua: dv(H30-T10);pr(UCBrowser/9.9.4.484);ov(Android 4.2.2);ss(720*1230);bt(UC);pm(1);bv(1);nm(0);im(0);sr(0);nt(2);
accept-language: zh-CN
accept-encoding: gzip
connection: keep-alive
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,UC/145,plugin/1,alipay/un
user-agent: Mozilla/5.0 (Linux; U; Android 4.2.2; zh-CN; H30-T10 Build/JDQ39) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.9.4.484 U3/0.8.0 Mobile Safari/533.1
host: i.ifeng.com
cookie: if_sn818=3; if_mid=1XgDcC
referer:  http://183.61.109.210:30003/c/c.php?url=http://i.ifeng.com

不确定的结构,可以在运行过程中通过print打印出来查看。


你可能感兴趣的:(pcap2har)