xref: /libbtbb/python/pcaptools/pcapdump/pcapdump.py (revision e25b118a40ed6b5c2ea76bae29e388cfbc2f6e92)
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