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_4(self
, checkDFilterCount
):
342 # The RHS is sometimes negative, sometimes equal to LHS.
343 # LHS is a FT_UINT8. It should match twice.
344 dfilter
= "ip.proto == ip.len - 311"
345 checkDFilterCount(dfilter
, 2)
347 def test_sub_no_space_1(self
, checkDFilterFail
):
348 # Minus operator requires whitespace preceding it.
349 error
= '"68-1" cannot be converted to Unsigned integer'
350 dfilter
= "udp.dstport == 68-1"
351 checkDFilterFail(dfilter
, error
)
353 def test_sub_no_space_2(self
, checkDFilterFail
):
354 # Different case, 68-67 should not be parsed
355 # as bytes separated by hyphen XX-XX-XX
356 # Minus operator still requires whitespace preceding it.
357 error
= '"68-67" cannot be converted to Unsigned integer'
358 dfilter
= "frame.number == 68-67"
359 checkDFilterFail(dfilter
, error
)
361 def test_expr_1(self
, checkDFilterCount
):
362 dfilter
= 'udp.port * { 10 / {5 - 4} } == udp.port * { {50 + 50} / 2 - 40 }'
363 checkDFilterCount(dfilter
, 4)
365 def test_expr_2(self
, checkDFilterCount
):
366 dfilter
= 'udp.dstport * { udp.srcport / {5 - 4} } == udp.srcport * { 2 * udp.dstport - 68 }'
367 checkDFilterCount(dfilter
, 2)
369 class TestDfilterFieldReference
:
370 trace_file
= "ipoipoip.pcap"
372 def test_ref_1(self
, checkDFilterCountWithSelectedFrame
):
373 dfilter
= 'frame.number < ${frame.number}'
374 # select frame 2, expect 1 frames out of 2.
375 checkDFilterCountWithSelectedFrame(dfilter
, 1, 2)
377 def test_ref_2(self
, checkDFilterCountWithSelectedFrame
):
378 dfilter
= 'ip.src#3 == ${ip.src#4}'
379 # select frame 1, expect 1 frames out of 2.
380 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
382 def test_ref_3(self
, checkDFilterCountWithSelectedFrame
):
383 dfilter
= 'frame.number < $frame.number'
384 # select frame 2, expect 1 frames out of 2.
385 checkDFilterCountWithSelectedFrame(dfilter
, 1, 2)
387 def test_ref_4(self
, checkDFilterCountWithSelectedFrame
):
388 dfilter
= 'ip.src#3 == $ip.src#4'
389 # select frame 1, expect 1 frames out of 2.
390 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
392 def test_ref_5(self
, checkDFilterCountWithSelectedFrame
):
393 dfilter
= 'frame[52-54] == ${@ip.src}[0-2]'
394 # select frame 1, expect 1 frames out of 2.
395 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
397 def test_ref_6(self
, checkDFilterCountWithSelectedFrame
):
398 dfilter
= 'frame[52-54] == $@ip.src[0-2]'
399 # select frame 1, expect 1 frames out of 2.
400 checkDFilterCountWithSelectedFrame(dfilter
, 1, 1)
402 def test_ref_7(self
, checkDFilterFail
):
403 # anything after $ must be a field
404 dfilter
= 'frame == $aaaa'
405 error
= '"aaaa" is not a valid protocol or protocol field'
406 checkDFilterFail(dfilter
, error
)
408 class TestDfilterLayer
:
409 trace_file
= "ipoipoip.pcap"
411 def test_layer_1(self
, checkDFilterCount
):
412 dfilter
= 'ip.addr#2 == 4.4.4.4'
413 checkDFilterCount(dfilter
, 1)
415 def test_layer_2(self
, checkDFilterCount
):
416 dfilter
= 'ip.addr#5'
417 checkDFilterCount(dfilter
, 1)
419 def test_layer_3(self
, checkDFilterCount
):
420 dfilter
= 'ip.addr#6'
421 checkDFilterCount(dfilter
, 0)
423 def test_layer_4(self
, checkDFilterCount
):
424 dfilter
= 'ip.dst#[2-4] == 8.8.8.8'
425 checkDFilterCount(dfilter
, 1)
427 def test_layer_5(self
, checkDFilterCount
):
428 dfilter
= 'ip.dst#[-1] == 8.8.8.8'
429 checkDFilterCount(dfilter
, 0)
431 def test_layer_6(self
, checkDFilterCount
):
432 dfilter
= 'ip.dst#[-1] == 9.9.9.9'
433 checkDFilterCount(dfilter
, 1)
435 def test_layer_7(self
, checkDFilterCount
):
436 dfilter
= 'ip.dst#[-5] == 2.2.2.2'
437 checkDFilterCount(dfilter
, 1)
439 class TestDfilterQuantifiers
:
440 trace_file
= "ipoipoip.pcap"
442 def test_any_1(self
, checkDFilterCount
):
443 dfilter
= 'any ip.addr > 1.1.1.1'
444 checkDFilterCount(dfilter
, 2)
446 def test_all_1(self
, checkDFilterCount
):
447 dfilter
= 'all ip.addr > 1.1.1.1'
448 checkDFilterCount(dfilter
, 1)
450 class TestDfilterRawModifier
:
451 trace_file
= "s7comm-fuzz.pcapng.gz"
453 def test_regular(self
, checkDFilterCount
):
454 dfilter
= 's7comm.blockinfo.blocktype == "0\uFFFD"'
455 checkDFilterCount(dfilter
, 3)
457 def test_raw1(self
, checkDFilterCount
):
458 dfilter
= '@s7comm.blockinfo.blocktype == 30:aa'
459 checkDFilterCount(dfilter
, 2)
461 def test_raw2(self
, checkDFilterCount
):
462 dfilter
= '@s7comm.blockinfo.blocktype == 30:fe'
463 checkDFilterCount(dfilter
, 1)
465 def test_raw_ref(self
, checkDFilterCountWithSelectedFrame
):
466 dfilter
= '@s7comm.blockinfo.blocktype == ${@s7comm.blockinfo.blocktype}'
467 # select frame 3, expect 2 frames out of 3.
468 checkDFilterCountWithSelectedFrame(dfilter
, 2, 3)
470 class TestDfilterRawSlice
:
471 trace_file
= "http.pcap"
473 def test_raw_slice1(self
, checkDFilterFail
):
474 dfilter
= 'tcp.port[1] == 0xc3'
475 checkDFilterFail(dfilter
, "cannot be sliced")
477 def test_raw_slice2(self
, checkDFilterCount
):
478 dfilter
= '@tcp.port[1] == 0xc3'
479 checkDFilterCount(dfilter
, 1)
481 def test_raw_slice3(self
, checkDFilterFail
):
482 dfilter
= 'tcp.port[0:] == 0c:c3'
483 checkDFilterFail(dfilter
, "cannot be sliced")
485 def test_raw_slice4(self
, checkDFilterCount
):
486 dfilter
= '@tcp.port[0:] == 0c:c3'
487 checkDFilterCount(dfilter
, 1)
489 class TestDfilterXor
:
490 trace_file
= "ipoipoip.pcap"
492 def test_xor_1(self
, checkDFilterCount
):
493 dfilter
= 'ip.src == 7.7.7.7 xor ip.dst == 7.7.7.7'
494 checkDFilterCount(dfilter
, 1)
496 def test_xor_2(self
, checkDFilterCount
):
497 dfilter
= 'ip.src == 7.7.7.7 ^^ ip.dst == 7.7.7.7'
498 checkDFilterCount(dfilter
, 1)
500 def test_xor_3(self
, checkDFilterCount
):
501 dfilter
= 'ip.src == 9.9.9.9 xor ip.dst == 9.9.9.9'
502 checkDFilterCount(dfilter
, 0)
504 def test_xor_4(self
, checkDFilterCount
):
505 dfilter
= 'ip.src == 9.9.9.9 ^^ ip.dst == 9.9.9.9'
506 checkDFilterCount(dfilter
, 0)
508 class TestDfilterTFSValueString
:
509 trace_file
= "http.pcap"
511 def test_tfs_1(self
, checkDFilterCount
):
512 dfilter
= 'ip.flags.df == True'
513 checkDFilterCount(dfilter
, 1)
515 def test_tfs_2(self
, checkDFilterCount
):
516 dfilter
= 'ip.flags.df == "True"'
517 checkDFilterCount(dfilter
, 1)
519 def test_tfs_3(self
, checkDFilterCount
):
520 dfilter
= 'ip.flags.df == "Set"'
521 checkDFilterCount(dfilter
, 1)
523 def test_tfs_4(self
, checkDFilterCount
):
524 dfilter
= 'frame.ignored == False'
525 checkDFilterCount(dfilter
, 1)
527 def test_tfs_5(self
, checkDFilterCount
):
528 dfilter
= 'frame.ignored == "False"'
529 checkDFilterCount(dfilter
, 1)
531 def test_tfs_6(self
, checkDFilterFail
):
532 error
= 'expected "True" or "False", not "Unset"'
533 dfilter
= 'frame.ignored == "Unset"'
534 checkDFilterFail(dfilter
, error
)