Test: Add text2pcap.
[metze/wireshark/wip.git] / test / suite_text2pcap.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 '''Text2pcap tests'''
11
12 import config
13 import os.path
14 import pprint
15 import re
16 import subprocesstest
17 import unittest
18
19 # XXX We should probably generate these automatically in config.py.
20 c1222_std_example8_pcap = os.path.join(config.capture_dir, 'c1222_std_example8.pcap')
21 dhcp_nanosecond_pcap = os.path.join(config.capture_dir, 'dhcp-nanosecond.pcap')
22 dhcp_nanosecond_pcapng = os.path.join(config.capture_dir, 'dhcp-nanosecond.pcapng')
23 dhcp_pcap = os.path.join(config.capture_dir, 'dhcp.pcap')
24 dhcp_pcapng = os.path.join(config.capture_dir, 'dhcp.pcapng')
25 dhe1_pcapng_gz = os.path.join(config.capture_dir, 'dhe1.pcapng.gz')
26 dmgr_pcapng = os.path.join(config.capture_dir, 'dmgr.pcapng')
27 dns_icmp_pcapng_gz = os.path.join(config.capture_dir, 'dns+icmp.pcapng.gz')
28 dns_port_pcap = os.path.join(config.capture_dir, 'dns_port.pcap')
29 dvb_ci_uv1_0000_pcap = os.path.join(config.capture_dir, 'dvb-ci_UV1_0000.pcap')
30 empty_pcap = os.path.join(config.capture_dir, 'empty.pcap')
31 ikev1_certs_pcap = os.path.join(config.capture_dir, 'ikev1-certs.pcap')
32 packet_h2_14_headers_pcapng = os.path.join(config.capture_dir, 'packet-h2-14_headers.pcapng')
33 rsa_p_lt_q_pcap = os.path.join(config.capture_dir, 'rsa-p-lt-q.pcap')
34 rsasnakeoil2_pcap = os.path.join(config.capture_dir, 'rsasnakeoil2.pcap')
35 sample_control4_2012_03_24_pcap = os.path.join(config.capture_dir, 'sample_control4_2012-03-24.pcap')
36 segmented_fpm_pcap = os.path.join(config.capture_dir, 'segmented_fpm.pcap')
37 sip_pcapng = os.path.join(config.capture_dir, 'sip.pcapng')
38 snakeoil_dtls_pcap = os.path.join(config.capture_dir, 'snakeoil-dtls.pcap')
39 wpa_induction_pcap_gz = os.path.join(config.capture_dir, 'wpa-Induction.pcap.gz')
40 wpa_eap_tls_pcap_gz = os.path.join(config.capture_dir, 'wpa-eap-tls.pcap.gz')
41
42 testin_txt = 'testin.txt'
43 testout_pcap = 'testout.pcap'
44 testout_pcapng = 'testout.pcapng'
45
46 file_type_to_descr = {
47     'pcap': 'Wireshark/tcpdump/... - pcap',
48     'pcapng': 'Wireshark/... - pcapng',
49 }
50
51 file_type_to_testout = {
52     'pcap': testout_pcap,
53     'pcapng': testout_pcapng,
54 }
55
56 encap_to_link_type = {
57     'Ethernet': 1,
58     'Raw IP': 14,
59     'Linux cooked-mode capture': 113,
60     'IEEE 802.11 plus radiotap radio header': 127,
61     'DVB-CI (Common Interface)': 235,
62 }
63
64 def check_capinfos_info(self, cap_file):
65     cap_info = {
66         'filetype': None,
67         'encapsulation': None,
68         'packets': None,
69         'datasize': None,
70     }
71     str_pats = {
72         'filetype': 'File type',
73         'encapsulation': 'File encapsulation',
74     }
75     int_pats = {
76         'packets': 'Number of packets',
77         'datasize': 'Data size',
78     }
79     capinfos_out = self.getCaptureInfo(capinfos_args=('-t', '-E', '-c', '-d', '-M'), cap_file=cap_file)
80
81     for sp_key in str_pats:
82         str_pat = '{}:\s+([\S ]+)'.format(str_pats[sp_key])
83         str_res = re.search(str_pat, capinfos_out)
84         self.assertTrue(str_res is not None, 'Failed to generate {}'.format(sp_key))
85         cap_info[sp_key] = str_res.group(1)
86
87     for ip_key in int_pats:
88         int_pat = '{}:\s+(\d+)'.format(int_pats[ip_key])
89         int_res = re.search(int_pat, capinfos_out)
90         self.assertTrue(int_res is not None, 'Failed to generate {}'.format(ip_key))
91         cap_info[ip_key] = int(int_res.group(1))
92
93     return cap_info
94
95 def get_capinfos_cmp_info(cii):
96     cmp_keys = ('encapsulation', 'packets', 'datasize')
97     return { k: v for k, v in cii.items() if k in cmp_keys }
98
99 def compare_capinfos_info(self, cii1, cii2, filename1, filename2):
100     cii_cmp_i1 = get_capinfos_cmp_info(cii1)
101     cii_cmp_i2 = get_capinfos_cmp_info(cii2)
102     if not cii_cmp_i1 == cii_cmp_i2:
103         cii1_pp = pprint.pformat(cii_cmp_i1)
104         cii2_pp = pprint.pformat(cii_cmp_i2)
105         self.diffOutput(cii1_pp, cii2_pp, filename1, filename2)
106         self.fail('text2pcap output file differs from input file.')
107
108 def check_text2pcap(self, cap_file, file_type, expected_packets=None, expected_datasize=None):
109     # Perfom the following actions
110     # - Get information for the input pcap file with capinfos
111     # - Generate an ASCII hexdump with TShark
112     # - Convert the ASCII hexdump back to pcap using text2pcap
113     # - Get information for the output pcap file with capinfos
114     # - Check that file type, encapsulation type, number of packets and data size
115     #   in the output file are the same as in the input file
116
117     pre_cap_info = check_capinfos_info(self, cap_file)
118     self.assertTrue(encap_to_link_type.has_key(pre_cap_info['encapsulation']))
119
120     self.assertTrue(file_type in file_type_to_testout, 'Invalid file type')
121
122     # text2pcap_generate_input()
123     # $TSHARK -o 'gui.column.format:"Time","%t"' -tad -P -x -r $1 > testin.txt
124     testin_file = self.filename_from_id(testin_txt)
125     cf_path = os.path.join(config.capture_dir, cap_file)
126     tshark_cmd = '{cmd} -r {cf} -o gui.column.format:"Time","%t" -t ad -P -x > {of}'.format(
127         cmd = config.cmd_tshark,
128         cf = cf_path,
129         of = testin_file,
130     )
131     self.assertRun(tshark_cmd, shell=True)
132
133     testout_fname = file_type_to_testout[file_type]
134     testout_file = self.filename_from_id(testout_fname)
135     if 'pcapng' in pre_cap_info['filetype'] or 'nanosecond libpcap' in pre_cap_info['filetype']:
136         pcapng_flag = '-n'
137     else:
138         pcapng_flag = ''
139     text2pcap_cmd = '{cmd} {ns} -d -l {linktype} -t "%Y-%m-%d %H:%M:%S." {in_f} {out_f}'.format(
140         cmd = config.cmd_text2pcap,
141         ns = pcapng_flag,
142         linktype = encap_to_link_type[pre_cap_info['encapsulation']],
143         in_f = testin_file,
144         out_f = testout_file,
145     )
146     self.assertRun(text2pcap_cmd, shell=True)
147     self.assertTrue(self.grepOutput('potential packet'), "text2pcap didn't complete")
148     self.assertFalse(self.grepOutput('Inconsistent offset'), 'text2pcap detected inconsistent offset')
149
150     post_cap_info = check_capinfos_info(self, testout_file)
151     if expected_packets is not None:
152         post_cap_info['packtets'] = expected_packets
153     if expected_datasize is not None:
154         post_cap_info['datasize'] = expected_datasize
155     compare_capinfos_info(self, pre_cap_info, post_cap_info, cap_file, testout_fname)
156
157
158 class case_text2pcap_pcap(subprocesstest.SubprocessTestCase):
159     def test_text2pcap_empty_pcap(self):
160         '''Test text2pcap with empty.pcap.'''
161         check_text2pcap(self, empty_pcap, 'pcap')
162
163     def test_text2pcap_dhcp_pcap(self):
164         '''Test text2pcap with dhcp.pcap.'''
165         check_text2pcap(self, dhcp_pcap, 'pcap')
166
167     def test_text2pcap_dhcp_nanosecond_pcap(self):
168         '''Test text2pcap with dhcp-nanosecond.pcap.'''
169         check_text2pcap(self, dhcp_nanosecond_pcap, 'pcap')
170
171     def test_text2pcap_segmented_fpm_pcap(self):
172         '''Test text2pcap with segmented_fpm.pcap.'''
173         check_text2pcap(self, segmented_fpm_pcap, 'pcap')
174
175     def test_text2pcap_c1222_std_example8_pcap(self):
176         '''Test text2pcap with c1222_std_example8.pcap.'''
177         check_text2pcap(self, c1222_std_example8_pcap, 'pcap')
178
179     def test_text2pcap_dns_port_pcap(self):
180         '''Test text2pcap with dns_port.pcap.'''
181         check_text2pcap(self, dns_port_pcap, 'pcap')
182
183     def test_text2pcap_dvb_ci_uv1_0000_pcap(self):
184         '''Test text2pcap with dvb-ci_UV1_0000.pcap.'''
185         check_text2pcap(self, dvb_ci_uv1_0000_pcap, 'pcap')
186
187     def test_text2pcap_ikev1_certs_pcap(self):
188         '''Test text2pcap with ikev1-certs.pcap.'''
189         check_text2pcap(self, ikev1_certs_pcap, 'pcap')
190
191     def test_text2pcap_rsa_p_lt_q_pcap(self):
192         '''Test text2pcap with rsa-p-lt-q.pcap.'''
193         check_text2pcap(self, rsa_p_lt_q_pcap, 'pcap')
194
195     def test_text2pcap_rsasnakeoil2_pcap(self):
196         '''Test text2pcap with rsasnakeoil2.pcap.'''
197         check_text2pcap(self, rsasnakeoil2_pcap, 'pcap')
198
199     def test_text2pcap_sample_control4_2012_03_24_pcap(self):
200         '''Test text2pcap with sample_control4_2012-03-24.pcap.'''
201         # tshark currently output decrypted ZigBee packets and
202         # as a result the number of packets and data size are different
203         check_text2pcap(self, sample_control4_2012_03_24_pcap, 'pcap', 239, 10103)
204
205     def test_text2pcap_snakeoil_dtls_pcap(self):
206         '''Test text2pcap with snakeoil-dtls.pcap.'''
207         check_text2pcap(self, snakeoil_dtls_pcap, 'pcap')
208
209     def test_text2pcap_wpa_eap_tls_pcap_gz(self):
210         '''Test text2pcap with wpa-eap-tls.pcap.gz.'''
211         # tshark reassembles some packets and because of this
212         # the number of packets and data size are different
213         check_text2pcap(self, wpa_eap_tls_pcap_gz, 'pcap', 88, 38872)
214
215     def test_text2pcap_wpa_induction_pcap(self):
216         '''Test text2pcap with wpa-Induction.pcap.gz.'''
217         check_text2pcap(self, wpa_induction_pcap_gz, 'pcap')
218
219 class case_text2pcap_pcap(subprocesstest.SubprocessTestCase):
220     def test_text2pcap_dhcp_pcapng(self):
221         '''Test text2pcap with dhcp.pcapng.'''
222         check_text2pcap(self, dhcp_pcapng, 'pcapng')
223
224     def test_text2pcap_dhcp_nanosecond_pcapng(self):
225         '''Test text2pcap with dhcp-nanosecond.pcapng.'''
226         check_text2pcap(self, dhcp_nanosecond_pcapng, 'pcapng')
227
228     def test_text2pcap_dhe1_pcapng_gz(self):
229         '''Test text2pcap with dhe1.pcapng.gz.'''
230         check_text2pcap(self, dhe1_pcapng_gz, 'pcapng')
231
232     def test_text2pcap_dmgr_pcapng(self):
233         '''Test text2pcap with dmgr.pcapng.'''
234         check_text2pcap(self, dmgr_pcapng, 'pcapng')
235
236     def test_text2pcap_dns_icmp_pcapng_gz(self):
237         '''Test text2pcap with dns+icmp.pcapng.gz.'''
238         # Different data size
239         # Most probably the problem is that input file timestamp precision is in microseconds
240         # File timestamp precision: microseconds (6)
241         check_text2pcap(self, dns_icmp_pcapng_gz, 'pcapng', None, 3180)
242
243     def test_text2pcap_packet_h2_14_headers_pcapng(self):
244         '''Test text2pcap with packet-h2-14_headers.pcapng.'''
245         check_text2pcap(self, packet_h2_14_headers_pcapng, 'pcapng')
246
247     def test_text2pcap_sip_pcapng(self):
248         '''Test text2pcap with sip.pcapng.'''
249         check_text2pcap(self, sip_pcapng, 'pcapng')
250
251 class case_text2pcap_eol_hash(subprocesstest.SubprocessTestCase):
252     def test_text2pcap_eol_hash(self):
253         '''Test text2pcap hash sign at the end-of-line.'''
254         txt_fname = 'text2pcap_hash_eol.txt'
255         txt_file = os.path.join(config.capture_dir, txt_fname)
256         testout_file = self.filename_from_id(testout_pcap)
257         self.assertRun((config.cmd_text2pcap,
258             '-n',
259             '-d',
260             '-t', '%Y-%m-%d %H:%M:%S.',
261             txt_file,
262             testout_file,
263         ))
264         self.assertFalse(self.grepOutput('Inconsistent offset'), 'text2pcap failed to parse the hash sign at the end of the line')
265         self.assertTrue(self.grepOutput('Directive \[ test_directive'), 'text2pcap failed to parse #TEXT2PCAP test_directive')
266         pre_cmp_info = {'encapsulation': 'Ethernet', 'packets': 1, 'datasize': 96 }
267         post_cmp_info = check_capinfos_info(self, testout_file)
268         compare_capinfos_info(self, pre_cmp_info, post_cmp_info, txt_fname, testout_pcap)
269
270
271
272 #       test_step_add "hash sign at the end of the line" text2pcap_step_hash_at_eol
273
274
275
276 # text2pcap_step_hash_at_eol() {
277 #       $TEXT2PCAP -n -d -t "%Y-%m-%d %H:%M:%S."\
278 #               "${CAPTURE_DIR}/text2pcap_hash_eol.txt" testout.pcap > testout.txt 2>&1
279 #       RETURNVALUE=$?
280
281 #       grep -q "Inconsistent offset" testout.txt
282 #       if [ $? -eq 0 ]; then
283 #               cat ./testout.txt
284 #               test_step_failed "text2pcap failed to parse the hash sign at the end of the line"
285 #       fi
286
287 #       #Check that #TEXT2PCAP is not prased as a comment
288 #       grep -q "Directive \[ test_directive" testout.txt
289 #       if [ $? -ne 0 ]; then
290 #               cat ./testout.txt
291 #               test_step_failed "text2pcap failed to parse #TEXT2PCAP test_directive"
292 #       fi
293
294 #       text2pcap_common_pcapng_check $RETURNVALUE "Ethernet" 1 96
295 #       test_step_ok
296 # }
297
298