1 # Copyright (c) 2013 by Gilbert Ramirez <gram@alumni.rice.edu>
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 from suite_dfilter
.dfiltertest
import *
9 class TestDfilterSyntax
:
10 trace_file
= "http.pcap"
12 def test_exists_1(self
, checkDFilterCount
):
14 checkDFilterCount(dfilter
, 1)
16 def test_exists_2(self
, checkDFilterCount
):
17 # Protocol using minus
19 checkDFilterCount(dfilter
, 0)
21 def test_exists_3(self
, checkDFilterCount
):
22 # Protocol starting with digit
23 dfilter
= "9p or http"
24 checkDFilterCount(dfilter
, 1)
26 # The HTTP dissector no longer has a expert Chat
27 # def test_exists_4(self, checkDFilterCount):
29 # dfilter = "_ws.expert"
30 # checkDFilterCount(dfilter, 1)
32 def test_exists_5(self
, checkDFilterSucceed
):
33 # Protocol field name with leading digit and minus
34 dfilter
= "diameter.3GPP-Reporting-Reason"
35 checkDFilterSucceed(dfilter
)
37 def test_commute_1(self
, checkDFilterCount
):
38 dfilter
= "ip.proto == 6"
39 checkDFilterCount(dfilter
, 1)
41 def test_commute_2(self
, checkDFilterCount
):
42 dfilter
= "6 == ip.proto"
43 checkDFilterCount(dfilter
, 1)
45 def test_commute_3(self
, checkDFilterFail
):
47 error
= "Constant expression is invalid"
48 checkDFilterFail(dfilter
, error
)
50 def test_func_1(self
, checkDFilterCount
):
51 dfilter
= "len(frame) == 207"
52 checkDFilterCount(dfilter
, 1)
54 def test_value_string_1(self
, checkDFilterSucceed
):
55 dfilter
= 'eth.fcs.status=="Bad"'
56 checkDFilterSucceed(dfilter
)
58 def test_matches_1(self
, checkDFilterSucceed
):
59 dfilter
= 'http.request.method matches "^HEAD"'
60 checkDFilterSucceed(dfilter
)
62 def test_matches_2(self
, checkDFilterFail
):
63 dfilter
= 'http.request.method matches HEAD'
64 checkDFilterFail(dfilter
, 'requires a double quoted string')
66 def test_matches_3(self
, checkDFilterFail
):
67 dfilter
= 'http.request.method matches "^HEAD" matches "^POST"'
68 checkDFilterFail(dfilter
, '"matches" was unexpected in this context.')
70 def test_matches_4(self
, checkDFilterCount
):
71 dfilter
= r
'http.host matches r"update\.microsoft\.c.."'
72 checkDFilterCount(dfilter
, 1)
74 def test_matches_5(self
, checkDFilterSucceed
):
76 dfilter
= 'http.request.method matches "^head"'
77 checkDFilterSucceed(dfilter
)
79 def test_equal_1(self
, checkDFilterCount
):
80 dfilter
= 'ip.addr == 10.0.0.5'
81 checkDFilterCount(dfilter
, 1)
83 def test_equal_2(self
, checkDFilterCount
):
84 dfilter
= 'ip.addr == 207.46.134.94'
85 checkDFilterCount(dfilter
, 1)
87 def test_equal_3(self
, checkDFilterCount
):
88 dfilter
= 'ip.addr == 10.0.0.5 or ip.addr == 207.46.134.94'
89 checkDFilterCount(dfilter
, 1)
91 def test_equal_4(self
, checkDFilterCount
):
92 dfilter
= 'ip.addr == 10.0.0.5 and ip.addr == 207.46.134.94'
93 checkDFilterCount(dfilter
, 1)
95 def test_not_equal_1(self
, checkDFilterCount
):
96 dfilter
= 'ip.addr != 10.0.0.5'
97 checkDFilterCount(dfilter
, 0)
99 def test_not_equal_2(self
, checkDFilterCount
):
100 dfilter
= 'ip.addr != 207.46.134.94'
101 checkDFilterCount(dfilter
, 0)
103 def test_not_equal_3(self
, checkDFilterCount
):
104 dfilter
= 'ip.addr != 10.0.0.5 and ip.addr != 207.46.134.94'
105 checkDFilterCount(dfilter
, 0)
107 def test_not_equal_4(self
, checkDFilterCount
):
108 dfilter
= 'ip.addr != 10.0.0.5 or ip.addr != 207.46.134.94'
109 checkDFilterCount(dfilter
, 0)
111 def test_deprecated_1(self
, checkDFilterSucceed
):
113 checkDFilterSucceed(dfilter
, "Deprecated token \"bootp\"")
115 def test_charconst_bytes_1(self
, checkDFilterCount
):
116 # Bytes as a character constant.
117 dfilter
= "frame contains 'H'"
118 checkDFilterCount(dfilter
, 1)
120 def test_charconst_bytes_2(self
, checkDFilterCount
):
121 dfilter
= "frame[54] == 'H'"
122 checkDFilterCount(dfilter
, 1)
124 def test_charconst_invalid(self
, checkDFilterFail
):
125 dfilter
= r
"ip.proto == '\Z'"
126 checkDFilterFail(dfilter
, "isn't a valid character constant")
128 def test_bool_1(self
, checkDFilterCount
):
129 dfilter
= "tcp.flags.push == 1"
130 checkDFilterCount(dfilter
, 1)
132 def test_bool_2(self
, checkDFilterCount
):
133 dfilter
= "tcp.flags.push == True"
134 checkDFilterCount(dfilter
, 1)
136 def test_bool_2(self
, checkDFilterCount
):
137 dfilter
= "tcp.flags.push == FALSE"
138 checkDFilterCount(dfilter
, 0)
140 def test_misc_1(self
, checkDFilterSucceed
):
142 dfilter
= "icmp and ((icmp.type > 0 and icmp.type < 8) or icmp.type > 8)"
143 checkDFilterSucceed(dfilter
)
145 def test_whitespace(self
, checkDFilterSucceed
):
146 dfilter
= '\ttcp.stream \r\n== 1'
147 checkDFilterSucceed(dfilter
)
149 def test_func_name_clash1(self
, checkDFilterFail
):
150 # "tcp" is a (non-existent) function, not a protocol
151 error
= "Function 'tcp' does not exist"
152 dfilter
= 'frame == tcp()'
153 checkDFilterFail(dfilter
, error
)
155 class TestDfilterEquality
:
156 trace_file
= "sip.pcapng"
158 def test_all_eq_1(self
, checkDFilterCount
):
159 dfilter
= "udp.port === 5060"
160 checkDFilterCount(dfilter
, 2)
162 def test_any_ne_1(self
, checkDFilterCount
):
163 dfilter
= "udp.port !== 5060"
164 checkDFilterCount(dfilter
, 4)
166 def test_any_eq_1(self
, checkDFilterCount
):
167 dfilter
= "udp.port == 5060"
168 checkDFilterCount(dfilter
, 5)
170 def test_all_ne_1(self
, checkDFilterCount
):
171 dfilter
= "udp.port != 5060"
172 checkDFilterCount(dfilter
, 1)
174 def test_root_1(self
, checkDFilterCount
):
175 dfilter
= "udp.srcport == .udp.dstport"
176 checkDFilterCount(dfilter
, 2)
178 def test_literal_3(self
, checkDFilterCount
):
179 dfilter
= "frame[0:10] contains :00:01:6c"
180 checkDFilterCount(dfilter
, 1)
182 def test_literal_4(self
, checkDFilterCount
):
183 dfilter
= "frame[0:10] contains :00016c"
184 checkDFilterCount(dfilter
, 1)
186 def test_literal_5(self
, checkDFilterCount
):
187 dfilter
= "frame[0:10] contains :00.01.6c"
188 checkDFilterCount(dfilter
, 1)
190 def test_literal_6(self
, checkDFilterCount
):
191 dfilter
= "frame[0:10] contains :00-01-6c"
192 checkDFilterCount(dfilter
, 1)
194 def test_rhs_bias_1(self
, checkDFilterCount
):
195 # Protocol "Fibre Channel" on the RHS
196 dfilter
= 'frame[37] == fc'
197 checkDFilterCount(dfilter
, 0)
199 def test_rhs_bias_2(self
, checkDFilterCount
):
200 # Byte 0xFC on the RHS
201 dfilter
= 'frame[37] == :fc'
202 checkDFilterCount(dfilter
, 1)
204 def test_rhs_bias_3(self
, checkDFilterCount
):
205 # Byte 0xFC on the RHS
206 dfilter
= 'frame[37] == fc:'
207 checkDFilterCount(dfilter
, 1)
209 def test_rhs_bias_4(self
, checkDFilterCount
):
210 # Protocol "Fibre Channel" on the RHS
211 dfilter
= 'frame[37] == .fc'
212 checkDFilterCount(dfilter
, 0)
214 def test_rhs_bias_5(self
, checkDFilterSucceed
):
215 # Protocol "Fibre Channel" on the RHS (with warning)
216 dfilter
= 'frame contains fc'
217 checkDFilterSucceed(dfilter
, 'Interpreting "fc" as Fibre Channel')
219 def test_rhs_bias_6(self
, checkDFilterSucceed
):
220 # Protocol "Fibre Channel" on the RHS (without warning)
221 dfilter
= 'frame contains .fc'
222 checkDFilterSucceed(dfilter
)
224 def test_rhs_bias_7(self
, checkDFilterSucceed
):
225 # Byte 0xFC on the RHS
226 dfilter
= 'frame contains fc:'
227 checkDFilterSucceed(dfilter
)
229 class TestDfilterBitwise
:
230 trace_file
= "http.pcap"
232 def test_exists_1(self
, checkDFilterCount
):
233 dfilter
= "tcp.flags & 0x8"
234 checkDFilterCount(dfilter
, 1)
236 def test_exists_2(self
, checkDFilterCount
):
237 dfilter
= "tcp.flags bitand 0x8"
238 checkDFilterCount(dfilter
, 1)
240 def test_exists_3(self
, checkDFilterCount
):
241 dfilter
= "eth[0] & 1"
242 checkDFilterCount(dfilter
, 0)
244 def test_equal_1(self
, checkDFilterCount
):
245 dfilter
= "tcp.flags & 0x0F == 8"
246 checkDFilterCount(dfilter
, 1)
248 def test_equal_2(self
, checkDFilterCount
):
249 dfilter
= "tcp.srcport != tcp.dstport & 0x0F"
250 checkDFilterCount(dfilter
, 1)
252 def test_equal_3(self
, checkDFilterCount
):
253 dfilter
= "tcp.srcport != tcp.dstport bitand 0x0F"
254 checkDFilterCount(dfilter
, 1)
256 def test_equal_4(self
, checkDFilterCount
):
257 dfilter
= "tcp.srcport != tcp.dstport bitwise_and 0x0F"
258 checkDFilterCount(dfilter
, 1)
260 class TestDfilterUnaryMinus
:
261 trace_file
= "http.pcap"
263 def test_minus_const_1(self
, checkDFilterCount
):
264 dfilter
= "tcp.window_size_scalefactor == -1"
265 checkDFilterCount(dfilter
, 1)
267 def test_minus_const_2(self
, checkDFilterCount
):
268 dfilter
= "tcp.window_size_scalefactor == -2"
269 checkDFilterCount(dfilter
, 0)
271 def test_plus_const_1(self
, checkDFilterCount
):
272 dfilter
= "tcp.window_size_scalefactor == +1"
273 checkDFilterCount(dfilter
, 0)
275 def test_unary_1(self
, checkDFilterCount
):
276 dfilter
= "tcp.window_size_scalefactor == -tcp.dstport"
277 checkDFilterCount(dfilter
, 0)
279 def test_unary_2(self
, checkDFilterCount
):
280 dfilter
= "tcp.window_size_scalefactor == +tcp.dstport"
281 checkDFilterCount(dfilter
, 0)
283 def test_unary_3(self
, checkDFilterCount
):
284 dfilter
= "-2 == tcp.dstport"
285 checkDFilterCount(dfilter
, 0)
287 def test_unary_4(self
, checkDFilterCount
):
288 dfilter
= "tcp.window_size_scalefactor == -{tcp.dstport * 20}"
289 checkDFilterCount(dfilter
, 0)
291 def test_unary_invalid_1(self
, checkDFilterFail
):
292 error
= 'FT_PROTOCOL cannot be negated'
294 checkDFilterFail(dfilter
, error
)
296 class TestDfilterArithmetic
:
297 trace_file
= "dhcp.pcap"
299 def test_add_1(self
, checkDFilterCount
):
300 dfilter
= "udp.dstport == udp.srcport + 1"
301 checkDFilterCount(dfilter
, 2)
303 def test_add_2(self
, checkDFilterCount
):
304 dfilter
= "udp.dstport == 66 + 1"
305 checkDFilterCount(dfilter
, 2)
307 def test_add_3(self
, checkDFilterCount
):
308 dfilter
= "udp.dstport == 66+1"
309 checkDFilterCount(dfilter
, 2)
311 def test_add_4(self
, checkDFilterCount
):
312 dfilter
= "1 + 2 == frame.number"
313 checkDFilterCount(dfilter
, 1)
315 def test_add_5(self
, checkDFilterFail
):
316 error
= 'Constant expression is invalid'
317 dfilter
= "1 + 2 == 2 + 1"
318 checkDFilterFail(dfilter
, error
)
320 def test_add_6(self
, checkDFilterFail
):
321 error
= 'Constant expression is invalid'
323 checkDFilterFail(dfilter
, error
)
325 def test_add_7(self
, checkDFilterCount
):
326 dfilter
= r
"udp.dstport == 66+'\x01'"
327 checkDFilterCount(dfilter
, 2)
329 def test_sub_1(self
, checkDFilterCount
):
330 dfilter
= "udp.srcport == udp.dstport - 1"
331 checkDFilterCount(dfilter
, 2)
333 def test_sub_2(self
, checkDFilterCount
):
334 dfilter
= "udp.dstport == 68 - 1"
335 checkDFilterCount(dfilter
, 2)
337 def test_sub_3(self
, checkDFilterCount
):
338 dfilter
= "udp.length == ip.len - 20"
339 checkDFilterCount(dfilter
, 4)
341 def test_sub_no_space_1(self
, checkDFilterFail
):
342 # Minus operator requires whitespace preceding it.
343 error
= '"68-1" cannot be converted to Unsigned integer'
344 dfilter
= "udp.dstport == 68-1"
345 checkDFilterFail(dfilter
, error
)
347 def test_sub_no_space_2(self
, checkDFilterFail
):
348 # Different case, 68-67 should not be parsed
349 # as bytes separated by hyphen XX-XX-XX
350 # Minus operator still requires whitespace preceding it.
351 error
= '"68-67" cannot be converted to Unsigned integer'
352 dfilter
= "frame.number == 68-67"
353 checkDFilterFail(dfilter
, error
)
355 def test_expr_1(self
, checkDFilterCount
):
356 dfilter
= 'udp.port * { 10 / {5 - 4} } == udp.port * { {50 + 50} / 2 - 40 }'
357 checkDFilterCount(dfilter
, 4)
359 def test_expr_2(self
, checkDFilterCount
):
360 dfilter
= 'udp.dstport * { udp.srcport / {5 - 4} } == udp.srcport * { 2 * udp.dstport - 68 }'
361 checkDFilterCount(dfilter
, 2)
363 class TestDfilterFieldReference
:
364 trace_file
= "ipoipoip.pcap"
366 def test_ref_1(self
, checkDFilterCountWithSelectedFrame
):
367 dfilter
= 'frame.number < ${frame.number}'
368 # select frame 2, expect 1 frames out of 2.
369 checkDFilterCountWithSelectedFrame(dfilter
, 1, 2)
371 def test_ref_2(self
, checkDFilterCountWithSelectedFrame
):
372 dfilter
= 'ip.src#3 == ${ip.src#4}'
373 # select frame 1, expect 1 frames out of 2.
374 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
376 def test_ref_3(self
, checkDFilterCountWithSelectedFrame
):
377 dfilter
= 'frame.number < $frame.number'
378 # select frame 2, expect 1 frames out of 2.
379 checkDFilterCountWithSelectedFrame(dfilter
, 1, 2)
381 def test_ref_4(self
, checkDFilterCountWithSelectedFrame
):
382 dfilter
= 'ip.src#3 == $ip.src#4'
383 # select frame 1, expect 1 frames out of 2.
384 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
386 def test_ref_5(self
, checkDFilterCountWithSelectedFrame
):
387 dfilter
= 'frame[52-54] == ${@ip.src}[0-2]'
388 # select frame 1, expect 1 frames out of 2.
389 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
391 def test_ref_6(self
, checkDFilterCountWithSelectedFrame
):
392 dfilter
= 'frame[52-54] == $@ip.src[0-2]'
393 # select frame 1, expect 1 frames out of 2.
394 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
396 def test_ref_7(self
, checkDFilterFail
):
397 # anything after $ must be a field
398 dfilter
= 'frame == $aaaa'
399 error
= '"aaaa" is not a valid protocol or protocol field'
400 checkDFilterFail(dfilter
, error
)
402 class TestDfilterLayer
:
403 trace_file
= "ipoipoip.pcap"
405 def test_layer_1(self
, checkDFilterCount
):
406 dfilter
= 'ip.addr#2 == 4.4.4.4'
407 checkDFilterCount(dfilter
, 1)
409 def test_layer_2(self
, checkDFilterCount
):
410 dfilter
= 'ip.addr#5'
411 checkDFilterCount(dfilter
, 1)
413 def test_layer_3(self
, checkDFilterCount
):
414 dfilter
= 'ip.addr#6'
415 checkDFilterCount(dfilter
, 0)
417 def test_layer_4(self
, checkDFilterCount
):
418 dfilter
= 'ip.dst#[2-4] == 8.8.8.8'
419 checkDFilterCount(dfilter
, 1)
421 def test_layer_5(self
, checkDFilterCount
):
422 dfilter
= 'ip.dst#[-1] == 8.8.8.8'
423 checkDFilterCount(dfilter
, 0)
425 def test_layer_6(self
, checkDFilterCount
):
426 dfilter
= 'ip.dst#[-1] == 9.9.9.9'
427 checkDFilterCount(dfilter
, 1)
429 def test_layer_7(self
, checkDFilterCount
):
430 dfilter
= 'ip.dst#[-5] == 2.2.2.2'
431 checkDFilterCount(dfilter
, 1)
433 class TestDfilterQuantifiers
:
434 trace_file
= "ipoipoip.pcap"
436 def test_any_1(self
, checkDFilterCount
):
437 dfilter
= 'any ip.addr > 1.1.1.1'
438 checkDFilterCount(dfilter
, 2)
440 def test_all_1(self
, checkDFilterCount
):
441 dfilter
= 'all ip.addr > 1.1.1.1'
442 checkDFilterCount(dfilter
, 1)
444 class TestDfilterRawModifier
:
445 trace_file
= "s7comm-fuzz.pcapng.gz"
447 def test_regular(self
, checkDFilterCount
):
448 dfilter
= 's7comm.blockinfo.blocktype == "0\uFFFD"'
449 checkDFilterCount(dfilter
, 3)
451 def test_raw1(self
, checkDFilterCount
):
452 dfilter
= '@s7comm.blockinfo.blocktype == 30:aa'
453 checkDFilterCount(dfilter
, 2)
455 def test_raw2(self
, checkDFilterCount
):
456 dfilter
= '@s7comm.blockinfo.blocktype == 30:fe'
457 checkDFilterCount(dfilter
, 1)
459 def test_raw_ref(self
, checkDFilterCountWithSelectedFrame
):
460 dfilter
= '@s7comm.blockinfo.blocktype == ${@s7comm.blockinfo.blocktype}'
461 # select frame 3, expect 2 frames out of 3.
462 checkDFilterCountWithSelectedFrame(dfilter
, 2, 3)
464 class TestDfilterRawSlice
:
465 trace_file
= "http.pcap"
467 def test_raw_slice1(self
, checkDFilterFail
):
468 dfilter
= 'tcp.port[1] == 0xc3'
469 checkDFilterFail(dfilter
, "cannot be sliced")
471 def test_raw_slice2(self
, checkDFilterCount
):
472 dfilter
= '@tcp.port[1] == 0xc3'
473 checkDFilterCount(dfilter
, 1)
475 def test_raw_slice3(self
, checkDFilterFail
):
476 dfilter
= 'tcp.port[0:] == 0c:c3'
477 checkDFilterFail(dfilter
, "cannot be sliced")
479 def test_raw_slice4(self
, checkDFilterCount
):
480 dfilter
= '@tcp.port[0:] == 0c:c3'
481 checkDFilterCount(dfilter
, 1)
483 class TestDfilterXor
:
484 trace_file
= "ipoipoip.pcap"
486 def test_xor_1(self
, checkDFilterCount
):
487 dfilter
= 'ip.src == 7.7.7.7 xor ip.dst == 7.7.7.7'
488 checkDFilterCount(dfilter
, 1)
490 def test_xor_2(self
, checkDFilterCount
):
491 dfilter
= 'ip.src == 7.7.7.7 ^^ ip.dst == 7.7.7.7'
492 checkDFilterCount(dfilter
, 1)
494 def test_xor_3(self
, checkDFilterCount
):
495 dfilter
= 'ip.src == 9.9.9.9 xor ip.dst == 9.9.9.9'
496 checkDFilterCount(dfilter
, 0)
498 def test_xor_4(self
, checkDFilterCount
):
499 dfilter
= 'ip.src == 9.9.9.9 ^^ ip.dst == 9.9.9.9'
500 checkDFilterCount(dfilter
, 0)
502 class TestDfilterTFSValueString
:
503 trace_file
= "http.pcap"
505 def test_tfs_1(self
, checkDFilterCount
):
506 dfilter
= 'ip.flags.df == True'
507 checkDFilterCount(dfilter
, 1)
509 def test_tfs_2(self
, checkDFilterCount
):
510 dfilter
= 'ip.flags.df == "True"'
511 checkDFilterCount(dfilter
, 1)
513 def test_tfs_3(self
, checkDFilterCount
):
514 dfilter
= 'ip.flags.df == "Set"'
515 checkDFilterCount(dfilter
, 1)
517 def test_tfs_4(self
, checkDFilterCount
):
518 dfilter
= 'frame.ignored == False'
519 checkDFilterCount(dfilter
, 1)
521 def test_tfs_5(self
, checkDFilterCount
):
522 dfilter
= 'frame.ignored == "False"'
523 checkDFilterCount(dfilter
, 1)
525 def test_tfs_6(self
, checkDFilterFail
):
526 error
= 'expected "True" or "False", not "Unset"'
527 dfilter
= 'frame.ignored == "Unset"'
528 checkDFilterFail(dfilter
, error
)