3 Retrieve a packet from a wireshark/tshark core file
4 and save it in a packet-capture file.
10 # Copyright (C) 2013 by Gilbert Ramirez <gram@alumni.rice.edu>
12 # This program is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 2
15 # of the License, or (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
40 re_frame
= re
.compile(r
"^#(?P<num>\d+) ")
41 re_func1
= re
.compile(r
"^#\d+\s+(?P<func>\w+) \(")
42 re_func2
= re
.compile(r
"^#\d+\s+0x[A-Fa-f\d]+ in (?P<func>\w+) \(")
44 def __init__(self
, lines
):
46 # In order; each item is the function name.
48 found_non_bt_frame
= 0
52 m
= self
.re_frame
.search(line
)
54 # Skip the first frame that gdb shows,
55 # which is not part of the backtrace.
56 if not found_non_bt_frame
:
57 found_non_bt_frame
= 1
60 # Get the frame number and make sure it's
61 # what we expect it should be.
62 frame_num
= int(m
.group("num"))
63 if frame_num
!= frame_will_be
:
64 sys
.exit("Found frame %d instead of %d" % \
65 (frame_num
, frame_will_be
))
67 # Find the function name. XXX - need to handle '???'
68 n
= self
.re_func1
.search(line
)
70 n
= self
.re_func2
.search(line
)
73 func
= n
.group("func")
75 sys
.exit("Function name not found in %s" % (line
,))
78 self
.frames
.append(func
)
85 def HasFunction(self
, func
):
86 return func
in self
.frames
88 def Frame(self
, func
):
89 return self
.frames
.index(func
)
92 # Some values from wiretap; wiretap should be a shared
93 # libray and a Python module should be created for it so
94 # this program could just write a libpcap file directly.
95 WTAP_ENCAP_PER_PACKET
= -1
96 WTAP_ENCAP_UNKNOWN
= 0
97 WTAP_ENCAP_ETHERNET
= 1
98 WTAP_ENCAP_TOKEN_RING
= 2
102 WTAP_ENCAP_FDDI_BITSWAPPED
= 6
103 WTAP_ENCAP_RAW_IP
= 7
104 WTAP_ENCAP_ARCNET
= 8
105 WTAP_ENCAP_ATM_RFC1483
= 9
106 WTAP_ENCAP_LINUX_ATM_CLIP
= 10
108 WTAP_ENCAP_ATM_SNIFFER
= 12
110 WTAP_ENCAP_ASCEND
= 14
113 WTAP_ENCAP_PPP_WITH_PHDR
= 17
114 WTAP_ENCAP_IEEE_802_11
= 18
116 WTAP_ENCAP_FRELAY
= 20
117 WTAP_ENCAP_CHDLC
= 21
118 WTAP_ENCAP_CISCO_IOS
= 22
119 WTAP_ENCAP_LOCALTALK
= 23
120 WTAP_ENCAP_PRISM_HEADER
= 24
121 WTAP_ENCAP_PFLOG
= 25
122 WTAP_ENCAP_AIROPEEK
= 26
123 WTAP_ENCAP_HHDLC
= 27
124 # last WTAP_ENCAP_ value + 1
125 WTAP_NUM_ENCAP_TYPES
= 28
129 WTAP_ENCAP_ETHERNET
: 1,
130 WTAP_ENCAP_TOKEN_RING
: 6,
131 WTAP_ENCAP_ARCNET
: 7,
134 WTAP_ENCAP_FDDI_BITSWAPPED
: 10,
135 WTAP_ENCAP_FDDI
: 10,
136 WTAP_ENCAP_ATM_RFC1483
: 11,
137 WTAP_ENCAP_RAW_IP
: 12,
138 WTAP_ENCAP_LINUX_ATM_CLIP
: 16, # or 18, or 19...
139 WTAP_ENCAP_CHDLC
: 104,
140 WTAP_ENCAP_IEEE_802_11
: 105,
141 WTAP_ENCAP_SLL
: 113,
142 WTAP_ENCAP_LOCALTALK
: 114,
143 WTAP_ENCAP_PFLOG
: 117,
144 WTAP_ENCAP_CISCO_IOS
: 118,
145 WTAP_ENCAP_PRISM_HEADER
: 119,
146 WTAP_ENCAP_HHDLC
: 121,
151 WTAP_ENCAP_UNKNOWN
: "Unknown",
152 WTAP_ENCAP_ETHERNET
: "Ethernet",
153 WTAP_ENCAP_TOKEN_RING
: "Token-Ring",
154 WTAP_ENCAP_SLIP
: "SLIP",
155 WTAP_ENCAP_PPP
: "PPP",
156 WTAP_ENCAP_FDDI
: "FDDI",
157 WTAP_ENCAP_FDDI_BITSWAPPED
: "FDDI (Bitswapped)",
158 WTAP_ENCAP_RAW_IP
: "Raw IP",
159 WTAP_ENCAP_ARCNET
: "ARCNET",
160 WTAP_ENCAP_ATM_RFC1483
: "ATM RFC1483",
161 WTAP_ENCAP_LINUX_ATM_CLIP
: "Linux ATM CLIP",
162 WTAP_ENCAP_LAPB
: "LAPB",
163 WTAP_ENCAP_ATM_SNIFFER
: "ATM Sniffer",
164 WTAP_ENCAP_NULL
: "Null",
165 WTAP_ENCAP_ASCEND
: "Ascend",
166 WTAP_ENCAP_LAPD
: "LAPD",
167 WTAP_ENCAP_V120
: "V.120",
168 WTAP_ENCAP_PPP_WITH_PHDR
: "PPP (with PHDR)",
169 WTAP_ENCAP_IEEE_802_11
: "IEEE 802.11",
170 WTAP_ENCAP_SLL
: "SLL",
171 WTAP_ENCAP_FRELAY
: "Frame Relay",
172 WTAP_ENCAP_CHDLC
: "Cisco HDLC",
173 WTAP_ENCAP_CISCO_IOS
: "Cisco IOS",
174 WTAP_ENCAP_LOCALTALK
: "LocalTalk",
175 WTAP_ENCAP_PRISM_HEADER
: "Prism Header",
176 WTAP_ENCAP_PFLOG
: "PFLog",
177 WTAP_ENCAP_AIROPEEK
: "AiroPeek",
178 WTAP_ENCAP_HHDLC
: "HHDLC",
181 def wtap_to_pcap(wtap
):
182 if not wtap_to_pcap_map
.has_key(wtap
):
183 sys
.exit("Don't know how to convert wiretap encoding %d to libpcap." % \
186 return wtap_to_pcap_map
[wtap
]
189 def run_gdb(*commands
):
190 if len(commands
) == 0:
193 # Create a temporary file
194 fname
= tempfile
.mktemp()
196 fh
= open(fname
, "w")
198 sys
.exit("Cannot open %s for writing: %s" % (fname
, err
))
200 # Put the commands in it
213 sys
.exit("Cannot close %s: %s" % (fname
, err
))
217 cmd
= "gdb --nw --quiet --command=%s %s %s" % (fname
, exec_file
, core_file
)
219 print "Invoking %s" % (cmd
,)
227 sys
.exit("Cannot run gdb: %s" % (err
,))
230 result
= pipe
.readlines()
237 sys
.exit("gdb returned an exit value of %s" % (error
,))
240 # Remove the temp file and return the results
247 def get_value_from_frame(frame_num
, variable
, fmt
=""):
250 cmds
.append("up %d" % (frame_num
,))
252 cmds
.append("print %s %s" % (fmt
, variable
))
253 lines
= apply(run_gdb
, cmds
)
255 LOOKING_FOR_START
= 0
257 state
= LOOKING_FOR_START
265 if state
== LOOKING_FOR_START
:
269 if line
[0:4] == "$1 =":
271 state
= READING_VALUE
273 elif state
== READING_VALUE
:
278 def get_int_from_frame(frame_num
, variable
):
279 text
= get_value_from_frame(frame_num
, variable
)
283 sys
.exit("Could not convert '%s' to integer." % (text
,))
287 def get_byte_array_from_frame(frame_num
, variable
, length
):
290 cmds
.append("up %d" % (frame_num
,))
292 cmds
.append("print %s" % (variable
,))
293 cmds
.append("x/%dxb %s" % (length
, variable
))
294 lines
= apply(run_gdb
, cmds
)
300 LOOKING_FOR_START
= 0
302 state
= LOOKING_FOR_START
305 if state
== LOOKING_FOR_START
:
308 elif line
[0:3] == "$1 ":
312 fields
= line
.split('\t')
313 if fields
[0][-1] != ":":
314 print "Failed to parse byte array from gdb:"
318 for field
in fields
[1:]:
326 def make_cap_file(pkt_data
, lnk_t
):
328 pcap_lnk_t
= wtap_to_pcap(lnk_t
)
330 # Create a temporary file
331 fname
= tempfile
.mktemp()
333 fh
= open(fname
, "w")
335 sys
.exit("Cannot open %s for writing: %s" % (fname
, err
))
339 # Put the hex dump in it
342 for byte
in pkt_data
:
343 if (offset
% BYTES_IN_ROW
) == 0:
344 print >> fh
, "\n%08X " % (offset
,),
345 print "\n%08X " % (offset
,),
347 print >> fh
, "%02X " % (byte
,),
348 print "%02X " % (byte
,),
361 sys
.exit("Cannot close %s: %s" % (fname
, err
))
365 cmd
= "text2pcap -q -l %s %s %s" % (pcap_lnk_t
, fname
, output_file
)
366 # print "Command is %s" % (cmd,)
368 retval
= os
.system(cmd
)
374 sys
.exit("Cannot run text2pcap: %s" % (err
,))
376 # Remove the temp file
383 print "%s created with %d bytes in packet, and %s encoding." % \
384 (output_file
, len(pkt_data
), wtap_name
[lnk_t
])
386 sys
.exit("text2pcap did not run succesfully.")
391 def try_frame(func_text
, cap_len_text
, lnk_t_text
, data_text
):
394 bt_text
= run_gdb("bt")
395 bt
= BackTrace(bt_text
)
396 if not bt
.HasFunction(func_text
):
397 print "%s() not found in backtrace." % (func_text
,)
400 print "%s() found in backtrace." % (func_text
,)
402 # Figure out where the call to epan_dissect_run is.
403 frame_num
= bt
.Frame(func_text
)
405 # Get the capture length
406 cap_len
= get_int_from_frame(frame_num
, cap_len_text
)
408 # Get the encoding type
409 lnk_t
= get_int_from_frame(frame_num
, lnk_t_text
)
411 # Get the packet data
412 pkt_data
= get_byte_array_from_frame(frame_num
, data_text
, cap_len
)
415 print "Length=%d" % (cap_len
,)
416 print "Encoding=%d" % (lnk_t
,)
417 print "Data (%d bytes) = %s" % (len(pkt_data
), pkt_data
)
418 make_cap_file(pkt_data
, lnk_t
)
422 if try_frame("epan_dissect_run",
423 "fd->cap_len", "fd->lnk_t", "data"):
425 elif try_frame("add_packet_to_packet_list",
426 "fdata->cap_len", "fdata->lnk_t", "buf"):
429 sys
.exit("A packet cannot be pulled from this core.")
433 print "pkt-from-core.py [-v] -w capture_file executable-file (core-file or process-id)"
435 print "\tGiven an executable file and a core file, this tool"
436 print "\tuses gdb to retrieve the packet that was being dissected"
437 print "\tat the time wireshark/tshark stopped running. The packet"
438 print "\tis saved in the capture_file specified by the -w option."
440 print "\t-v : verbose"
452 opts
, args
= getopt
.getopt(sys
.argv
[1:], optstring
)
456 for opt
, arg
in opts
:
466 if output_file
== None:
477 if __name__
== '__main__':