标签:
最近一直在分析数据包。凑一块儿了...于是,便开工了。座椅爆炸!
struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ };具体我就不解释了,待会儿我会用一个实例来解析。紧接着这个文件头,后面就是一个个数据包了,为了描述每一个数据包的元信息,每一个数据包都会有一个描述头:
struct pcap_pkthdr { struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present 由于tcpdump可以设置-s参数指定抓取的长度,这个字段表示实际抓取的数据包长度 */ bpf_u_int32 len; /* length this packet (off wire) 这个字段表示数据包的自然长度 */ };
这个结构体描述了数据包抓取的时间信息以及长度信息,在这个结构之后才会是数据包,因此一个典型的pcap文件应该是如下所示:
这简直清晰至极啊,再次看我的那个需求,我想统计的两个量怎么得到呢?
一个TCP连接实际发送的字节数:每一个数据包的TCP载荷长度的加和。#!/usr/bin/python import sys import socket import struct filename = sys.argv[0] filename = sys.argv[1] ipaddr = sys.argv[2] direction = sys.argv[3] packed = socket.inet_aton(ipaddr) ip32 = struct.unpack("!L", packed)[0] file = open(filename, "rb") pcaphdrlen = 24 pkthdrlen=16 pkthdrlen1=14 iphdrlen=20 tcphdrlen=20 stdtcp = 20 total = 0 pos = 0 start_seq = 0 end_seq = 0 cnt = 0 # Read 24-bytes pcap header data = file.read(pcaphdrlen) (tag, maj, min, tzone, ts, ppsize, lt) = struct.unpack("=L2p2pLLLL", data) # 具体的LinkType细节,请看: # http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html#appendixBlockCodes if lt == 0x71: pkthdrlen1 = 16 else: pkthdrlen1 = 14 ipcmp = 0 # Read 16-bytes packet header data = file.read(pkthdrlen) while data: (sec, microsec, iplensave, origlen) = struct.unpack("=LLLL", data) # read link link = file.read(pkthdrlen1) # read IP header data = file.read(iphdrlen) (vl, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr) = struct.unpack(">ssHHHssHLL", data) iphdrlen = ord(vl) & 0x0F iphdrlen *= 4 # read TCP standard header tcpdata = file.read(stdtcp) (sport, dport, seq, ack_seq, pad1, win, check, urgp) = struct.unpack(">HHLLHHHH", tcpdata) tcphdrlen = pad1 & 0xF000 tcphdrlen = tcphdrlen >> 12 tcphdrlen = tcphdrlen*4 if direction == ‘out‘: ipcmp = saddr else: ipcmp = daddr if ipcmp == ip32: cnt += 1 total += tot_len total -= iphdrlen + tcphdrlen if start_seq == 0: # BUG? start_seq = seq end_seq = seq # skip data skip = file.read(iplensave-pkthdrlen1-iphdrlen-stdtcp) # read next packet pos += 1 data = file.read(pkthdrlen) # 打印出实际传输的字节数,以及本应该传输的字节数 print pos, cnt, ‘Actual:‘+str(total), ‘ideal:‘+str(end_seq-start_seq)
我们发现pcap的文件格式中,大部分的元描述结构都是固定数量且定长的,以LinkType为例,一次抓包我只能指定一个LinkType,它被记录在pcap文件开始的pcap_file_header中,这意味着,我无法同时在以太网卡和非以太的PPP网卡上抓包并同时得到详细的链路层信息!而pcapng解决了这个问题。
欲知pcapng如何,且看下篇文字。
如果说使用tcpdump -i any参数,我们不会看到标准的以太头信息,我们看到的是Cooked Capture,而不是Ethernet!关键的是,Cooked Capture描述的元信息长度是16字节而不是Ethernet的14字节。以下是Cooked Capture的头示例:
if pos > 900: data = struct.pack("=LLLL", sec+40, microsec, iplensave, origlen) file_out.write(data)然后就重现了这个现象:
标签:
原文地址:http://blog.csdn.net/dog250/article/details/52005893