wireshark/test/suite_dfilter/group_membership.py

95 lines
3.5 KiB
Python
Raw Normal View History

# Copyright (c) 2018 Peter Wu <peter@lekensteyn.nl>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import unittest
import fixtures
from suite_dfilter.dfiltertest import *
@fixtures.uses_fixtures
class case_membership(unittest.TestCase):
trace_file = "http.pcap"
def test_membership_match_1(self, checkDFilterCount):
dfilter = 'tcp.port in {80, 3267}'
checkDFilterCount(dfilter, 1)
def test_membership_match_2(self, checkDFilterCount):
dfilter = 'tcp.port in {80,3267}'
checkDFilterCount(dfilter, 1)
def test_membership_match_3(self, checkDFilterCount):
dfilter = 'tcp.port in {80 ,3267}'
checkDFilterCount(dfilter, 1)
def test_membership_match_4(self, checkDFilterCount):
dfilter = 'tcp.port in {80 , 3267}'
checkDFilterCount(dfilter, 1)
def test_membership_match_5(self, checkDFilterCount):
dfilter = 'tcp.port in { 80 , 3267 }'
checkDFilterCount(dfilter, 1)
def test_membership_range_match_1(self, checkDFilterCount):
dfilter = 'tcp.port in {80..81}'
checkDFilterCount(dfilter, 1)
def test_membership_range_match_2(self, checkDFilterCount):
dfilter = 'tcp.port in {80 ..81}'
checkDFilterCount(dfilter, 1)
def test_membership_range_match_3(self, checkDFilterCount):
dfilter = 'tcp.port in {80.. 81}'
checkDFilterCount(dfilter, 1)
def test_membership_range_match_4(self, checkDFilterCount):
dfilter = 'tcp.port in {80 .. 81}'
checkDFilterCount(dfilter, 1)
def test_membership_3_range_no_match(self, checkDFilterCount):
dfilter = 'tcp.dstport in {1 .. 79, 81 .. 65535}'
checkDFilterCount(dfilter, 0)
def test_membership_4_range_no_match_multiple(self, checkDFilterCount):
# Verifies that multiple fields cannot satisfy different conditions.
dfilter = 'tcp.port in {1 .. 79,81 .. 3266,3268 .. 65535}'
checkDFilterCount(dfilter, 0)
def test_membership_5_negative_range_float(self, checkDFilterCount):
dfilter = 'frame.time_delta in {-2.0 .. 0.0}'
checkDFilterCount(dfilter, 1)
def test_membership_6_both_negative_range_float(self, checkDFilterCount):
dfilter = 'frame.time_delta in {-20 .. -0.7}'
checkDFilterCount(dfilter, 0)
def test_membership_7_string(self, checkDFilterCount):
dfilter = 'http.request.method in {"GET", "HEAD"}'
checkDFilterCount(dfilter, 1)
def test_membership_8_ip_range(self, checkDFilterCount):
dfilter = 'ip.addr in { 10.0.0.5 .. 10.0.0.9 , 10.0.0.1..10.0.0.1 }'
checkDFilterCount(dfilter, 1)
dfilter: Add special syntax for literals and names The syntax for protocols and some literals like numbers and bytes/addresses can be ambiguous. Some protocols can be parsed as a literal, for example the protocol "fc" (Fibre Channel) can be parsed as 0xFC. If a numeric protocol is registered that will also take precedence over any literal, according to the current rules, thereby breaking numerical comparisons to that number. The same for an hypothetical protocol named "true", etc. To allow the user to disambiguate this meaning introduce new syntax. Any value prefixed with ':' or enclosed in <,> will be treated as a literal value only. The value :fc or <fc> will always mean 0xFC, under any context. Never a protocol whose filter name is "fc". Likewise any value prefixed with a dot will always be parsed as an identifier (protocol or protocol field) in the language. Never any literal value parsed from the token "fc". This allows the user to be explicit about the meaning, and between the two explicit methods plus the ambiguous one it doesn't completely break any one meaning. The difference can be seen in the following two programs: Filter: frame == fc Constants: Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 5 00002 READ_TREE fc -> reg#1 00003 IF-FALSE-GOTO 5 00004 ANY_EQ reg#0 == reg#1 00005 RETURN -------- Filter: frame == :fc Constants: 00000 PUT_FVALUE fc <FT_PROTOCOL> -> reg#1 Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 3 00002 ANY_EQ reg#0 == reg#1 00003 RETURN The filter "frame == fc" is the same as "filter == .fc", according to the current heuristic, except the first form will try to parse it as a literal if the name does not correspond to any registered protocol. By treating a leading dot as a name in the language we necessarily disallow writing floats with a leading dot. We will also disallow writing with an ending dot when using unparsed values. This is a backward incompatibility but has the happy side effect of making the expression {1...2} unambiguous. This could either mean "1 .. .2" or "1. .. 2". If we require a leading and ending digit then the meaning is clear: 1.0..0.2 -> 1.0 .. 0.2 Fixes #17731.
2022-02-22 21:55:05 +00:00
def test_membership_9_range_invalid_float(self, checkDFilterFail):
# expression should be parsed as "0.1 .. .7"
dfilter: Add special syntax for literals and names The syntax for protocols and some literals like numbers and bytes/addresses can be ambiguous. Some protocols can be parsed as a literal, for example the protocol "fc" (Fibre Channel) can be parsed as 0xFC. If a numeric protocol is registered that will also take precedence over any literal, according to the current rules, thereby breaking numerical comparisons to that number. The same for an hypothetical protocol named "true", etc. To allow the user to disambiguate this meaning introduce new syntax. Any value prefixed with ':' or enclosed in <,> will be treated as a literal value only. The value :fc or <fc> will always mean 0xFC, under any context. Never a protocol whose filter name is "fc". Likewise any value prefixed with a dot will always be parsed as an identifier (protocol or protocol field) in the language. Never any literal value parsed from the token "fc". This allows the user to be explicit about the meaning, and between the two explicit methods plus the ambiguous one it doesn't completely break any one meaning. The difference can be seen in the following two programs: Filter: frame == fc Constants: Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 5 00002 READ_TREE fc -> reg#1 00003 IF-FALSE-GOTO 5 00004 ANY_EQ reg#0 == reg#1 00005 RETURN -------- Filter: frame == :fc Constants: 00000 PUT_FVALUE fc <FT_PROTOCOL> -> reg#1 Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 3 00002 ANY_EQ reg#0 == reg#1 00003 RETURN The filter "frame == fc" is the same as "filter == .fc", according to the current heuristic, except the first form will try to parse it as a literal if the name does not correspond to any registered protocol. By treating a leading dot as a name in the language we necessarily disallow writing floats with a leading dot. We will also disallow writing with an ending dot when using unparsed values. This is a backward incompatibility but has the happy side effect of making the expression {1...2} unambiguous. This could either mean "1 .. .2" or "1. .. 2". If we require a leading and ending digit then the meaning is clear: 1.0..0.2 -> 1.0 .. 0.2 Fixes #17731.
2022-02-22 21:55:05 +00:00
# .7 is the identifier (protocol) named "7"
dfilter = 'frame.time_delta in {0.1...7}'
dfilter: Add special syntax for literals and names The syntax for protocols and some literals like numbers and bytes/addresses can be ambiguous. Some protocols can be parsed as a literal, for example the protocol "fc" (Fibre Channel) can be parsed as 0xFC. If a numeric protocol is registered that will also take precedence over any literal, according to the current rules, thereby breaking numerical comparisons to that number. The same for an hypothetical protocol named "true", etc. To allow the user to disambiguate this meaning introduce new syntax. Any value prefixed with ':' or enclosed in <,> will be treated as a literal value only. The value :fc or <fc> will always mean 0xFC, under any context. Never a protocol whose filter name is "fc". Likewise any value prefixed with a dot will always be parsed as an identifier (protocol or protocol field) in the language. Never any literal value parsed from the token "fc". This allows the user to be explicit about the meaning, and between the two explicit methods plus the ambiguous one it doesn't completely break any one meaning. The difference can be seen in the following two programs: Filter: frame == fc Constants: Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 5 00002 READ_TREE fc -> reg#1 00003 IF-FALSE-GOTO 5 00004 ANY_EQ reg#0 == reg#1 00005 RETURN -------- Filter: frame == :fc Constants: 00000 PUT_FVALUE fc <FT_PROTOCOL> -> reg#1 Instructions: 00000 READ_TREE frame -> reg#0 00001 IF-FALSE-GOTO 3 00002 ANY_EQ reg#0 == reg#1 00003 RETURN The filter "frame == fc" is the same as "filter == .fc", according to the current heuristic, except the first form will try to parse it as a literal if the name does not correspond to any registered protocol. By treating a leading dot as a name in the language we necessarily disallow writing floats with a leading dot. We will also disallow writing with an ending dot when using unparsed values. This is a backward incompatibility but has the happy side effect of making the expression {1...2} unambiguous. This could either mean "1 .. .2" or "1. .. 2". If we require a leading and ending digit then the meaning is clear: 1.0..0.2 -> 1.0 .. 0.2 Fixes #17731.
2022-02-22 21:55:05 +00:00
error = 'not a valid protocol or protocol field'
checkDFilterFail(dfilter, error)
def test_membership_10_bad_lhs_number(self, checkDFilterFail):
dfilter = '123 in {ip}'
error = 'Only a field may be tested for membership in a set.'
checkDFilterFail(dfilter, error)
def test_membership_11_bad_rhs_string(self, checkDFilterFail):
dfilter = 'frame.number in {1, "foo"}'
error = 'Unsigned integer (4 bytes) cannot be converted from a string'
checkDFilterFail(dfilter, error)
def test_membership_12_value_string(self, checkDFilterCount):
dfilter = 'tcp.checksum.status in {"Unverified", "Good"}'
checkDFilterCount(dfilter, 1)