@node Statements and Expressions @chapter Statements and Expressions You express Bro's analysis of network traffic using @emph{event handlers}, which, as discussed in XX, are essentially subroutines written in Bro's policy scripting language. In this chapter we discuss the different types of statements and expressions available for expressing event handlers and the auxiliary functions they use. @menu * Statements:: * Expressions:: @end menu @node Statements, @section Statements @cindex statements Bro functions and event handlers are written in an imperative style, and the statements available for doing so are similar to those provided in C. @cindex statements, semi-colon termination @cindex semi-colon statement termination @cindex statements, multi-line @cindex whitespace, in statements As in C, statements are terminated with a semi-colon. There are no restrictions on how many lines a statement can span. Whitespace can appear between any of the syntactic components in a statement, and its presence always serves as a separator (that is, a single syntactic component cannot in general contain embedded whitespace, unless it is escaped in some form, such as appearing inside a string literal). Bro provides the following types of statements: @command{expression} @cindex expression @quotation Syntax: @quotation @emph{expr} ; @end quotation As in C, an expression by itself can also be used as a statement. For example, assignments, calling functions, and scheduling timers are all expressions; they also are often used as statements. @end quotation @command{print} @cindex print statement @quotation Syntax: @quotation print @emph{file} @emph{expr-list} ; @end quotation The expressions are converted to a list of strings, which are then printed as a comma-separated list. If the first expression is of type , then the other expressions are printed to the corresponding file; otherwise they're written to @cindex stdout @emph{stdout}. For control over how the strings are formatted, see the @code{fmt} function. @end quotation @command{alarm} @cindex alarm statement @quotation Syntax: @quotation alarm @emph{expr-list} ; @end quotation The expressions are converted to a list of strings, which are then logged as a comma-separated list. ``Logging'' means recording the values to @file{bro-alarm-file}. In addition, if Bro is reading @cindex live traffic @cindex traffic, live vs. recorded @emph{live} network traffic (as opposed to from a trace file), then the messages are also reported via @cindex syslog @emph{syslog(3)} at level @emph{LOG_NOTICE}. If the message does not already include a timestamp, one is added. See the @code{alarm} module for a discussion of controlling logging behavior from your policy script. In particular, an important feature of the @code{alarm} statement is that prior to logging the giving string(s), Bro first invokes @command{alarm-hook} to determine whether to suppress the logging. @end quotation @command{event} @cindex event statement @quotation Syntax: @quotation event @emph{expr} ( @emph{expr-list*} ) ; @end quotation Evaluates @emph{expr} to obtain an event handler and queues an event for it with the value corresponding to the optional comma-separated list of values given by @emph{expr-list}. @emph{Note:} @code{event} statements look syntactically just like function calls, other than the keyword ``@code{event}''. However, @command{function-call-expr}, while queueing an event is not, since it does not return a value. @end quotation @command{if} @cindex if statement @quotation Syntax: @quotation if ( @emph{expr} ) @emph{stmt} @* if ( @emph{expr} ) @emph{stmt} else @emph{stmt2} @end quotation Evaluates @emph{expr}, which must yield a @command{bool} value. If true, executes @emph{stmt}. For the second form, if false, executes @emph{stmt2}. @end quotation @command{for} @cindex for statement @quotation Syntax: @quotation for ( @emph{var} in @emph{expr} ) @emph{stmt} @end quotation Iterates over the indices of @emph{expr}, which must evaluate to either a @code{set} or a @code{table}. For each iteration, @emph{var} is set to one of the indices and @emph{stmt} is executed. @emph{var} needn't have been previously declared (in which case its type is implicitly inferred from that of the indices of @emph{expr}), and must not be a global variable. If @emph{expr} is a @code{set}, then the indices correspond to the members of the set. If @emph{expr} is a @code{table}, then they correspond to the indices of the table. @emph{Deficiency: You can only use @code{for} statements to iterate over sets and tables with a single, non-compound index type. You can't iterate over multi-dimensional or compound indices. } @emph{Deficiency: Bro lacks ways of controlling the order in which it iterates over the indices. } @end quotation @command{next} @cindex next statement @quotation Syntax: @quotation next ; @end quotation Only valid within a @code{for} statement. When executed, causes the loop to proceed to the next iteration value (i.e., the next index value). @end quotation @command{break} @cindex break statement @quotation Syntax: @quotation break ; @end quotation Only valid within a @code{for} statement. When executed, causes the loop to immediately exit. @end quotation @command{return} @cindex return statement @quotation Syntax: @quotation return @emph{expr} ; @end quotation Immediately exits the current function or event handler. For a function, returns the value @emph{expr} (which is omitted if the function does not return a value, or for event handlers). @end quotation @command{add} @cindex add statement @quotation Syntax: @quotation add @emph{expr1} @emph{expr2} ; @end quotation Adds the element specified by @emph{expr2} to the set given by @emph{expr1}. For example, @example global active_hosts: set[addr, port]; ... add active_hosts[1.44.33.7, 80/tcp]; @end example adds an element corresponding to the pair 1.44.33.7 and 80/tcp to the set active_hosts. @end quotation @command{delete} @cindex delete statement @quotation Syntax: @quotation delete @emph{expr1} [@emph{expr2}] ; @end quotation Deletes the corresponding value, where @emph{expr1} corresponds to a set or table, and @emph{expr2} an element/index of the set/table. If the element is not in the set/table, does nothing. @end quotation @command{compound} @cindex compound statement @quotation Compound statements are formed from a list of (zero or more) statements enclosed in @code{@{@}}'s: @quotation @{ @emph{statement*} @} @end quotation @end quotation @command{null} @cindex null statement @quotation A lone: @quotation ; @end quotation denotes an empty, do-nothing statement. @end quotation @cindex variables, local @cindex local variables @cindex variables, constant @cindex constant variables @command{local,const} @cindex local @quotation Syntax: @quotation local @emph{var} : @emph{type} = @emph{initialization} @emph{attributes} ; @* const @emph{var} : @emph{type} = @emph{initialization} @emph{attributes} ; @end quotation Declares a local variable with the given type, initialization, and attributes, all of which are optional. The syntax of these fields is the same as for @command{global-vars}. The second form likewise declares a local variable, but one which is @emph{constant}: trying to assign a new value to it results in an error. @emph{Deficiency:Currently, this @code{const} restriction isn't detected/enforced. } @cindex variables, scope @emph{Unlike with C} the scope of a local variable is from the point of declaration to the end of the encompassing function or event handler. @end quotation @cindex statements @node Expressions, @section Expressions @cindex expressions|( Expressions in Bro are very similar to those in C, with similar precedence: @cindex left parenthesis operator( operator @cindex operator, left parenthesis( parenthesis @cindex right parenthesis operator) operator @cindex operator, right parenthesis) parenthesis @cindex parentheses operators() @command{parenthesized} @quotation Syntax: @quotation ( @emph{expr} ) @end quotation Parentheses are used as usual to override precedence. @end quotation @command{constant} @cindex constant @quotation Any constant value is an expression. @end quotation @command{variable} @cindex variable @quotation The name of a @emph{variable} is an expression. @end quotation @command{clone} @cindex clone operator @quotation Syntax: @quotation copy( @emph{expr} ) @end quotation Produces a clone, or deep copy, of the value produced by the expression it is applied to. @end quotation @command{increment,decrement} @cindex increment @cindex decrement @quotation Syntax: @quotation ++ @emph{expr} @* -- @emph{expr} @end quotation Increments or decrements the given expression, which must correspond to an assignable value (variable, table element, or record element) and of a number type. Yields the value of the expression after the increment. @emph{Unlike with C, these operators only are defined for ``pre''-increment/decrement; there is no post-increment/decrement.} @end quotation @command{negation} @cindex negation @quotation Syntax: @quotation ! @emph{expr} @* - @emph{expr} @end quotation Yields the boolean or arithmetic negation for values of boolean or @emph{numeric} (or @emph{interval}) types, respectively. @end quotation @command{positivation} @quotation Syntax: @quotation + @emph{expr} @end quotation Yields the value of @emph{expr}, which must be of type @emph{numeric} or @emph{interval}. The point of this operator is to explicitly convert a value of type count to int. For example, suppose you want to declare a local variable code to be of type int, but initialized to the value 2. If you used: @example local code = 2; @end example then Bro's implicit typing would make it of type count, because that's the type of a @command{numeric-constants}. You could instead use: @example local code = +2; @end example to direct the type inferencing to instead assign a type of int to code. Or, of course, you could specify the type explicitly: @example local code:int = 2; @end example @end quotation @command{arithmetic} @quotation Syntax: @quotation @emph{expr1} + @emph{expr2} @* @emph{expr1} - @emph{expr2} @* @emph{expr1} * @emph{expr2} @* @emph{expr1} / @emph{expr2} @* @emph{expr1} % @emph{expr2} @end quotation The usual C arithmetic operators, defined for numeric types, except modulus (@code{%}) is only defined for integral types. @end quotation @cindex & short-circuit&&@ short-circuit ``and'' @cindex short-circuit1-circuit && ``and'' operator @cindex and operator&& ``and'' operator @cindex operator, and&& ``and'' @cindex & or short-circuit"|"|@ short-circuit ``or'' @cindex short-circuit2-circuit "|"| ``or'' operator @cindex or operator"|"| ``or'' operator @cindex operator, or"|"| ``or'' @command{logical} @quotation Syntax: @quotation @emph{expr1} @code{&&} @emph{expr2} @* @emph{expr1} @code{||} @emph{expr2} @end quotation The usual C logical operators, defined for boolean types. @end quotation @cindex == equality operator==@ equality operator @cindex == inequality operator", =@ inequality operator @command{equality} @quotation Syntax: @quotation @emph{expr1} @code{==} @emph{expr2} \ @emph{expr1} @code{"!=} @emph{expr2} @end quotation @command{rel-operators}, Compares two values for equality or inequality, yielding a @code{bool} value. Defined for all non-compound types except pattern. @end quotation @cindex == less-than operator<@ @ less-than operator @cindex == less-than-or-equal operator<=@ less-or-equal operator @cindex == z operator>@ @ greater-than operator @cindex == zz operator>=@ greater-or-equal operator @command{relational} @quotation Syntax: @quotation @emph{expr1} @code{<} @emph{expr2} \ @emph{expr1} @code{<=} @emph{expr2} \ @emph{expr1} @code{>} @emph{expr2} \ @emph{expr1} @code{>=} @emph{expr2} @end quotation Compares two values for magnitude ordering, yielding a bool value. Defined for values of type @emph{numeric}, time, interval, port, or addr. @emph{Note:} TCP port values are considered less than UDP port values. @emph{Note:} IPv4 addr values less than IPv6 addr values. @emph{Deficiency: Should also be defined at for @command{string} values. } @end quotation @command{conditional} @quotation Syntax: @quotation @emph{expr1} ? @emph{expr2} : @emph{expr3} @end quotation Evaluates @emph{expr1} and, if true, evaluates and yields @emph{expr2}, otherwise evaluates and yields @emph{expr3}. @emph{expr2} and @emph{expr3} must have compatible types. @end quotation @command{assignment} @quotation Syntax: @quotation @emph{expr1} = @emph{expr2} @end quotation Assigns the value of @emph{expr2} to the storage defined by @emph{expr1}, which must be an assignable value (variable, table element, or record element). Yields the assigned value. @end quotation @cindex left parenthesis operator( operator @cindex operator, left parenthesis( parenthesis @cindex right parenthesis operator) operator @cindex operator, right parenthesis) parenthesis @cindex parentheses operators() @cindex invocation, function @cindex function invocation @command{function call} @quotation Syntax: @quotation @emph{expr1} ( @emph{expr-list2} ) @end quotation Evaluates @emph{expr1} to obtain a value of type @code{function}, which is then invoked with its arguments bound left-to-right to the values obtained from the comma-separated list of expressions @emph{expr-list2}. Each element of @emph{expr-list2} must be assignment-compatible with the corresponding formal argument in the type of @emph{expr1}. The list may (and must) be empty if the function does not take any parameters. @end quotation @cindex functions, anonymous @command{anonymous function} @quotation Syntax: @quotation function ( @emph{parameters} ) @emph{body} @end quotation Defines an @emph{anonymous function}, which, in abstract terms, is how you specify a constant of type @code{function}. @emph{parameters} has the syntax of parameter declarations for @command{functions}, as does @emph{body}, which is just a list of statements enclosed in braces. Anonymous functions can be used anywhere you'd usually instead use a function declared in the usual direct fashion. For example, consider the function: @example function demo(msg: string): bool @{ if ( msg == "do the demo" ) @{ print "got it"; return T; @} else return F; @} @end example You could instead declare demo as a global variable of type @code{function}: @example global demo: function(msg: string): bool; @end example and then later assign to it an anonymous function: @example demo = function (msg: string): bool @{ if ( msg == "do the demo" ) @{ print "got it"; return T; @} else return F; @}; @end example You can even call the anonymous function directly: @example (function (msg: string): bool @{ if ( msg == "do the demo" ) @{ print "got it"; return T; @} else return F; @})("do the demo") @end example though to do so you need to enclose the function in parentheses to avoid confusing Bro's parser. One particularly handy form of anonymous function is that used for @command{&default}. @end quotation @cindex timers @cindex events, scheduling @cindex scheduling events @command{event scheduling} @quotation Syntax: @quotation schedule @emph{expr1} @code{@{} @emph{expr2} ( @emph{expr-list3} ) @code{@}} @end quotation Evaluates @emph{expr1} to obtain a value of type @command{interval}, and schedules the event given by @emph{expr2} with parameters @emph{expr-list3} for that time. Note that the expressions are all evaluated and bound at the time of execution of the schedule expression; evaluation is @emph{not} deferred until the future execution of the event handler. For example, we could define the following event handler: @example event once_in_a_blue_moon(moon_phase: interval) @{ print fmt("wow, a blue moon - phase %s", moon_phase); @} @end example and then we could schedule delivery of the event for 6 hours from the present, with a moon_phase of 12 days, using: @example schedule +6 hr @{ once_in_a_blue_moon(12 days) @}; @end example @emph{Note: The syntax is admittedly a bit clunky. In particular, it's easy to @emph{(i)} forget to include the braces (which are needed to avoid confusing Bro's parser), @emph{(ii)} forget the final semi-colon if the schedule expression is being used as an expression-statement, or @emph{(iii)} erroneously place a semi-colon after the event specification but before the closing brace.} @cindex timer expiration @cindex expiration, timer Timer invocation is inexact. In general, Bro uses arriving packets to serve as its clock (when reading a trace file off-line, this is still the case---the timestamp of the latest packet read from the trace is used as the notion of ``now''). Once this clock reaches or passes the time associated with a queued event, Bro will invoke the event handler, which is termed ``expiring'' the timer. (However, Bro will only invoke @command{max-timer-expires} timers per packet, and these include its own internal timers for managing connection state, so this can also delay invocation.) It will also expire all pending timers (whose time has not yet arrived) when Bro terminates; if you don't want those event handlers to activate in this instance, you need to test @command{done-with-network}. You would think that @code{schedule} should just be a statement like @command{event-invocation} is, rather than an expression. But it actually does return a value, of the undocumented type timer. @cindex possible future changes, type In the future, Bro may provide mechanisms for manipulating such timers; for example, to cancel them if you no longer want them to expire. @end quotation @command{index} @quotation Syntax: @quotation @emph{expr1} [ @emph{expr-list2} ] @end quotation Returns the sub-value of @emph{expr1} indexed by the value of @emph{expr-list2}, which must be compatible with the index type of @emph{expr1}. @emph{expr-list2} is a comma-separated list of expressions (with at least one expression listed) whose values are matched left-to-right against the index types of @emph{expr1}. The only type of value that can be indexed in this fashion is a table. @emph{Note:} set's cannot be indexed because they do not yield any value. Use @code{in} to test for set membership. @end quotation @command{membership} @quotation Syntax: @quotation @emph{expr1} in @emph{expr2} @* @emph{expr1} !in @emph{expr2} @end quotation Yields true (false, respectively) if the index @emph{expr1} is present in the @code{table} or @code{set} @emph{expr2}. For example, if notice_level is a table index by an address and yielding a count: @example global notice_level: table[addr] of count; @end example then we could test whether the address 127.0.0.1 is present using: @example 127.0.0.1 in notice_level @end example For table's and set's indexed by multiple dimensions, you enclose @emph{expr1} in brackets. For example, if we have: @example global connection_seen: set[addr, addr]; @end example then we could test for the presence of the element indexed by 8.1.14.2 and 129.186.0.77 using: @example [8.1.14.2, 129.186.0.77] in connection_seen @end example We can also instead use a corresponding record type. If we had @example local t = [$x = 8.1.14.2, $y = 129.186.0.77] @end example then we could test: @example t in connection_seen @end example @end quotation @cindex == equality operator==@ equality operator @cindex == inequality operator", =@ inequality operator @command{pattern matching} @quotation Syntax: @quotation @emph{expr1} == @emph{expr2} @* @emph{expr1} "!= @emph{expr2} @* @emph{expr1} in @emph{expr2} @* @emph{expr1} "!in @emph{expr2} @end quotation As discussed for @command{pattern values}. the first two forms yield true (false) if the @code{pattern} @emph{expr1} exactly matches the string @emph{expr2}. (You can also list the @code{string} value on the left-hand side of the operator and the @code{pattern} on the right.) The second two forms yield true (false) if the pattern @emph{expr1} is present within the string @emph{expr2}. (For these, you @emph{must} list the pattern as the left-hand operand.) @end quotation @cindex $$@ record field access operator @command{record field access} @quotation Syntax: @quotation @emph{expr} $ @emph{field-name} @end quotation Returns the given field @emph{field-name} of the record @emph{expr}. If the record does not contain the given field, a compile-time error results. @end quotation @cindex $$@ record constructor operator @command{record constructor} @quotation Syntax: @quotation [ @emph{field-constructor-list} ] @end quotation Constructs a @code{record} value. The @emph{field-constructor-list} is a comma-separated list of individual field constructors, which have the syntax: @quotation $ @emph{field-name} = @emph{expr} @end quotation For example, @example [$foo = 3, $bar = 23/tcp] @end example yields a @code{record} with two fields, @code{foo} of type @code{count} and @code{bar} of type @code{port}. The values used in the constructor needn't be constants, however; they can be any expression of an assignable type. @end quotation @cindex ?$?$@ record field test @command{record field test} @quotation Syntax: @quotation @emph{expr} @code{?$} @emph{field-name} @end quotation Returns true if the given field has been set in the record yielded by @emph{expr}. Note that @emph{field-name} @emph{must} correspond to one of the fields in the record type of @emph{expr} (otherwise, the expression would always be false). The point of this operator is to test whether an @emph{&optional} field of a record has been assigned to. For example, suppose we have: @example type rap_sheet: record @{ num_scans: count &optional; first_activity: time; @}; global the_goods: table[addr] of rap_sheet; @end example and we want to test whether the address held in the variable perp exists in the_goods and, if so, whether num_scans has been assigned to, then we could use: @example perp in the_goods && the_goods[perp]?$num_scans @end example @end quotation @cindex expressions