test: do not silently ignore feature detection failures
[metze/wireshark/wip.git] / test / config.py
1 #
2 # -*- coding: utf-8 -*-
3 # Wireshark tests
4 # By Gerald Combs <gerald@wireshark.org>
5 #
6 # Ported from a set of Bash scripts which were copyright 2005 Ulf Lamping
7 #
8 # SPDX-License-Identifier: GPL-2.0-or-later
9 #
10 '''Configuration'''
11
12 import logging
13 import os
14 import os.path
15 import re
16 import shutil
17 import subprocess
18 import sys
19 import tempfile
20
21 commands = (
22     'capinfos',
23     'dumpcap',
24     'mergecap',
25     'rawshark',
26     'sharkd',
27     'text2pcap',
28     'tshark',
29     'wireshark',
30 )
31
32 can_capture = False
33 capture_interface = None
34
35 # Our executables
36 program_path = None
37 # Strings
38 cmd_capinfos = None
39 cmd_dumpcap = None
40 cmd_mergecap = None
41 cmd_rawshark = None
42 cmd_tshark = None
43 cmd_text2pcap = None
44 cmd_wireshark = None
45 # Arrays
46 args_ping = None
47
48 have_lua = False
49 have_nghttp2 = False
50 have_kerberos = False
51 have_libgcrypt16 = False
52 have_libgcrypt17 = False
53
54 test_env = None
55 program_path = None
56 home_path = None
57 conf_path = None
58 custom_profile_path = None
59 custom_profile_name = 'Custom Profile'
60
61 this_dir = os.path.dirname(__file__)
62 baseline_dir = os.path.join(this_dir, 'baseline')
63 capture_dir = os.path.join(this_dir, 'captures')
64 config_dir = os.path.join(this_dir, 'config')
65 key_dir = os.path.join(this_dir, 'keys')
66 lua_dir = os.path.join(this_dir, 'lua')
67 tools_dir = os.path.join(this_dir, '..', 'tools')
68
69 all_groups = []
70
71 def canCapture():
72     # XXX This appears to be evaluated at the wrong time when called
73     # from a unittest.skipXXX decorator.
74     return can_capture and capture_interface is not None
75
76 def setCanCapture(new_cc):
77     can_capture = new_cc
78
79 def setCaptureInterface(iface):
80     global capture_interface
81     setCanCapture(True)
82     capture_interface = iface
83
84 def canMkfifo():
85     return not sys.platform.startswith('win32')
86
87 def canDisplay():
88     if sys.platform.startswith('win32') or sys.platform.startswith('darwin'):
89         return True
90     # Qt requires XKEYBOARD and Xrender, which Xvnc doesn't provide.
91     return False
92
93 def getTsharkInfo():
94     global have_lua
95     global have_nghttp2
96     global have_kerberos
97     global have_libgcrypt16
98     global have_libgcrypt17
99     if not cmd_tshark:
100         logging.warning("tshark binary is not yet set")
101         return
102     try:
103         tshark_v = subprocess.check_output(
104             (cmd_tshark, '--version'),
105             stderr=subprocess.PIPE,
106             universal_newlines=True,
107             env={'WIRESHARK_CONFIG_DIR': '/dummy/non/existing'}
108         ).replace('\n', ' ')
109     except subprocess.CalledProcessError as e:
110         logging.warning("Failed to detect tshark features: %s", e)
111         tshark_v = ''
112     have_lua = bool(re.search('with +Lua', tshark_v))
113     have_nghttp2 = bool(re.search('with +nghttp2', tshark_v))
114     have_kerberos = bool(re.search('(with +MIT +Kerberos|with +Heimdal +Kerberos)', tshark_v))
115     gcry_m = re.search('with +Gcrypt +([0-9]+\.[0-9]+)', tshark_v)
116     have_libgcrypt16 = gcry_m and float(gcry_m.group(1)) >= 1.6
117     have_libgcrypt17 = gcry_m and float(gcry_m.group(1)) >= 1.7
118
119 def getDefaultCaptureInterface():
120     '''Choose a default capture interface for our platform. Currently Windows only.'''
121     global capture_interface
122     if capture_interface:
123         return
124     if cmd_dumpcap is None:
125         return
126     if not sys.platform.startswith('win32'):
127         return
128     try:
129         dumpcap_d_data = subprocess.check_output((cmd_dumpcap, '-D'), stderr=subprocess.PIPE)
130         if sys.version_info[0] >= 3:
131             dumpcap_d_stdout = dumpcap_d_data.decode('UTF-8', 'replace')
132         else:
133             dumpcap_d_stdout = unicode(dumpcap_d_data, 'UTF-8', 'replace')
134         for d_line in dumpcap_d_stdout.splitlines():
135             iface_m = re.search('(\d+)\..*(Ethernet|Network Connection|VMware|Intel)', d_line)
136             if iface_m:
137                 capture_interface = iface_m.group(1)
138                 break
139     except:
140         pass
141
142 def getPingCommand():
143     '''Return an argument list required to ping www.wireshark.org for 60 seconds.'''
144     global args_ping
145     # XXX The shell script tests swept over packet sizes from 1 to 240 every 0.25 seconds.
146     if sys.platform.startswith('win32'):
147         # XXX Check for psping? https://docs.microsoft.com/en-us/sysinternals/downloads/psping
148         args_ping = ('ping', '-n', '60', '-l', '100', 'www.wireshark.org')
149     elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
150         args_ping = ('ping', '-c', '240', '-s', '100', '-i', '0.25', 'www.wireshark.org')
151     elif sys.platform.startswith('darwin'):
152         args_ping = ('ping', '-c', '1', '-g', '1', '-G', '240', '-i', '0.25', 'www.wireshark.org')
153     # XXX Other BSDs, Solaris, etc
154
155 def setProgramPath(path):
156     global program_path
157     program_path = path
158     retval = True
159     dotexe = ''
160     if sys.platform.startswith('win32'):
161         dotexe = '.exe'
162     for cmd in commands:
163         cmd_var = 'cmd_' + cmd
164         cmd_path = os.path.normpath(os.path.join(path, cmd + dotexe))
165         if not os.path.exists(cmd_path) or not os.access(cmd_path, os.X_OK):
166             cmd_path = None
167             program_path = None
168             retval = False
169         globals()[cmd_var] = cmd_path
170     getTsharkInfo()
171     getDefaultCaptureInterface()
172     setUpHostFiles()
173     return retval
174
175 def testEnvironment():
176     return test_env
177
178 def setUpTestEnvironment():
179     global home_path
180     global conf_path
181     global custom_profile_path
182     global test_env
183
184     # Create our directories
185     test_confdir = tempfile.mkdtemp(prefix='wireshark-tests.')
186     home_path = os.path.join(test_confdir, 'home')
187     if sys.platform.startswith('win32'):
188         home_env = 'APPDATA'
189         conf_path = os.path.join(home_path, 'Wireshark')
190     else:
191         home_env = 'HOME'
192         conf_path = os.path.join(home_path, '.config', 'wireshark')
193     os.makedirs(conf_path)
194     # Test spaces while we're here.
195     custom_profile_path = os.path.join(conf_path, 'profiles', custom_profile_name)
196     os.makedirs(custom_profile_path)
197
198     # Populate our UAT files
199     uat_files = [
200         '80211_keys',
201         'dtlsdecrypttablefile',
202         'esp_sa',
203         'ssl_keys',
204         'c1222_decryption_table',
205         'ikev1_decryption_table',
206         'ikev2_decryption_table',
207     ]
208     for uat in uat_files:
209         setUpUatFile(uat)
210
211     # Set up our environment
212     test_env = os.environ.copy()
213     test_env['WIRESHARK_RUN_FROM_BUILD_DIRECTORY'] = 'True'
214     test_env['WIRESHARK_QUIT_AFTER_CAPTURE'] = 'True'
215     test_env['TZ'] = 'UTC'
216     test_env[home_env] = home_path
217
218 def setUpUatFile(conf_file):
219     global home_path
220     global conf_path
221     if home_path is None or conf_path is None:
222         setUpTestEnvironment()
223     template = os.path.join(os.path.dirname(__file__), 'config', conf_file) + '.tmpl'
224     with open(template, 'r') as tplt_fd:
225         tplt_contents = tplt_fd.read()
226         tplt_fd.close()
227         key_dir_path = os.path.join(key_dir, '')
228         # uat.c replaces backslashes...
229         key_dir_path = key_dir_path.replace('\\', '\\x5c')
230         cf_contents = tplt_contents.replace('TEST_KEYS_DIR', key_dir_path)
231     out_file = os.path.join(conf_path, conf_file)
232     with open(out_file, 'w') as cf_fd:
233         cf_fd.write(cf_contents)
234         cf_fd.close()
235
236 def setUpHostFiles():
237     global program_path
238     global conf_path
239     global custom_profile_path
240     if program_path is None:
241         return
242     if conf_path is None or custom_profile_path is None:
243         setUpTestEnvironment()
244     bundle_path = os.path.join(program_path, 'Wireshark.app', 'Contents', 'MacOS')
245     if os.path.isdir(bundle_path):
246         global_path = bundle_path
247     else:
248         global_path = program_path
249     hosts_path_pfx = os.path.join(this_dir, 'hosts.')
250     shutil.copyfile(hosts_path_pfx + 'global', os.path.join(global_path, 'hosts'))
251     shutil.copyfile(hosts_path_pfx + 'personal', os.path.join(conf_path, 'hosts'))
252     shutil.copyfile(hosts_path_pfx + 'custom', os.path.join(custom_profile_path, 'hosts'))
253
254 if sys.platform.startswith('win32') or sys.platform.startswith('darwin'):
255     can_capture = True
256
257 # Initialize ourself.
258 getPingCommand()