TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / test / suite_clopts.py
blob4d2d8b4ca97bd563f6e2b2d8ea2a07f597e16832
2 # Wireshark tests
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 '''Command line option tests'''
11 import json
12 import sys
13 import os.path
14 import subprocess
15 import subprocesstest
16 from subprocesstest import ExitCodes, grep_output, count_output
17 import shutil
18 import pytest
20 #glossaries = ('fields', 'protocols', 'values', 'decodes', 'defaultprefs', 'currentprefs')
22 glossaries = ('decodes', 'values')
23 testout_pcap = 'testout.pcap'
26 class TestDumpcapOptions:
27 # XXX Should we generate individual test functions instead of looping?
28 def test_dumpcap_invalid_chars(self, cmd_dumpcap, base_env):
29 '''Invalid dumpcap parameters'''
30 for char_arg in 'CEFGHJKNORTUVWXYejloxz':
31 process = subprocesstest.run((cmd_dumpcap, '-' + char_arg), env=base_env)
32 assert process.returncode == ExitCodes.COMMAND_LINE
34 # XXX Should we generate individual test functions instead of looping?
35 def test_dumpcap_valid_chars(self, cmd_dumpcap, base_env):
36 for char_arg in 'hv':
37 process = subprocesstest.run((cmd_dumpcap, '-' + char_arg), env=base_env)
38 assert process.returncode == ExitCodes.OK
40 # XXX Should we generate individual test functions instead of looping?
41 def test_dumpcap_interface_chars(self, cmd_dumpcap, base_env):
42 '''Valid dumpcap parameters requiring capture permissions'''
43 valid_returns = [ExitCodes.OK, ExitCodes.INVALID_INTERFACE]
44 for char_arg in 'DL':
45 process = subprocesstest.run((cmd_dumpcap, '-' + char_arg), env=base_env)
46 assert process.returncode in valid_returns
49 class TestDumpcapClopts:
50 def test_dumpcap_invalid_capfilter(self, cmd_dumpcap, capture_interface, result_file, base_env):
51 '''Invalid capture filter'''
52 invalid_filter = '__invalid_protocol'
53 # $DUMPCAP -f 'jkghg' -w './testout.pcap' > ./testout.txt 2>&1
54 testout_file = result_file(testout_pcap)
55 process = subprocesstest.run((cmd_dumpcap, '-f', invalid_filter, '-w', testout_file), capture_output=True, env=base_env)
56 assert grep_output(process.stderr, 'Invalid capture filter "' + invalid_filter + '" for interface')
58 def test_dumpcap_invalid_interface_name(self, cmd_dumpcap, capture_interface, result_file, base_env):
59 '''Invalid capture interface name'''
60 invalid_interface = '__invalid_interface'
61 # $DUMPCAP -i invalid_interface -w './testout.pcap' > ./testout.txt 2>&1
62 testout_file = result_file(testout_pcap)
63 process = subprocesstest.run((cmd_dumpcap, '-i', invalid_interface, '-w', testout_file), capture_output=True, env=base_env)
64 assert grep_output(process.stderr, 'There is no device named "__invalid_interface"') or \
65 grep_output(process.stderr, 'The capture session could not be initiated on capture device "__invalid_interface"')
67 def test_dumpcap_invalid_interface_index(self, cmd_dumpcap, capture_interface, result_file, base_env):
68 '''Invalid capture interface index'''
69 invalid_index = '0'
70 # $DUMPCAP -i 0 -w './testout.pcap' > ./testout.txt 2>&1
71 testout_file = result_file(testout_pcap)
72 process = subprocesstest.run((cmd_dumpcap, '-i', invalid_index, '-w', testout_file), capture_output=True, env=base_env)
73 assert grep_output(process.stderr, 'There is no interface with that adapter index')
76 class TestBasicClopts:
77 def test_existing_file(self, cmd_tshark, capture_file, test_env):
78 # $TSHARK -r "${CAPTURE_DIR}dhcp.pcap" > ./testout.txt 2>&1
79 process = subprocesstest.run((cmd_tshark, '-r', capture_file('dhcp.pcap')), env=test_env)
80 assert process.returncode == ExitCodes.OK
82 def test_existing_file_longopt(self, cmd_tshark, capture_file, test_env):
83 # $TSHARK -r "${CAPTURE_DIR}dhcp.pcap" > ./testout.txt 2>&1
84 process = subprocesstest.run((cmd_tshark, '--read-file', capture_file('dhcp.pcap'),
85 '--display-filter', 'dhcp'), env=test_env)
86 assert process.returncode == ExitCodes.OK
88 def test_nonexistent_file(self, cmd_tshark, capture_file, test_env):
89 # $TSHARK - r ThisFileDontExist.pcap > ./testout.txt 2 > &1
90 process = subprocesstest.run((cmd_tshark, '-r', capture_file('__ceci_nest_pas_une.pcap')), env=test_env)
91 assert process.returncode == ExitCodes.INVALID_FILE_ERROR
94 class TestTsharkOptions:
95 # XXX Should we generate individual test functions instead of looping?
96 def test_tshark_invalid_chars(self, cmd_tshark, test_env):
97 '''Invalid tshark parameters'''
98 # Most of these are valid but require a mandatory parameter
99 for char_arg in 'ABCEFGHJKMNORTUWXYZabcdefijkmorstuwyz':
100 process = subprocesstest.run((cmd_tshark, '-' + char_arg), env=test_env)
101 assert process.returncode == ExitCodes.COMMAND_LINE
103 # XXX Should we generate individual test functions instead of looping?
104 def test_tshark_valid_chars(self, cmd_tshark, test_env):
105 for char_arg in 'hv':
106 process = subprocesstest.run((cmd_tshark, '-' + char_arg), env=test_env)
107 assert process.returncode == ExitCodes.OK
109 # XXX Should we generate individual test functions instead of looping?
110 def test_tshark_interface_chars(self, cmd_tshark, cmd_dumpcap, test_env):
111 '''Valid tshark parameters requiring capture permissions'''
112 # These options require dumpcap, but may fail with a pacp error
113 # if WinPcap or Npcap are not present
114 valid_returns = [ExitCodes.OK, ExitCodes.PCAP_ERROR, ExitCodes.INVALID_CAPABILITY, ExitCodes.INVALID_INTERFACE]
115 for char_arg in 'DL':
116 process = subprocesstest.run((cmd_tshark, '-' + char_arg), env=test_env)
117 assert process.returncode in valid_returns
119 def test_tshark_disable_protos(self, cmd_tshark, capture_file, test_env):
120 '''--disable-protocol/--enable-protocol from !16923'''
121 process = subprocesstest.run((cmd_tshark, "-r", capture_file("http.pcap"),
122 "--disable-protocol", "ALL",
123 "--enable-protocol", "eth,ip",
124 "-Tjson", "-eeth.type", "-eip.proto", "-ehttp.host",
125 ), capture_output=True, env=test_env)
126 assert process.returncode == ExitCodes.OK
127 obj = json.loads(process.stdout)[0]['_source']['layers']
128 assert obj.get('eth.type', 'NOT FOUND') == ['0x0800']
129 assert obj.get('ip.proto', 'NOT FOUND') == ['6']
130 assert obj.get('http.host', 'NOT FOUND') == 'NOT FOUND'
133 class TestTsharkCaptureClopts:
134 def test_tshark_invalid_capfilter(self, cmd_tshark, capture_interface, result_file, test_env):
135 '''Invalid capture filter'''
136 invalid_filter = '__invalid_protocol'
137 # $TSHARK -f 'jkghg' -w './testout.pcap' > ./testout.txt 2>&1
138 testout_file = result_file(testout_pcap)
139 process = subprocesstest.run((cmd_tshark, '-f', invalid_filter, '-w', testout_file ), capture_output=True, env=test_env)
140 assert grep_output(process.stderr, 'Invalid capture filter "' + invalid_filter + '" for interface')
142 def test_tshark_invalid_interface_name(self, cmd_tshark, capture_interface, result_file, test_env):
143 '''Invalid capture interface name'''
144 invalid_interface = '__invalid_interface'
145 # $TSHARK -i invalid_interface -w './testout.pcap' > ./testout.txt 2>&1
146 testout_file = result_file(testout_pcap)
147 process = subprocesstest.run((cmd_tshark, '-i', invalid_interface, '-w', testout_file), capture_output=True, env=test_env)
148 assert grep_output(process.stderr, 'There is no device named "__invalid_interface"') or \
149 grep_output(process.stderr, 'The capture session could not be initiated on capture device "__invalid_interface"')
151 def test_tshark_invalid_interface_index(self, cmd_tshark, capture_interface, result_file, test_env):
152 '''Invalid capture interface index'''
153 invalid_index = '0'
154 # $TSHARK -i 0 -w './testout.pcap' > ./testout.txt 2>&1
155 testout_file = result_file(testout_pcap)
156 process = subprocesstest.run((cmd_tshark, '-i', invalid_index, '-w', testout_file), capture_output=True, env=test_env)
157 assert grep_output(process.stderr, 'There is no interface with that adapter index')
160 class TestTsharkNameResolutionClopts:
161 def test_tshark_valid_name_resolution(self, cmd_tshark, capture_file, test_env):
162 # $TSHARK -N mnNtdv -a duration:1 > ./testout.txt 2>&1
163 process = subprocesstest.run((cmd_tshark,
164 '-r', capture_file('empty.pcap'),
165 '-N', 'mnNtdv',
166 ), env=test_env)
167 assert process.returncode == 0
169 # XXX Add invalid name resolution.
171 class TestTsharkUnicodeClopts:
172 def test_tshark_unicode_display_filter(self, cmd_tshark, capture_file, test_env):
173 '''Unicode (UTF-8) display filter'''
174 process = subprocesstest.run((cmd_tshark, '-r', capture_file('http.pcap'), '-Y', 'tcp.flags.str == "·······AP···"'), capture_output=True, env=test_env)
175 assert grep_output(process.stdout, 'HEAD.*/v4/iuident.cab')
178 class TestTsharkDumpGlossaries:
179 def test_tshark_dump_glossary(self, cmd_tshark, base_env):
180 for glossary in glossaries:
181 process = subprocesstest.run((cmd_tshark, '-G', glossary), capture_output=True, env=base_env)
182 assert not process.stderr, 'Found error output while printing glossary ' + glossary
184 def test_tshark_glossary_valid_utf8(self, cmd_tshark, base_env):
185 for glossary in glossaries:
186 env = base_env
187 env['LANG'] = 'en_US.UTF-8'
188 # subprocess.run() returns bytes here.
189 proc = subprocess.run((cmd_tshark, '-G', glossary), capture_output=True, env=env)
190 assert proc.returncode == 0
191 proc.stdout.decode('UTF-8')
193 def test_tshark_glossary_plugin_count(self, cmd_tshark, base_env, features):
194 if not features.have_plugins:
195 pytest.skip('Test requires binary plugin support.')
196 process = subprocesstest.run((cmd_tshark, '-G', 'plugins'), capture_output=True, env=base_env)
197 assert count_output(process.stdout, 'dissector') >= 10, 'Fewer than 10 dissector plugins found'
199 def test_tshark_elastic_mapping(self, cmd_tshark, dirs, base_env):
200 def get_ip_props(obj):
201 return obj['mappings']['properties']['layers']['properties']['ip']['properties']
202 baseline_file = os.path.join(dirs.baseline_dir, 'elastic-mapping-ip-subset.json')
203 with open(baseline_file) as f:
204 expected_obj = json.load(f)
205 keys_to_check = get_ip_props(expected_obj).keys()
206 proc = subprocesstest.run((cmd_tshark, '-G', 'elastic-mapping', '--elastic-mapping-filter', 'ip'), capture_output=True, env=base_env)
207 actual_obj = json.loads(proc.stdout)
208 ip_props = get_ip_props(actual_obj)
209 for key in list(ip_props.keys()):
210 if key not in keys_to_check:
211 del ip_props[key]
212 assert actual_obj == expected_obj
214 def test_tshark_unicode_folders(self, cmd_tshark, unicode_env, features):
215 '''Folders output with unicode'''
216 if not features.have_lua:
217 pytest.skip('Test requires Lua scripting support.')
218 if sys.platform == 'win32' and not features.have_lua_unicode:
219 pytest.skip('Test requires a patched Lua build with UTF-8 support.')
220 proc = subprocesstest.run((cmd_tshark, '-G', 'folders'), capture_output=True, env=unicode_env.env)
221 out = proc.stdout
222 pluginsdir = [x.split('\t', 1)[1] for x in out.splitlines() if x.startswith('Personal Lua Plugins:')]
223 assert [unicode_env.pluginsdir] == pluginsdir
226 class TestTsharkZExpert:
227 def test_tshark_z_expert_all(self, cmd_tshark, capture_file, test_env):
228 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert',
229 '-o', 'tcp.check_checksum:TRUE',
230 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
231 # http2-data-reassembly.pcap has Errors, Warnings, Notes, and Chats
232 # when TCP checksum are verified.
233 assert grep_output(proc.stdout, 'Errors')
234 assert grep_output(proc.stdout, 'Warns')
235 assert grep_output(proc.stdout, 'Notes')
236 assert grep_output(proc.stdout, 'Chats')
238 def test_tshark_z_expert_error(self, cmd_tshark, capture_file, test_env):
239 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,error',
240 '-o', 'tcp.check_checksum:TRUE',
241 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
242 assert grep_output(proc.stdout, 'Errors')
243 assert not grep_output(proc.stdout, 'Warns')
244 assert not grep_output(proc.stdout, 'Notes')
245 assert not grep_output(proc.stdout, 'Chats')
247 def test_tshark_z_expert_warn(self, cmd_tshark, capture_file, test_env):
248 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,warn',
249 '-o', 'tcp.check_checksum:TRUE',
250 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
251 assert grep_output(proc.stdout, 'Errors')
252 assert grep_output(proc.stdout, 'Warns')
253 assert not grep_output(proc.stdout, 'Notes')
254 assert not grep_output(proc.stdout, 'Chats')
256 def test_tshark_z_expert_note(self, cmd_tshark, capture_file, test_env):
257 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,note',
258 '-o', 'tcp.check_checksum:TRUE',
259 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
260 assert grep_output(proc.stdout, 'Errors')
261 assert grep_output(proc.stdout, 'Warns')
262 assert grep_output(proc.stdout, 'Notes')
263 assert not grep_output(proc.stdout, 'Chats')
265 def test_tshark_z_expert_chat(self, cmd_tshark, capture_file, test_env):
266 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,chat',
267 '-o', 'tcp.check_checksum:TRUE',
268 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
269 assert grep_output(proc.stdout, 'Errors')
270 assert grep_output(proc.stdout, 'Warns')
271 assert grep_output(proc.stdout, 'Notes')
272 assert grep_output(proc.stdout, 'Chats')
274 def test_tshark_z_expert_comment(self, cmd_tshark, capture_file, test_env):
275 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,comment',
276 '-r', capture_file('sip.pcapng')), capture_output=True, env=test_env)
277 assert grep_output(proc.stdout, 'Notes')
278 assert grep_output(proc.stdout, 'Comments')
280 def test_tshark_z_expert_invalid_filter(self, cmd_tshark, capture_file, test_env):
281 invalid_filter = '__invalid_protocol'
282 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,' + invalid_filter,
283 '-r', capture_file('http-ooo.pcap')), capture_output=True, env=test_env)
284 assert proc.returncode == ExitCodes.COMMAND_LINE
285 assert grep_output(proc.stdout, 'Filter "' + invalid_filter + '" is invalid')
287 def test_tshark_z_expert_error_invalid_filter(self, cmd_tshark, capture_file, test_env):
288 invalid_filter = '__invalid_protocol'
289 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,error,' + invalid_filter,
290 '-r', capture_file('http-ooo.pcap')), capture_output=True, env=test_env)
291 assert proc.returncode == ExitCodes.COMMAND_LINE
292 assert grep_output(proc.stdout, 'Filter "' + invalid_filter + '" is invalid')
294 def test_tshark_z_expert_filter(self, cmd_tshark, capture_file, test_env):
295 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,udp',
296 '-o', 'tcp.check_checksum:TRUE',
297 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
298 # Filtering for UDP should produce no expert infos.
299 assert not grep_output(proc.stdout, 'Errors')
300 assert not grep_output(proc.stdout, 'Warns')
301 assert not grep_output(proc.stdout, 'Notes')
302 assert not grep_output(proc.stdout, 'Chats')
304 def test_tshark_z_expert_error_filter(self, cmd_tshark, capture_file, test_env):
305 proc = subprocesstest.run((cmd_tshark, '-q', '-z', 'expert,note,http', # tls is a filter
306 '-o', 'tcp.check_checksum:TRUE',
307 '-r', capture_file('http-ooo-fuzzed.pcapng')), capture_output=True, env=test_env)
308 # Filtering for HTTP and Note level expert info should produce only
309 # Error and Warning level expert infos with checksumming turned on.
310 # The Note warnings on are packets with TCP but not HTTP, and we're
311 # filtering out the Chat level.
312 assert grep_output(proc.stdout, 'Errors')
313 assert grep_output(proc.stdout, 'Warns')
314 assert not grep_output(proc.stdout, 'Notes')
315 assert not grep_output(proc.stdout, 'Chats')
318 class TestTsharkExtcap:
319 # dumpcap dependency has been added to run this test only with capture support
320 def test_tshark_extcap_interfaces(self, cmd_tshark, cmd_dumpcap, test_env, home_path):
321 # Script extcaps don't work with the current code on windows.
322 # https://www.wireshark.org/docs/wsdg_html_chunked/ChCaptureExtcap.html
323 # TODO: skip this test until it will get fixed.
324 if sys.platform == 'win32':
325 pytest.skip('FIXME extcap .py scripts needs special treatment on Windows')
326 # Various guides and vulnerability scanners recommend setting /tmp noexec.
327 # If our temp path is such, the extcap script won't work.
328 try:
329 if os.statvfs(home_path).f_flag & os.ST_NOEXEC:
330 pytest.skip('Test requires temp directory to allow execution')
331 except AttributeError:
332 # Most Linux and NetBSD have ST_NOEXEC; Darwin and other *BSDs don't.
333 pass
334 extcap_dir_path = os.path.join(home_path, 'extcap')
335 os.makedirs(extcap_dir_path)
336 test_env['WIRESHARK_EXTCAP_DIR'] = extcap_dir_path
337 source_file = os.path.join(os.path.dirname(__file__), 'sampleif.py')
338 # We run our tests in a bare, reproducible home environment. This can result in an
339 # invalid or missing Python interpreter if our main environment has a wonky Python
340 # path, as is the case in the GitLab SaaS macOS runners which use `asdf`. Force
341 # sampleif.py to use our current Python executable.
342 with open(source_file, 'r') as sf:
343 sampleif_py = sf.read()
344 sampleif_py = sampleif_py.replace('/usr/bin/env python3', sys.executable)
345 sys.stderr.write(sampleif_py)
346 extcap_file = os.path.join(extcap_dir_path, 'sampleif.py')
347 with open(extcap_file, 'w') as ef:
348 ef.write(sampleif_py)
349 os.fchmod(ef.fileno(), os.fstat(sf.fileno()).st_mode)
351 # Ensure the test extcap_tool is properly loaded
352 proc = subprocesstest.run((cmd_tshark, '-D'), capture_output=True, env=test_env)
353 assert count_output(proc.stdout, 'sampleif') == 1
354 # Ensure tshark lists 2 interfaces in the preferences
355 proc = subprocesstest.run((cmd_tshark, '-G', 'currentprefs'), capture_output=True, env=test_env)
356 assert count_output(proc.stdout, 'extcap.sampleif.test') == 2