3 # By Gerald Combs <gerald@wireshark.org>
5 # Ported from a set of Bash scripts which were copyright 2005 Ulf Lamping
7 # SPDX-License-Identifier: GPL-2.0-or-later
9 '''Wireshark Lua scripting tests'''
19 dhcp_pcap
= 'dhcp.pcap'
20 dns_port_pcap
= 'dns_port.pcap'
21 empty_pcap
= 'empty.pcap'
22 segmented_fpm_pcap
= 'segmented_fpm.pcap'
23 sip_pcapng
= 'sip.pcapng'
24 sipmsg_log
= 'sipmsg.log'
25 wpa_induction_pcap_gz
= 'wpa-Induction.pcap.gz'
29 def check_lua_script(cmd_tshark
, features
, dirs
, capture_file
, test_env
):
30 if not features
.have_lua
:
31 pytest
.skip('Test requires Lua scripting support.')
32 def check_lua_script_real(lua_script
, cap_file
, check_passed
, *args
):
33 tshark_cmd
= [cmd_tshark
,
34 '-r', capture_file(cap_file
),
35 '-X', 'lua_script:' + os
.path
.join(dirs
.lua_dir
, lua_script
)
38 tshark_proc
= subprocess
.run(tshark_cmd
, check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
41 logging
.info(tshark_proc
.stdout
)
42 logging
.info(tshark_proc
.stderr
)
43 if not 'All tests passed!' in tshark_proc
.stdout
:
44 pytest
.fail("Some test failed, check the logs (eg: pytest --lf --log-cli-level=info)")
47 return check_lua_script_real
51 def check_lua_script_verify(check_lua_script
, result_file
):
52 def check_lua_script_verify_real(lua_script
, cap_file
, check_stage_1
=False, heur_regmode
=None):
53 # First run tshark with the dissector script.
54 if heur_regmode
is None:
55 tshark_proc
= check_lua_script(lua_script
, cap_file
, check_stage_1
,
59 tshark_proc
= check_lua_script(lua_script
, cap_file
, check_stage_1
,
61 '-X', 'lua_script1:heur_regmode={}'.format(heur_regmode
)
64 # then dump tshark's output to a verification file.
65 verify_file
= result_file('testin.txt')
66 with
open(verify_file
, 'w', newline
='\n') as f
:
67 f
.write(tshark_proc
.stdout
)
69 # finally run tshark again with the verification script and the verification file.
70 if heur_regmode
is None:
71 check_lua_script('verify_dissector.lua', empty_pcap
, True,
72 '-X', 'lua_script1:verify_file=' + verify_file
,
75 check_lua_script('verify_dissector.lua', empty_pcap
, True,
76 '-X', 'lua_script1:verify_file=' + verify_file
,
77 '-X', 'lua_script1:no_heur',
79 return check_lua_script_verify_real
82 def check_lua_script_locale(cmd_tshark
, features
, dirs
, capture_file
, test_env
):
83 if not features
.have_lua
:
84 pytest
.skip('Test requires Lua scripting support.')
85 # run a Lua script under a particular locale. On UN*X we could set
86 # environment variables in the test environment (which could make
87 # this easier to do with less code duplication), but Windows doesn't
88 # set the locale based on the environment variables so we do it
89 # in a Lua script calling os.setlocale
90 def check_lua_script_locale_real(lua_script
, cap_file
, check_passed
, test_locale
= None, *args
):
91 tshark_cmd
= [cmd_tshark
,
92 '-r', capture_file(cap_file
),
93 '-X', 'lua_script:' + os
.path
.join(dirs
.lua_dir
, 'locale.lua'),
94 '-X', 'lua_script:' + os
.path
.join(dirs
.lua_dir
, lua_script
),
96 if test_locale
is not None:
97 tshark_cmd
+= ['-X', 'lua_script1:' + test_locale
]
99 tshark_proc
= subprocess
.run(tshark_cmd
, check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
102 logging
.info(tshark_proc
.stdout
)
103 logging
.info(tshark_proc
.stderr
)
104 if not 'All tests passed!' in tshark_proc
.stdout
:
105 pytest
.fail("Some test failed, check the logs (eg: pytest --lf --log-cli-level=info)")
108 return check_lua_script_locale_real
111 def test_wslua_dir(self
, check_lua_script
):
112 '''wslua directory functions'''
113 check_lua_script('dir.lua', empty_pcap
, True)
115 def test_wslua_util(self
, check_lua_script
):
116 '''wslua utility functions'''
117 check_lua_script('util.lua', empty_pcap
, True)
119 # Mode_1, mode_2, and mode_3, and fpm were all under wslua_step_dissector_test
120 # in the Bash version.
121 def test_wslua_dissector_mode_1(self
, check_lua_script_verify
):
122 '''wslua dissector functions, mode 1'''
123 check_lua_script_verify('dissector.lua', dns_port_pcap
)
125 def test_wslua_dissector_mode_2(self
, check_lua_script_verify
):
126 '''wslua dissector functions, mode 2'''
127 check_lua_script_verify('dissector.lua', dns_port_pcap
, heur_regmode
=2)
129 def test_wslua_dissector_mode_3(self
, check_lua_script_verify
):
130 '''wslua dissector functions, mode 3'''
131 check_lua_script_verify('dissector.lua', dns_port_pcap
, heur_regmode
=3)
133 def test_wslua_dissector_fpm(self
, check_lua_script
):
134 '''wslua dissector functions, fpm'''
135 tshark_fpm_tcp_proc
= check_lua_script('dissectFPM.lua', segmented_fpm_pcap
, False,
137 '-e', 'frame.number',
142 '-o', 'fpm.dissect_tcp:true'
145 tshark_fpm_no_tcp_proc
= check_lua_script('dissectFPM.lua', segmented_fpm_pcap
, False,
147 '-e', 'frame.number',
152 '-o', 'fpm.dissect_tcp:false'
155 assert tshark_fpm_tcp_proc
.stdout
== tshark_fpm_no_tcp_proc
.stdout
157 def test_wslua_field(self
, check_lua_script
):
159 check_lua_script('field.lua', dhcp_pcap
, True, '-q', '-c1')
161 # reader, writer, and acme_reader were all under wslua_step_file_test
162 # in the Bash version.
163 def test_wslua_file_reader(self
, check_lua_script
, cmd_tshark
, capture_file
, test_env
):
164 '''wslua file reader'''
165 cap_file_1
= capture_file(dhcp_pcap
)
166 cap_file_2
= capture_file(wpa_induction_pcap_gz
)
168 # First run tshark with the pcap_file_reader script.
169 lua_proc_1
= check_lua_script('pcap_file.lua', cap_file_1
, False)
170 lua_proc_2
= check_lua_script('pcap_file.lua', cap_file_2
, False)
171 lua_out
= lua_proc_1
.stdout
+ lua_proc_2
.stdout
173 # then run tshark again without the script
174 tshark_proc_1
= subprocess
.run((cmd_tshark
, '-r', cap_file_1
), check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
175 tshark_proc_2
= subprocess
.run((cmd_tshark
, '-r', cap_file_2
), check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
176 tshark_out
= tshark_proc_1
.stdout
+ tshark_proc_2
.stdout
178 assert lua_out
== tshark_out
180 def test_wslua_file_writer(self
, check_lua_script
, capture_file
, result_file
):
181 '''wslua file writer'''
182 cap_file_1
= capture_file(dhcp_pcap
)
183 cap_file_2
= result_file('lua_writer.pcap')
185 # Generate a new capture file using the Lua writer.
186 check_lua_script('pcap_file.lua', cap_file_1
, False,
190 assert filecmp
.cmp(cap_file_1
, cap_file_2
), cap_file_1
+ ' differs from ' + cap_file_2
192 def test_wslua_file_acme_reader(self
, check_lua_script
, cmd_tshark
, capture_file
, result_file
, test_env
):
193 '''wslua acme file reader'''
195 cap_file
= result_file('lua_acme_reader.pcap')
196 # Read an acme sipmsg.log using the acme Lua reader, writing it out as pcapng.
197 check_lua_script('acme_file.lua', sipmsg_log
, False,
202 # Read lua_acme_reader.pcap and sip.pcapng and compare their verbose outputs.
203 tshark_proc_1
= subprocess
.run((cmd_tshark
,
206 ), check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
207 tshark_proc_2
= subprocess
.run((cmd_tshark
,
208 '-r', capture_file(sip_pcapng
),
210 ), check
=True, capture_output
=True, encoding
='utf-8', env
=test_env
)
212 assert tshark_proc_1
.stdout
== tshark_proc_2
.stdout
214 def test_wslua_listener(self
, check_lua_script
):
216 check_lua_script('listener.lua', dhcp_pcap
, True)
218 def test_wslua_nstime(self
, check_lua_script
):
220 check_lua_script('nstime.lua', dhcp_pcap
, True, '-q')
222 def test_wslua_pinfo(self
, check_lua_script
):
224 check_lua_script('pinfo.lua', dhcp_pcap
, True)
226 def test_wslua_proto(self
, check_lua_script
):
228 check_lua_script('proto.lua', empty_pcap
, True)
230 def test_wslua_byte_array(self
, check_lua_script
):
231 '''wslua byte_array'''
232 check_lua_script('byte_array.lua', empty_pcap
, True)
234 def test_wslua_protofield_tree(self
, check_lua_script
):
235 '''wslua protofield with a tree'''
236 check_lua_script('protofield.lua', dns_port_pcap
, True,
238 '-Y', 'test.filtered==1',
241 def test_wslua_protofield_no_tree(self
, check_lua_script
):
242 '''wslua protofield without a tree'''
243 check_lua_script('protofield.lua', dns_port_pcap
, True,
244 '-Y', 'test.filtered==1',
247 def test_wslua_int64(self
, check_lua_script
):
249 check_lua_script('int64.lua', empty_pcap
, True)
251 def test_wslua_args_1(self
, check_lua_script
):
253 check_lua_script('script_args.lua', empty_pcap
, True,
254 '-X', 'lua_script1:1',
257 def test_wslua_args_2(self
, check_lua_script
):
259 check_lua_script('script_args.lua', empty_pcap
, True,
260 '-X', 'lua_script1:3',
261 '-X', 'lua_script1:foo',
262 '-X', 'lua_script1:bar',
265 def test_wslua_args_3(self
, check_lua_script
, dirs
):
267 check_lua_script('script_args.lua', empty_pcap
, True,
268 '-X', 'lua_script:' + os
.path
.join(dirs
.lua_dir
, 'script_args.lua'),
269 '-X', 'lua_script1:3',
270 '-X', 'lua_script2:1',
271 '-X', 'lua_script1:foo',
272 '-X', 'lua_script1:bar',
275 def test_wslua_args_4(self
, check_lua_script
):
277 tshark_proc
= check_lua_script('script_args.lua', empty_pcap
, False)
278 assert 'All tests passed!' not in tshark_proc
.stdout
280 def test_wslua_args_5(self
, check_lua_script
):
282 tshark_proc
= check_lua_script('script_args.lua', empty_pcap
, False,
283 '-X', 'lua_script1:3',
285 assert 'All tests passed!' not in tshark_proc
.stdout
287 def test_wslua_globals(self
, check_lua_script
, dirs
):
289 check_lua_script('verify_globals.lua', empty_pcap
, True,
290 '-X', 'lua_script1:' + os
.path
.join(dirs
.lua_dir
, ''),
291 '-X', 'lua_script1:' + os
.path
.join(dirs
.lua_dir
, 'globals_4.4.txt'),
294 def test_wslua_struct(self
, check_lua_script
):
296 check_lua_script('struct.lua', empty_pcap
, True)
298 def test_wslua_tvb_tree(self
, check_lua_script
):
299 '''wslua tvb with a tree'''
300 check_lua_script('tvb.lua', dns_port_pcap
, True, '-c1', '-V')
302 def test_wslua_tvb_no_tree(self
, check_lua_script
):
303 '''wslua tvb without a tree'''
304 check_lua_script('tvb.lua', dns_port_pcap
, True, '-c1')
306 def test_wslua_try_heuristics(self
, check_lua_script
):
307 '''wslua try_heuristics'''
308 check_lua_script('try_heuristics.lua', dns_port_pcap
, True)
310 def test_wslua_add_packet_field(self
, check_lua_script
):
311 '''wslua add_packet_field'''
312 check_lua_script('add_packet_field.lua', dns_port_pcap
, True)
314 class TestWsluaUnicode
:
315 def test_wslua_unicode(self
, cmd_tshark
, features
, dirs
, capture_file
, unicode_env
):
316 '''Check handling of unicode paths.'''
317 if not features
.have_lua
:
318 pytest
.skip('Test requires Lua scripting support.')
319 if sys
.platform
== 'win32' and not features
.have_lua_unicode
:
320 pytest
.skip('Test requires a patched Lua build with UTF-8 support.')
322 # Prepare test environment, put files in the right places.
323 uni_script
= os
.path
.join(unicode_env
.pluginsdir
, 'script-Ф-€-中.lua')
324 shutil
.copy(os
.path
.join(dirs
.lua_dir
, 'unicode.lua'), uni_script
)
325 with
open(unicode_env
.path('load-Ф-€-中.lua'), 'w', encoding
='utf8') as f
:
326 f
.write('return "Contents of Ф-€-中"\n')
327 uni_pcap
= unicode_env
.path('file-Ф-€-中.pcap')
328 shutil
.copy(capture_file('empty.pcap'), uni_pcap
)
330 # Run process from a Unicode path as working directory.
331 proc
= subprocess
.Popen((cmd_tshark
, '-r', uni_pcap
), env
=unicode_env
.env
,
332 stdout
=subprocess
.PIPE
,
333 stderr
=subprocess
.PIPE
,
334 cwd
=unicode_env
.path())
335 stdout
, stderr
= proc
.communicate(timeout
=60)
336 stdout_str
= stdout
.decode('utf8', 'replace')
337 stderr_str
= stderr
.decode('utf8', 'replace')
338 assert 'All tests passed!' in stdout_str
339 assert stderr_str
== ""
340 with
open(unicode_env
.path('written-by-lua-Ф-€-中.txt'), encoding
='utf8') as f
:
341 assert f
.read() == 'Feedback from Lua: Ф-€-中\n'
343 class TestWsluaLocale
:
344 # Some tests under different a locale, e.g. German uses comma as the decimal
345 # separator (and dot as the thousands separator.)
346 def test_wslua_util_locale(self
, check_lua_script_locale
):
347 '''wslua utility functions in a non-English locale'''
348 check_lua_script_locale('util.lua', empty_pcap
, True, 'de_DE.utf-8')
350 def test_wslua_protofield_locale_tree(self
, check_lua_script_locale
):
351 '''wslua protofield with a tree with a non-English locale'''
352 check_lua_script_locale('protofield.lua', dns_port_pcap
, True,
355 '-Y', 'test.filtered==1',
358 def test_wslua_protofield_locale_no_tree(self
, check_lua_script_locale
):
359 '''wslua protofield without a tree with a non-English locale'''
360 check_lua_script_locale('protofield.lua', dns_port_pcap
, True,
362 '-Y', 'test.filtered==1',