diff --git a/policy/utils/pattern.bro b/policy/utils/pattern.bro index a012247232..107eebce5b 100644 --- a/policy/utils/pattern.bro +++ b/policy/utils/pattern.bro @@ -1,11 +1,13 @@ ##! Functions for creating and working with patterns. -## This function only works at or before init time. Given a pattern as a string -## with two tildes (~~) contained in it, it will return a pattern with the -## set[string] elements OR'd together where the double-tilde was given. -## If a literal backslash is include in 'pat', it needs to be given as a double -## backslash due to Bro's string parsing reducing it to a single backslash -## upon rendering. +## Given a pattern as a string with two tildes (~~) contained in it, it will +## return a pattern with string set's elements OR'd together where the +## double-tilde was given (this function only works at or before init time). +## ss: a set of strings to OR together +## pat: the pattern containing a "~~" in it. If a literal backslash is +## included, it needs to be escaped with another backslash due to Bro's +## string parsing reducing it to a single backslash upon rendering. +## Returns: the input pattern with "~~" replaced by OR'd elements of input set function set_to_regex(ss: set[string], pat: string): pattern { local i: count = 0; @@ -31,15 +33,13 @@ type PatternMatchResult: record { ## Matches the given pattern against the given string, returning ## a :bro:type:`PatternMatchResult` record. -## For example: -## match_pattern("foobar", /o*[a-k]/) -## returns: -## [matched=T, str=f, off=1] -## because the *first* match is for zero o's followed by an [a-k], -## while: -## match_pattern("foobar", /o+[a-k]/) -## returns: -## [matched=T, str=oob, off=2] +## For example: ``match_pattern("foobar", /o*[a-k]/)`` returns +## ``[matched=T, str=f, off=1]``, because the *first* match is for +## zero o's followed by an [a-k], but ``match_pattern("foobar", /o+[a-k]/)`` +## returns ``[matched=T, str=oob, off=2]`` +## s: a string to match against +## p: a pattern to match +## Returns: a record indicating the match status function match_pattern(s: string, p: pattern): PatternMatchResult { local a = split_n(s, p, T, 1); diff --git a/policy/utils/strings.bro b/policy/utils/strings.bro index 6db9a002df..2836f368b4 100644 --- a/policy/utils/strings.bro +++ b/policy/utils/strings.bro @@ -9,8 +9,11 @@ function is_string_binary(s: string): bool return byte_len(gsub(s, /[\x00-\x7f]/, "")) * 100 / |s| >= 25; } -## Takes a :bro:type:`set[string]` and joins each element together with the -## second argument. +## Joins a set of string together, with elements delimited by a constant string. +## ss: a set of strings to join +## j: the string used to join set elements +## Returns: a string composed of the all elements of the set, delimited by the +## joining string. function join_string_set(ss: set[string], j: string): string { local output=""; @@ -26,9 +29,11 @@ function join_string_set(ss: set[string], j: string): string return output; } -## Given a string, returns an escaped version. This means that -## (1) any occurrences of any character in "chars" are escaped using '\', and -## (2) any '\'s are likewise escaped. +## Given a string, returns an escaped version. +## s: a string to escape +## chars: a string containing all the characters that need to be escaped +## Returns: a string with all occurrences of any character in ``chars`` escaped +## using ``\``, and any literal ``\`` characters likewise escaped. function string_escape(s: string, chars: string): string { s = subst_string(s, "\\", "\\\\"); @@ -38,6 +43,9 @@ function string_escape(s: string, chars: string): string } ## Cut a number of character from the end of the given string. +## s: a string to trim +## tail_len: the number of characters to remove from end of string +## Returns: the string in ``s`` with ``tail_len`` characters removed from end function cut_tail(s: string, tail_len: count): string { if ( tail_len > |s| ) diff --git a/policy/utils/thresholds.bro b/policy/utils/thresholds.bro index 6bf90f307e..14bcc3b50b 100644 --- a/policy/utils/thresholds.bro +++ b/policy/utils/thresholds.bro @@ -22,8 +22,12 @@ export { 30, 100, 1000, 10000, 100000, 1000000, 10000000, } &redef; - ## This will check if a :bro:type:`TrackCount` variable has crossed the - ## thresholds given in the first value. + ## This will check if a :bro:type:`TrackCount` variable has crossed any + ## thresholds in a given set. + ## v: a vector holding counts that represent thresholds + ## tracker: the record being used to track event counter and currently + ## monitored threshold value + ## Returns: T if a threshold has been crossed, else F global check_threshold: function(v: vector of count, tracker: TrackCount): bool; ## This will use the :bro:id:`default_notice_thresholds` variable to check diff --git a/testing/btest/Baseline/policy.utils.pattern/output b/testing/btest/Baseline/policy.utils.pattern/output new file mode 100644 index 0000000000..9400dc37ec --- /dev/null +++ b/testing/btest/Baseline/policy.utils.pattern/output @@ -0,0 +1,6 @@ +/^?((blarg|blah|bleh))$?/ +T +/^?(foo(blarg|blah|bleh)bar)$?/ +T +[matched=T, str=blah, off=4] +[matched=F, str=, off=0] diff --git a/testing/btest/Baseline/policy.utils.strings/output b/testing/btest/Baseline/policy.utils.strings/output new file mode 100644 index 0000000000..4f5f06eca1 --- /dev/null +++ b/testing/btest/Baseline/policy.utils.strings/output @@ -0,0 +1,13 @@ +'hello' is NOT considered binary +'\xff\xff\xff\0' IS considered binary +'\0\0\xff\0' IS considered binary +'\0\0\0\0' is NOT considered binary +two, one, three +one +hell\o w\orl\d +\\hello world\\ +hello world +hello worl +hello + + diff --git a/testing/btest/Baseline/policy.utils.thresholds/output b/testing/btest/Baseline/policy.utils.thresholds/output new file mode 100644 index 0000000000..0fa85cc81b --- /dev/null +++ b/testing/btest/Baseline/policy.utils.thresholds/output @@ -0,0 +1,45 @@ +Iteration: 0, threshold check: F +[n=0, index=0] +Iteration: 1, threshold check: F +[n=1, index=0] +Iteration: 2, threshold check: T +[n=2, index=1] +Iteration: 3, threshold check: F +[n=3, index=1] +Iteration: 4, threshold check: T +[n=4, index=2] +Iteration: 5, threshold check: F +[n=5, index=2] +Iteration: 6, threshold check: T +[n=6, index=3] +Iteration: 7, threshold check: F +[n=7, index=3] +Iteration: 8, threshold check: T +[n=8, index=4] +Iteration: 9, threshold check: F +[n=9, index=4] +Iteration: 10, threshold check: T +[n=10, index=5] +==================================== +Iteration: 0, threshold check: F +[n=0, index=0] +Iteration: 1, threshold check: F +[n=1, index=0] +Iteration: 2, threshold check: T +[n=2, index=1] +Iteration: 3, threshold check: F +[n=3, index=1] +Iteration: 4, threshold check: T +[n=4, index=2] +Iteration: 5, threshold check: F +[n=5, index=2] +Iteration: 6, threshold check: T +[n=6, index=3] +Iteration: 7, threshold check: F +[n=7, index=3] +Iteration: 8, threshold check: T +[n=8, index=4] +Iteration: 9, threshold check: F +[n=9, index=4] +Iteration: 10, threshold check: T +[n=10, index=5] diff --git a/testing/btest/policy/utils/pattern.test b/testing/btest/policy/utils/pattern.test new file mode 100644 index 0000000000..c16015a85b --- /dev/null +++ b/testing/btest/policy/utils/pattern.test @@ -0,0 +1,16 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +@load utils/pattern + +global r1 = set_to_regex(set("blah", "bleh", "blarg"), "(~~)"); +global r2 = set_to_regex(set("blah", "bleh", "blarg"), "foo(~~)bar"); + +print r1; +print "blah" == r1; + +print r2; +print "fooblargbar" == r2; + +print match_pattern("123blah123", r1); +print match_pattern("no match here", r1); diff --git a/testing/btest/policy/utils/strings.test b/testing/btest/policy/utils/strings.test new file mode 100644 index 0000000000..16de71d5ad --- /dev/null +++ b/testing/btest/policy/utils/strings.test @@ -0,0 +1,29 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +@load utils/strings + +function test_binary_string(s: string) + { + if ( is_string_binary(s) ) + print fmt("'%s' IS considered binary", s); + else + print fmt("'%s' is NOT considered binary", s); + } + +test_binary_string("\x68\x65\x6C\x6C\x6F"); +test_binary_string("\xFF\xFF\xFF\x00"); +test_binary_string("\x00\x00\xFF\x00"); +test_binary_string("\x00\x00\x00\x00"); + +print join_string_set(set("one", "two", "three"), ", "); +print join_string_set(set("one"), ", "); + +print string_escape("hello world", "od"); +print string_escape("\\hello world\\", ""); + +print cut_tail("hello world", 0); +print cut_tail("hello world", 1); +print cut_tail("hello world", 6); +print cut_tail("hello world", 11); +print cut_tail("hello world", 12); diff --git a/testing/btest/policy/utils/thresholds.test b/testing/btest/policy/utils/thresholds.test new file mode 100644 index 0000000000..0439841e41 --- /dev/null +++ b/testing/btest/policy/utils/thresholds.test @@ -0,0 +1,28 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +@load utils/thresholds + +redef default_notice_thresholds = { 2, 4, 6, 8, 10 }; +const my_thresholds: vector of count = { 2, 4, 6, 8, 10 }; +const loop_v: vector of count = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; +global track_count: TrackCount; + +for ( i in loop_v ) + { + print fmt("Iteration: %s, threshold check: %s", i, + check_threshold(my_thresholds, track_count)); + print track_count; + ++track_count$n; + } + +track_count$n = 0; track_count$index = 0; + +print "===================================="; +for ( i in loop_v ) + { + print fmt("Iteration: %s, threshold check: %s", i, + default_check_threshold(track_count)); + print track_count; + ++track_count$n; + }