1*e25b118aSDominic Spill# Copyright 2009 Joshua Wright 2*e25b118aSDominic Spill# 3*e25b118aSDominic Spill# This file is part of gr-bluetooth 4*e25b118aSDominic Spill# 5*e25b118aSDominic Spill# gr-bluetooth is free software; you can redistribute it and/or modify 6*e25b118aSDominic Spill# it under the terms of the GNU General Public License as published by 7*e25b118aSDominic Spill# the Free Software Foundation; either version 2, or (at your option) 8*e25b118aSDominic Spill# any later version. 9*e25b118aSDominic Spill# 10*e25b118aSDominic Spill# gr-bluetooth is distributed in the hope that it will be useful, 11*e25b118aSDominic Spill# but WITHOUT ANY WARRANTY; without even the implied warranty of 12*e25b118aSDominic Spill# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*e25b118aSDominic Spill# GNU General Public License for more details. 14*e25b118aSDominic Spill# 15*e25b118aSDominic Spill# You should have received a copy of the GNU General Public License 16*e25b118aSDominic Spill# along with gr-bluetooth; see the file COPYING. If not, write to 17*e25b118aSDominic Spill# the Free Software Foundation, Inc., 51 Franklin Street, 18*e25b118aSDominic Spill# Boston, MA 02110-1301, USA. 19*e25b118aSDominic Spill 20*e25b118aSDominic Spillimport struct 21*e25b118aSDominic Spillimport time 22*e25b118aSDominic Spill 23*e25b118aSDominic SpillPCAPH_MAGIC_NUM = 0xa1b2c3d4 24*e25b118aSDominic SpillPCAPH_VER_MAJOR = 2 25*e25b118aSDominic SpillPCAPH_VER_MINOR = 4 26*e25b118aSDominic SpillPCAPH_THISZONE = 0 27*e25b118aSDominic SpillPCAPH_SIGFIGS = 0 28*e25b118aSDominic SpillPCAPH_SNAPLEN = 65535 29*e25b118aSDominic Spill 30*e25b118aSDominic Spillclass PcapReader: 31*e25b118aSDominic Spill 32*e25b118aSDominic Spill def __init__(self, savefile): 33*e25b118aSDominic Spill ''' 34*e25b118aSDominic Spill Opens the specified file, validates a libpcap header is present. 35*e25b118aSDominic Spill @type savefile: String 36*e25b118aSDominic Spill @param savefile: Input libpcap filename to open 37*e25b118aSDominic Spill @rtype: None 38*e25b118aSDominic Spill ''' 39*e25b118aSDominic Spill PCAPH_LEN = 24 40*e25b118aSDominic Spill self.__fh = open(savefile, mode='rb') 41*e25b118aSDominic Spill self._pcaphsnaplen = 0 42*e25b118aSDominic Spill header = self.__fh.read(PCAPH_LEN) 43*e25b118aSDominic Spill 44*e25b118aSDominic Spill # Read the first 4 bytes for the magic number, determine endianness 45*e25b118aSDominic Spill magicnum = struct.unpack("I", header[0:4])[0] 46*e25b118aSDominic Spill if magicnum != 0xd4c3b2a1: 47*e25b118aSDominic Spill # Little endian 48*e25b118aSDominic Spill self.__endflag = "<" 49*e25b118aSDominic Spill elif magicnum == 0xa1b2c3d4: 50*e25b118aSDominic Spill # Big endign 51*e25b118aSDominic Spill self.__endflag = ">" 52*e25b118aSDominic Spill else: 53*e25b118aSDominic Spill raise Exception('Specified file is not a libpcap capture') 54*e25b118aSDominic Spill 55*e25b118aSDominic Spill pcaph = struct.unpack("%sIHHIIII"%self.__endflag, header) 56*e25b118aSDominic Spill if pcaph[1] != PCAPH_VER_MAJOR and pcaph[2] != PCAPH_VER_MINOR \ 57*e25b118aSDominic Spill and pcaph[3] != PCAPH_THISZONE and pcaph[4] != PCAPH_SIGFIGS \ 58*e25b118aSDominic Spill and pcaph[5] != PCAPH_SNAPLEN: 59*e25b118aSDominic Spill raise Exception('Unsupported pcap header format or version') 60*e25b118aSDominic Spill 61*e25b118aSDominic Spill self._pcaphsnaplen = pcaph[5] 62*e25b118aSDominic Spill self._datalink = pcaph[6] 63*e25b118aSDominic Spill 64*e25b118aSDominic Spill def datalink(self): 65*e25b118aSDominic Spill return self._datalink 66*e25b118aSDominic Spill 67*e25b118aSDominic Spill def close(self): 68*e25b118aSDominic Spill ''' 69*e25b118aSDominic Spill Closes the output packet capture; wrapper for pcap_close(). 70*e25b118aSDominic Spill @rtype: None 71*e25b118aSDominic Spill ''' 72*e25b118aSDominic Spill self.pcap_close() 73*e25b118aSDominic Spill 74*e25b118aSDominic Spill def pcap_close(self): 75*e25b118aSDominic Spill ''' 76*e25b118aSDominic Spill Closes the output packet capture. 77*e25b118aSDominic Spill @rtype: None 78*e25b118aSDominic Spill ''' 79*e25b118aSDominic Spill self.__fh.close() 80*e25b118aSDominic Spill 81*e25b118aSDominic Spill def pnext(self): 82*e25b118aSDominic Spill ''' 83*e25b118aSDominic Spill Wrapper for pcap_next to mimic method for Daintree SNA 84*e25b118aSDominic Spill ''' 85*e25b118aSDominic Spill return self.pcap_next() 86*e25b118aSDominic Spill 87*e25b118aSDominic Spill def pcap_next(self): 88*e25b118aSDominic Spill ''' 89*e25b118aSDominic Spill Retrieves the next packet from the capture file. Returns a list of 90*e25b118aSDominic Spill [Hdr, packet] where Hdr is a list of [timestamp, snaplen, plen] and 91*e25b118aSDominic Spill packet is a string of the payload content. Returns None at the end 92*e25b118aSDominic Spill of the packet capture. 93*e25b118aSDominic Spill @rtype: List 94*e25b118aSDominic Spill ''' 95*e25b118aSDominic Spill # Read the next header block 96*e25b118aSDominic Spill PCAPH_RECLEN = 16 97*e25b118aSDominic Spill rechdrdata = self.__fh.read(PCAPH_RECLEN) 98*e25b118aSDominic Spill 99*e25b118aSDominic Spill try: 100*e25b118aSDominic Spill rechdrtmp = struct.unpack("%sIIII"%self.__endflag, rechdrdata) 101*e25b118aSDominic Spill except struct.error: 102*e25b118aSDominic Spill return [None,None] 103*e25b118aSDominic Spill 104*e25b118aSDominic Spill rechdr = [ 105*e25b118aSDominic Spill float("%s.%s"%(rechdrtmp[0],rechdrtmp[1])), 106*e25b118aSDominic Spill rechdrtmp[2], 107*e25b118aSDominic Spill rechdrtmp[3] 108*e25b118aSDominic Spill ] 109*e25b118aSDominic Spill if rechdr[1] > rechdr[2] or rechdr[1] > self._pcaphsnaplen or rechdr[2] > self._pcaphsnaplen: 110*e25b118aSDominic Spill raise Exception('Corrupted or invalid libpcap record header (included length exceeds actual length)') 111*e25b118aSDominic Spill 112*e25b118aSDominic Spill # Read the included packet length 113*e25b118aSDominic Spill frame = self.__fh.read(rechdr[1]) 114*e25b118aSDominic Spill return [rechdr, frame] 115*e25b118aSDominic Spill 116*e25b118aSDominic Spill 117*e25b118aSDominic Spillclass PcapDumper: 118*e25b118aSDominic Spill 119*e25b118aSDominic Spill def __init__(self, datalink, savefile): 120*e25b118aSDominic Spill ''' 121*e25b118aSDominic Spill Creates a libpcap file using the specified datalink type. 122*e25b118aSDominic Spill @type datalink: Integer 123*e25b118aSDominic Spill @param datalink: Datalink type, one of DLT_* defined in pcap-bpf.h 124*e25b118aSDominic Spill @type savefile: String 125*e25b118aSDominic Spill @param savefile: Output libpcap filename to open 126*e25b118aSDominic Spill @rtype: None 127*e25b118aSDominic Spill ''' 128*e25b118aSDominic Spill self.__fh = open(savefile, mode='wb') 129*e25b118aSDominic Spill self.__fh.write(''.join([ 130*e25b118aSDominic Spill struct.pack("I", PCAPH_MAGIC_NUM), 131*e25b118aSDominic Spill struct.pack("H", PCAPH_VER_MAJOR), 132*e25b118aSDominic Spill struct.pack("H", PCAPH_VER_MINOR), 133*e25b118aSDominic Spill struct.pack("I", PCAPH_THISZONE), 134*e25b118aSDominic Spill struct.pack("I", PCAPH_SIGFIGS), 135*e25b118aSDominic Spill struct.pack("I", PCAPH_SNAPLEN), 136*e25b118aSDominic Spill struct.pack("I", datalink) 137*e25b118aSDominic Spill ])) 138*e25b118aSDominic Spill 139*e25b118aSDominic Spill def pcap_dump(self, packet, ts_sec=None, ts_usec=None, orig_len=None): 140*e25b118aSDominic Spill ''' 141*e25b118aSDominic Spill Appends a new packet to the libpcap file. Optionally specify ts_sec 142*e25b118aSDominic Spill and tv_usec for timestamp information, otherwise the current time is 143*e25b118aSDominic Spill used. Specify orig_len if your snaplen is smaller than the entire 144*e25b118aSDominic Spill packet contents. 145*e25b118aSDominic Spill @type ts_sec: Integer 146*e25b118aSDominic Spill @param ts_sec: Timestamp, number of seconds since Unix epoch. Default 147*e25b118aSDominic Spill is the current timestamp. 148*e25b118aSDominic Spill @type ts_usec: Integer 149*e25b118aSDominic Spill @param ts_usec: Timestamp microseconds. Defaults to current timestamp. 150*e25b118aSDominic Spill @type orig_len: Integer 151*e25b118aSDominic Spill @param orig_len: Length of the original packet, used if the packet you 152*e25b118aSDominic Spill are writing is smaller than the original packet. Defaults to the 153*e25b118aSDominic Spill specified packet's length. 154*e25b118aSDominic Spill @type packet: String 155*e25b118aSDominic Spill @param packet: Packet contents 156*e25b118aSDominic Spill @rtype: None 157*e25b118aSDominic Spill ''' 158*e25b118aSDominic Spill 159*e25b118aSDominic Spill if ts_sec == None or ts_usec == None: 160*e25b118aSDominic Spill # There must be a better way here that I don't know -JW 161*e25b118aSDominic Spill s_sec, s_usec = str(time.time()).split(".") 162*e25b118aSDominic Spill ts_sec = int(s_sec) 163*e25b118aSDominic Spill ts_usec = int(s_usec) 164*e25b118aSDominic Spill 165*e25b118aSDominic Spill if orig_len == None: 166*e25b118aSDominic Spill orig_len = len(packet) 167*e25b118aSDominic Spill 168*e25b118aSDominic Spill plen = len(packet) 169*e25b118aSDominic Spill 170*e25b118aSDominic Spill self.__fh.write(''.join([ 171*e25b118aSDominic Spill struct.pack("I", ts_sec), 172*e25b118aSDominic Spill struct.pack("I", ts_usec), 173*e25b118aSDominic Spill struct.pack("I", orig_len), 174*e25b118aSDominic Spill struct.pack("I", plen), 175*e25b118aSDominic Spill packet 176*e25b118aSDominic Spill ])) 177*e25b118aSDominic Spill 178*e25b118aSDominic Spill return 179*e25b118aSDominic Spill 180*e25b118aSDominic Spill 181*e25b118aSDominic Spill def close(self): 182*e25b118aSDominic Spill ''' 183*e25b118aSDominic Spill Closes the output packet capture; wrapper for pcap_close(). 184*e25b118aSDominic Spill @rtype: None 185*e25b118aSDominic Spill ''' 186*e25b118aSDominic Spill self.pcap_close() 187*e25b118aSDominic Spill 188*e25b118aSDominic Spill def pcap_close(self): 189*e25b118aSDominic Spill ''' 190*e25b118aSDominic Spill Closed the output packet capture. 191*e25b118aSDominic Spill @rtype: None 192*e25b118aSDominic Spill ''' 193*e25b118aSDominic Spill self.__fh.close() 194