3 Retrieve a packet from a wireshark/tshark core file
4 and save it in a packet-capture file.
7 # Copyright (C) 2013 by Gilbert Ramirez <gram@alumni.rice.edu>
9 # SPDX-License-Identifier: GPL-2.0-or-later
25 re_frame
= re
.compile(r
"^#(?P<num>\d+) ")
26 re_func1
= re
.compile(r
"^#\d+\s+(?P<func>\w+) \(")
27 re_func2
= re
.compile(r
"^#\d+\s+0x[A-Fa-f\d]+ in (?P<func>\w+) \(")
29 def __init__(self
, lines
):
31 # In order; each item is the function name.
33 found_non_bt_frame
= 0
37 m
= self
.re_frame
.search(line
)
39 # Skip the first frame that gdb shows,
40 # which is not part of the backtrace.
41 if not found_non_bt_frame
:
42 found_non_bt_frame
= 1
45 # Get the frame number and make sure it's
46 # what we expect it should be.
47 frame_num
= int(m
.group("num"))
48 if frame_num
!= frame_will_be
:
49 sys
.exit("Found frame %d instead of %d" %
50 (frame_num
, frame_will_be
))
52 # Find the function name. XXX - need to handle '???'
53 n
= self
.re_func1
.search(line
)
55 n
= self
.re_func2
.search(line
)
58 func
= n
.group("func")
60 sys
.exit("Function name not found in %s" % (line
,))
63 self
.frames
.append(func
)
70 def HasFunction(self
, func
):
71 return func
in self
.frames
73 def Frame(self
, func
):
74 return self
.frames
.index(func
)
77 # Some values from wiretap; wiretap should be a shared
78 # libray and a Python module should be created for it so
79 # this program could just write a libpcap file directly.
81 WTAP_ENCAP_PER_PACKET
= -1
82 WTAP_ENCAP_UNKNOWN
= 0
83 WTAP_ENCAP_ETHERNET
= 1
84 WTAP_ENCAP_TOKEN_RING
= 2
88 WTAP_ENCAP_FDDI_BITSWAPPED
= 6
91 WTAP_ENCAP_ATM_RFC1483
= 9
92 WTAP_ENCAP_LINUX_ATM_CLIP
= 10
94 WTAP_ENCAP_ATM_SNIFFER
= 12
96 WTAP_ENCAP_ASCEND
= 14
99 WTAP_ENCAP_PPP_WITH_PHDR
= 17
100 WTAP_ENCAP_IEEE_802_11
= 18
102 WTAP_ENCAP_FRELAY
= 20
103 WTAP_ENCAP_CHDLC
= 21
104 WTAP_ENCAP_CISCO_IOS
= 22
105 WTAP_ENCAP_LOCALTALK
= 23
106 WTAP_ENCAP_PRISM_HEADER
= 24
107 WTAP_ENCAP_PFLOG
= 25
108 WTAP_ENCAP_AIROPEEK
= 26
109 WTAP_ENCAP_HHDLC
= 27
110 # last WTAP_ENCAP_ value + 1
111 WTAP_NUM_ENCAP_TYPES
= 28
115 WTAP_ENCAP_ETHERNET
: 1,
116 WTAP_ENCAP_TOKEN_RING
: 6,
117 WTAP_ENCAP_ARCNET
: 7,
120 WTAP_ENCAP_FDDI_BITSWAPPED
: 10,
121 WTAP_ENCAP_FDDI
: 10,
122 WTAP_ENCAP_ATM_RFC1483
: 11,
123 WTAP_ENCAP_RAW_IP
: 12,
124 WTAP_ENCAP_LINUX_ATM_CLIP
: 16, # or 18, or 19...
125 WTAP_ENCAP_CHDLC
: 104,
126 WTAP_ENCAP_IEEE_802_11
: 105,
127 WTAP_ENCAP_SLL
: 113,
128 WTAP_ENCAP_LOCALTALK
: 114,
129 WTAP_ENCAP_PFLOG
: 117,
130 WTAP_ENCAP_CISCO_IOS
: 118,
131 WTAP_ENCAP_PRISM_HEADER
: 119,
132 WTAP_ENCAP_HHDLC
: 121,
137 WTAP_ENCAP_NONE
: "None",
138 WTAP_ENCAP_UNKNOWN
: "Unknown",
139 WTAP_ENCAP_ETHERNET
: "Ethernet",
140 WTAP_ENCAP_TOKEN_RING
: "Token-Ring",
141 WTAP_ENCAP_SLIP
: "SLIP",
142 WTAP_ENCAP_PPP
: "PPP",
143 WTAP_ENCAP_FDDI
: "FDDI",
144 WTAP_ENCAP_FDDI_BITSWAPPED
: "FDDI (Bitswapped)",
145 WTAP_ENCAP_RAW_IP
: "Raw IP",
146 WTAP_ENCAP_ARCNET
: "ARCNET",
147 WTAP_ENCAP_ATM_RFC1483
: "ATM RFC1483",
148 WTAP_ENCAP_LINUX_ATM_CLIP
: "Linux ATM CLIP",
149 WTAP_ENCAP_LAPB
: "LAPB",
150 WTAP_ENCAP_ATM_SNIFFER
: "ATM Sniffer",
151 WTAP_ENCAP_NULL
: "Null",
152 WTAP_ENCAP_ASCEND
: "Ascend",
153 WTAP_ENCAP_LAPD
: "LAPD",
154 WTAP_ENCAP_V120
: "V.120",
155 WTAP_ENCAP_PPP_WITH_PHDR
: "PPP (with PHDR)",
156 WTAP_ENCAP_IEEE_802_11
: "IEEE 802.11",
157 WTAP_ENCAP_SLL
: "SLL",
158 WTAP_ENCAP_FRELAY
: "Frame Relay",
159 WTAP_ENCAP_CHDLC
: "Cisco HDLC",
160 WTAP_ENCAP_CISCO_IOS
: "Cisco IOS",
161 WTAP_ENCAP_LOCALTALK
: "LocalTalk",
162 WTAP_ENCAP_PRISM_HEADER
: "Prism Header",
163 WTAP_ENCAP_PFLOG
: "PFLog",
164 WTAP_ENCAP_AIROPEEK
: "AiroPeek",
165 WTAP_ENCAP_HHDLC
: "HHDLC",
168 def wtap_to_pcap(wtap
):
169 if not wtap_to_pcap_map
.has_key(wtap
):
170 sys
.exit("Don't know how to convert wiretap encoding %d to libpcap." % \
173 return wtap_to_pcap_map
[wtap
]
176 def run_gdb(*commands
):
177 if len(commands
) == 0:
180 # Create a temporary file
181 fname
= tempfile
.mktemp()
183 fh
= open(fname
, "w")
185 sys
.exit("Cannot open %s for writing: %s" % (fname
, err
))
187 # Put the commands in it
200 sys
.exit("Cannot close %s: %s" % (fname
, err
))
204 cmd
= "gdb --nw --quiet --command=%s %s %s" % (fname
, exec_file
, core_file
)
206 print "Invoking %s" % (cmd
,)
214 sys
.exit("Cannot run gdb: %s" % (err
,))
217 result
= pipe
.readlines()
219 if error
is not None:
224 sys
.exit("gdb returned an exit value of %s" % (error
,))
227 # Remove the temp file and return the results
234 def get_value_from_frame(frame_num
, variable
, fmt
=""):
237 cmds
.append("up %d" % (frame_num
,))
239 cmds
.append("print %s %s" % (fmt
, variable
))
240 lines
= apply(run_gdb
, cmds
)
242 LOOKING_FOR_START
= 0
244 state
= LOOKING_FOR_START
252 if state
== LOOKING_FOR_START
:
256 if line
[0:4] == "$1 =":
258 state
= READING_VALUE
260 elif state
== READING_VALUE
:
265 def get_int_from_frame(frame_num
, variable
):
266 text
= get_value_from_frame(frame_num
, variable
)
270 sys
.exit("Could not convert '%s' to integer." % (text
,))
274 def get_byte_array_from_frame(frame_num
, variable
, length
):
277 cmds
.append("up %d" % (frame_num
,))
279 cmds
.append("print %s" % (variable
,))
280 cmds
.append("x/%dxb %s" % (length
, variable
))
281 lines
= apply(run_gdb
, cmds
)
287 LOOKING_FOR_START
= 0
289 state
= LOOKING_FOR_START
292 if state
== LOOKING_FOR_START
:
295 elif line
[0:3] == "$1 ":
299 fields
= line
.split('\t')
300 if fields
[0][-1] != ":":
301 print "Failed to parse byte array from gdb:"
305 for field
in fields
[1:]:
313 def make_cap_file(pkt_data
, lnk_t
):
315 pcap_lnk_t
= wtap_to_pcap(lnk_t
)
317 # Create a temporary file
318 fname
= tempfile
.mktemp()
320 fh
= open(fname
, "w")
322 sys
.exit("Cannot open %s for writing: %s" % (fname
, err
))
326 # Put the hex dump in it
329 for byte
in pkt_data
:
330 if (offset
% BYTES_IN_ROW
) == 0:
331 print >> fh
, "\n%08X " % (offset
,),
332 print "\n%08X " % (offset
,),
334 print >> fh
, "%02X " % (byte
,),
335 print "%02X " % (byte
,),
348 sys
.exit("Cannot close %s: %s" % (fname
, err
))
352 cmd
= "text2pcap -q -l %s %s %s" % (pcap_lnk_t
, fname
, output_file
)
353 # print "Command is %s" % (cmd,)
355 retval
= os
.system(cmd
)
361 sys
.exit("Cannot run text2pcap: %s" % (err
,))
363 # Remove the temp file
370 print "%s created with %d bytes in packet, and %s encoding." % \
371 (output_file
, len(pkt_data
), wtap_name
[lnk_t
])
373 sys
.exit("text2pcap did not run successfully.")
378 def try_frame(func_text
, cap_len_text
, lnk_t_text
, data_text
):
381 bt_text
= run_gdb("bt")
382 bt
= BackTrace(bt_text
)
383 if not bt
.HasFunction(func_text
):
384 print "%s() not found in backtrace." % (func_text
,)
387 print "%s() found in backtrace." % (func_text
,)
389 # Figure out where the call to epan_dissect_run is.
390 frame_num
= bt
.Frame(func_text
)
392 # Get the capture length
393 cap_len
= get_int_from_frame(frame_num
, cap_len_text
)
395 # Get the encoding type
396 lnk_t
= get_int_from_frame(frame_num
, lnk_t_text
)
398 # Get the packet data
399 pkt_data
= get_byte_array_from_frame(frame_num
, data_text
, cap_len
)
402 print "Length=%d" % (cap_len
,)
403 print "Encoding=%d" % (lnk_t
,)
404 print "Data (%d bytes) = %s" % (len(pkt_data
), pkt_data
)
405 make_cap_file(pkt_data
, lnk_t
)
409 if try_frame("epan_dissect_run",
410 "fd->cap_len", "fd->lnk_t", "data"):
412 elif try_frame("add_packet_to_packet_list",
413 "fdata->cap_len", "fdata->lnk_t", "buf"):
416 sys
.exit("A packet cannot be pulled from this core.")
420 print "pkt-from-core.py [-v] -w capture_file executable-file (core-file or process-id)"
422 print "\tGiven an executable file and a core file, this tool"
423 print "\tuses gdb to retrieve the packet that was being dissected"
424 print "\tat the time wireshark/tshark stopped running. The packet"
425 print "\tis saved in the capture_file specified by the -w option."
427 print "\t-v : verbose"
439 opts
, args
= getopt
.getopt(sys
.argv
[1:], optstring
)
443 for opt
, arg
in opts
:
453 if output_file
is None:
464 if __name__
== '__main__':
468 # Editor modelines - https://www.wireshark.org/tools/modelines.html
472 # indent-tabs-mode: nil
475 # vi: set shiftwidth=4 expandtab:
476 # :indentSize=4:noTabs=true: