1 import struct
2 import time
3
4 PCAPH_MAGIC_NUM = 0xa1b2c3d4
5 PCAPH_VER_MAJOR = 2
6 PCAPH_VER_MINOR = 4
7 PCAPH_THISZONE = 0
8 PCAPH_SIGFIGS = 0
9 PCAPH_SNAPLEN = 65535
10
11 DOT11COMMON_TAG = 000002
12 GPS_TAG = 30002
13
15
17 '''
18 Opens the specified file, validates a libpcap header is present.
19 @type savefile: String
20 @param savefile: Input libpcap filename to open
21 @rtype: None
22 '''
23 PCAPH_LEN = 24
24 self.__fh = open(savefile, mode='rb')
25 self._pcaphsnaplen = 0
26 header = self.__fh.read(PCAPH_LEN)
27
28
29 magicnum = struct.unpack("I", header[0:4])[0]
30 if magicnum != 0xd4c3b2a1:
31
32 self.__endflag = "<"
33 elif magicnum == 0xa1b2c3d4:
34
35 self.__endflag = ">"
36 else:
37 raise Exception('Specified file is not a libpcap capture')
38
39 pcaph = struct.unpack("%sIHHIIII"%self.__endflag, header)
40 if pcaph[1] != PCAPH_VER_MAJOR and pcaph[2] != PCAPH_VER_MINOR \
41 and pcaph[3] != PCAPH_THISZONE and pcaph[4] != PCAPH_SIGFIGS \
42 and pcaph[5] != PCAPH_SNAPLEN:
43 raise Exception('Unsupported pcap header format or version')
44
45 self._pcaphsnaplen = pcaph[5]
46 self._datalink = pcaph[6]
47
49 '''
50 Returns the data link type for the packet capture.
51 @rtype: Int
52 '''
53 return self._datalink
54
56 '''
57 Closes the output packet capture; wrapper for pcap_close().
58 @rtype: None
59 '''
60 self.pcap_close()
61
63 '''
64 Closes the output packet capture.
65 @rtype: None
66 '''
67 self.__fh.close()
68
70 '''
71 Wrapper for pcap_next to mimic method for Daintree SNA. See pcap_next()
72 '''
73 return self.pcap_next()
74
76 '''
77 Retrieves the next packet from the capture file. Returns a list of
78 [Hdr, packet] where Hdr is a list of [timestamp, snaplen, plen] and
79 packet is a string of the payload content. Returns None at the end
80 of the packet capture.
81 @rtype: List
82 '''
83
84 PCAPH_RECLEN = 16
85 rechdrdata = self.__fh.read(PCAPH_RECLEN)
86
87 try:
88 rechdrtmp = struct.unpack("%sIIII"%self.__endflag, rechdrdata)
89 except struct.error:
90 return [None,None]
91
92 rechdr = [
93 float("%s.%s"%(rechdrtmp[0],rechdrtmp[1])),
94 rechdrtmp[2],
95 rechdrtmp[3]
96 ]
97 if rechdr[1] > rechdr[2] or rechdr[1] > self._pcaphsnaplen or rechdr[2] > self._pcaphsnaplen:
98 raise Exception('Corrupted or invalid libpcap record header (included length exceeds actual length)')
99
100
101 frame = self.__fh.read(rechdr[1])
102 return [rechdr, frame]
103
104
106 - def __init__(self, datalink, savefile, ppi = False):
107 '''
108 Creates a libpcap file using the specified datalink type.
109 @type datalink: Integer
110 @param datalink: Datalink type, one of DLT_* defined in pcap-bpf.h
111 @type savefile: String
112 @param savefile: Output libpcap filename to open
113 @rtype: None
114 '''
115 if ppi: from killerbee.pcapdlt import DLT_PPI
116 self.ppi = ppi
117 self.__fh = open(savefile, mode='wb')
118 self.datalink = datalink
119 self.__fh.write(''.join([
120 struct.pack("I", PCAPH_MAGIC_NUM),
121 struct.pack("H", PCAPH_VER_MAJOR),
122 struct.pack("H", PCAPH_VER_MINOR),
123 struct.pack("I", PCAPH_THISZONE),
124 struct.pack("I", PCAPH_SIGFIGS),
125 struct.pack("I", PCAPH_SNAPLEN),
126 struct.pack("I", DLT_PPI if self.ppi else self.datalink)
127 ]))
128
129 - def pcap_dump(self, packet, ts_sec=None, ts_usec=None, orig_len=None,
130 freq_mhz = None, ant_dbm = None, location = None):
131 '''
132 Appends a new packet to the libpcap file. Optionally specify ts_sec
133 and tv_usec for timestamp information, otherwise the current time is
134 used. Specify orig_len if your snaplen is smaller than the entire
135 packet contents.
136 @type ts_sec: Integer
137 @param ts_sec: Timestamp, number of seconds since Unix epoch. Default
138 is the current timestamp.
139 @type ts_usec: Integer
140 @param ts_usec: Timestamp microseconds. Defaults to current timestamp.
141 @type orig_len: Integer
142 @param orig_len: Length of the original packet, used if the packet you
143 are writing is smaller than the original packet. Defaults to the
144 specified packet's length.
145 @type location: Tuple
146 @param location: 3-tuple of (longitude, latitude, altitude).
147 @type packet: String
148 @param packet: Packet contents
149 @rtype: None
150 '''
151
152
153 if self.ppi is True:
154 pph_len = 8
155
156
157 pph_len += 24
158 rf_freq_mhz = 0x0000
159 if freq_mhz is not None: rf_freq_mhz = freq_mhz
160 rf_ant_dbm = 0
161 if ant_dbm is not None: rf_ant_dbm = ant_dbm
162 caceppi_f80211common = ''.join([
163 struct.pack("<H", DOT11COMMON_TAG),
164 struct.pack("<H", 20),
165 struct.pack("<Q", 0),
166 struct.pack("<H", 0),
167 struct.pack("<H", 0),
168 struct.pack("<H", rf_freq_mhz),
169 struct.pack("<H", 0x0080),
170 struct.pack("<B", 0),
171 struct.pack("<B", 0),
172 struct.pack("<b", rf_ant_dbm),
173 struct.pack("<b", 0)
174 ])
175
176
177 if location is not None:
178 pph_len += 20
179 (lon, lat, alt) = location
180
181 if lat > -180.00000005 and lat < 180.00000005:
182 lat_i = int(round((lat + 180.0) * 1e7))
183 else:
184 raise Exception("Latitude value is out of expected range: %.8f" % lat)
185 if lon > -180.00000005 and lon < 180.00000005:
186 lon_i = int(round((lon + 180.0) * 1e7))
187 else:
188 raise Exception("Longitude value is out of expected range: %.8f" % lon)
189 if alt > -180000.00005 and alt < 180000.00005:
190 alt_i = int(round((alt + 180000.0) * 1e4))
191 else:
192 raise Exception("Altitude value is out of expected range: %.8f" % lon)
193
194 caceppi_fgeolocation = ''.join([
195 struct.pack("<H", GPS_TAG),
196 struct.pack("<H", 20),
197 struct.pack("<B", 1),
198 struct.pack("<B", 2),
199 struct.pack("<H", 24),
200 struct.pack("<I", 0x0E),
201 struct.pack("<I", lat_i),
202 struct.pack("<I", lon_i),
203 struct.pack("<I", alt_i),
204 ])
205
206
207 caceppi_hdr = ''.join([
208 struct.pack("<B", 0),
209 struct.pack("<B", 0x00),
210 struct.pack("<H", pph_len),
211 struct.pack("<I", self.datalink)
212 ])
213
214 if ts_sec == None or ts_usec == None:
215
216 s_sec, s_usec = str(time.time()).split(".")
217 ts_sec = int(s_sec)
218 ts_usec = int(s_usec)
219
220 plen = len(packet)
221 if orig_len == None:
222 orig_len = plen
223
224
225 output_list = [ struct.pack("I", ts_sec),
226 struct.pack("I", ts_usec),
227 struct.pack("I", orig_len),
228 struct.pack("I", plen) ]
229
230 if self.ppi is True:
231 output_list[2] = struct.pack("I", orig_len + pph_len)
232 output_list[3] = struct.pack("I", plen + pph_len)
233 output_list.append(caceppi_hdr)
234 if location is not None:
235 output_list.append(caceppi_fgeolocation)
236 output_list.append(caceppi_f80211common)
237
238 output_list.append(packet)
239 output = ''.join(output_list)
240
241
242
243
244
245
246 self.__fh.write(output)
247
248 try:
249 self.__fh.flush()
250 except IOError, e:
251 raise e
252
253 return
254
255
257 '''
258 Closes the output packet capture; wrapper for pcap_close().
259 @rtype: None
260 '''
261 self.pcap_close()
262
264 '''
265 Closed the output packet capture.
266 @rtype: None
267 '''
268 self.__fh.close()
269