This unit supports parsing of command line args, detection rules, IP addresses,
and config files. New Lua-based features are elsewhere.

==== Rules

A state machine parser expects a rule in the following format:

    Action Proto Source Dir Destination ( Options )

Where 'Action' is an IPS Action, 'Source/Destination' is a source or destination
IP address and port if any, 'Dir' is a marker for uni-directional or bi-directional
rule, 'Options' is a list of IPS options including matchers and meta-data.
Some of the tokens can be omitted, taking a default value.

The left part of the rule (before the opening parenthesis) is a header, which is
represented by RuleTreeNode structure internally, the RTN.

The right part of the rule (in the parentheses) is a rule body, which is just
a list of IPS options, delimited by a semi-colon. Internally this part is
represented by OptTreeNode structure, the OTN.
During parsing the options, the right IPS Option module is selected. It will
parse the option and its parameters and create an instance.

RTN is a per-policy data. Within a given policy all RTNs which have the
same action and 5-tuple (protocol, addresses, ports values after expanding
variables) will be collapsed into a single RTN. When strict reduction is enabled,
port variables with the same values will also be collapsed into single RTNs.
This reduces the memory and computation efforts to evaluate RTN.
Hence, RTN has a counter for OTNs referencing it.
RTNs populate policies when the rule states are applied.

OTN is a global data. It is uniquely identified by gid:sid pair.
So, a text rule, a rule state or stub can reference the same rule:

    ips.rules = [[ reject http ( gid:1; sid:1; ) ]]
    ips.states = [[ alert ( gid:1; sid:1; ) ]]

In the example above the state will affect the current policy, while the rule
will be loaded and become available in all policies (with inherited or
overridden state).
OTN has a pointer to the right RTN for each policy.

After all the rules are read and parsed, Detection module will create rule
groups and options trees to evaluate rules faster.

==== IP and Port Variables

IP or Port value (either a scalar or a list) can be represented by a user variable.
Each IPS policy has a table which maps variable name to a specific value.

    ips.variables.nets.HOME_NET = 192.168.0.0/24
    ips.variables.ports.STATIC_NAT_PORT = '8080, 40000:'

RTN gets expanded values when the rule state is applied.

==== Action Variables

An IPS policy can define action variables for configured react pages:

    ips =
    {
        variables =
        {
            actions =
            {
                BLOCK_PAGE_1 = { react = { page = "block_page_1.html" } },
                BLOCK_PAGE_2 = { react = { page = "block_page_2.html" } },
            }
        }
    }

Rules use the variable name as the rule action:

    $BLOCK_PAGE_1 http ( sid:1; )
    $BLOCK_PAGE_2 http ( sid:2; )

Rule states can also use the action variable, which is the common path for
built-in or externally supplied rules:

    ips.states =
    [[
        $BLOCK_PAGE_1 ( gid:119; sid:19; enable:yes; )
        $BLOCK_PAGE_2 ( gid:119; sid:20; enable:yes; )
    ]]

During rule parsing, an action token beginning with '$' is resolved against the
current IPS policy action variable table. The RTN stores both the underlying
action type, such as react, and an action selector. The action selector is part
of RTN comparison and hashing so rules with the same header but different
configured react pages do not share the same RTN.

ips.action_override is applied before this lookup. Therefore an override value
such as "$BLOCK_PAGE_1" is resolved through the same action variable path as a
rule action token.

Action selectors are policy-local indexes into an IPS policy's configured
action instances. RuleState therefore keeps the original "$NAME" action token
when a state uses an action variable. When detection.global_rule_state applies
that state to another IPS policy, the variable name is resolved again against
the target policy before the RTN is installed. This lets policies use the same
variable name for different react pages and avoids copying a selector from one
policy into another.

If a global rule state references an action variable that is missing from a
target IPS policy, configuration fails with an unknown IPS action variable
error for that policy.

Action variables currently support configured react.page instances only. They
are not general action aliases, and the parser does not support these forms:

    actions =
    {
        MISCONFIGURED_ALERT = "alert",
        MISCONFIGURED_REACT = "react",
    }
