mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00

This allows to read Zeek global variables from inside Spicy code. The main challenge here is supporting all of Zeek's data type in a type-safe manner. The most straight-forward API is a set of functions `get_<type>(<id>)`, where `<type>` is the Zeek-side type name (e.g., `count`, `string`, `bool`) and `<id>` is the fully scoped name of the Zeek-side global (e.g., `MyModule::Boolean`). These functions then return the corresponding Zeek value, converted in an appropriate Spicy type. Example: Zeek: module Foo; const x: count = 42; const y: string = "xxx"; Spicy: import zeek; assert zeek::get_count("Foo::x") == 42; assert zeek::get_string("Foo::y") == b"xxx"; # returns bytes(!) For container types, the `get_*` function returns an opaque types that can be used to access the containers' values. An additional set of functions `as_<type>` allows converting opaque values of atomic types to Spicy equivalents. Example: Zeek: module Foo; const s: set[count] = { 1, 2 }; const t: table[count] of string = { [1] = "One", [2] = "Two" } Spicy: # Check set membership. local set_ = zeek::get_set("Foo::s"); assert zeek::set_contains(set_, 1) == True # Look up table element. local table_ = zeek::get_table("Foo::t"); local value = zeek::table_lookup(t, 1); assert zeek::as_string(value) == b"One" There are also functions for accessing elements of Zeek-side vectors and records. If any of these `zeek::*` conversion functions fails (e.g., due to a global of that name not existing), it will throw an exception. Design considerations: - We support only reading Zeek variables, not writing. This is both to simplify the API, and also conceptually to avoid offering backdoors into Zeek state that could end up with a very tight coupling of Spicy and Zeek code. - We accept that a single access might be relatively slow due to name lookup and data conversion. This is primarily meant for configuration-style data, not for transferring lots of dynamic state over. - In that spirit, we don't support deep-copying complex data types from Zeek over to Spicy. This is (1) to avoid performance problems when accidentally copying large containers over, potentially even at every access; and (2) to avoid the two sides getting out of sync if one ends up modifying a container without the other being able to see it.
99 lines
3.8 KiB
Text
99 lines
3.8 KiB
Text
# @TEST-REQUIRES: have-spicy
|
|
#
|
|
# @TEST-EXEC: spicyz -d -o test.hlto %INPUT
|
|
# @TEST-EXEC: zeek globals.zeek test.hlto Spicy::enable_print=T >output
|
|
# @TEST-EXEC: btest-diff output
|
|
#
|
|
# @TEST-DOC: Test access to Zeek-side globals.
|
|
|
|
module Foo;
|
|
|
|
import zeek;
|
|
|
|
assert zeek::get_address("Bar::address_") == 1.2.3.4;
|
|
assert zeek::get_bool("Bar::bool_") == True;
|
|
assert zeek::get_count("Bar::count_") == 42;
|
|
assert zeek::get_double("Bar::double_") == 42.0;
|
|
assert zeek::get_enum("Bar::enum_") == "Foo";
|
|
assert zeek::get_int("Bar::int_") == 42;
|
|
assert zeek::get_interval("Bar::interval_") == interval(42);
|
|
assert zeek::get_port("Bar::port_") == 42/tcp;
|
|
assert zeek::get_string("Bar::string_") == b"xxx";
|
|
assert zeek::get_subnet("Bar::subnet_") == 1.2.3.4/16;
|
|
assert zeek::get_time("Bar::time_") == time(42.0);
|
|
|
|
assert zeek::as_address(zeek::get_value("Bar::address_")) == 1.2.3.4;
|
|
assert zeek::as_bool(zeek::get_value("Bar::bool_")) == True;
|
|
assert zeek::as_count(zeek::get_value("Bar::count_")) == 42;
|
|
assert zeek::as_double(zeek::get_value("Bar::double_")) == 42.0;
|
|
assert zeek::as_enum(zeek::get_value("Bar::enum_")) == "Foo";
|
|
assert zeek::as_int(zeek::get_value("Bar::int_")) == 42;
|
|
assert zeek::as_interval(zeek::get_value("Bar::interval_")) == interval(42);
|
|
assert zeek::as_port(zeek::get_value("Bar::port_")) == 42/tcp;
|
|
assert zeek::as_string(zeek::get_value("Bar::string_")) == b"xxx";
|
|
assert zeek::as_subnet(zeek::get_value("Bar::subnet_")) == 1.2.3.4/16;
|
|
assert zeek::as_time(zeek::get_value("Bar::time_")) == time(42.0);
|
|
|
|
assert zeek::as_string(zeek::record_field("Bar::record_", "x")) == b"foo";
|
|
assert zeek::as_int(zeek::record_field("Bar::record_", "y")) == 42;
|
|
assert zeek::as_int(zeek::record_field(zeek::get_record("Bar::record_"), "y")) == 42;
|
|
assert zeek::record_has_value("Bar::record_", "x");
|
|
assert zeek::record_has_value(zeek::get_record("Bar::record_"), "y");
|
|
assert zeek::record_has_value("Bar::record_", "y");
|
|
assert ! zeek::record_has_value("Bar::record_", "z");
|
|
assert zeek::record_has_field("Bar::record_", "x");
|
|
assert ! zeek::record_has_field("Bar::record_", "z");
|
|
assert-exception zeek::record_field("Bar::record_", "z"); # not set
|
|
|
|
assert zeek::set_contains("Bar::set_", "foo");
|
|
assert ! zeek::set_contains("Bar::set_", "xxx");
|
|
assert zeek::set_contains(zeek::get_set("Bar::set_"), "foo");
|
|
|
|
assert zeek::table_contains("Bar::table_", "foo");
|
|
assert ! zeek::table_contains("Bar::table_", "xxx");
|
|
assert zeek::table_contains(zeek::get_table("Bar::table_"), "foo");
|
|
assert zeek::as_string(*zeek::table_lookup("Bar::table_", "foo")) == b"bar";
|
|
assert zeek::as_string(*zeek::table_lookup(zeek::get_table("Bar::table_"), "foo")) == b"bar";
|
|
assert ! zeek::table_lookup("Bar::table_", "does-not-exist");
|
|
|
|
assert zeek::as_count(zeek::vector_index("Bar::vector_", 2)) == 2;
|
|
assert zeek::as_count(zeek::vector_index(zeek::get_vector("Bar::vector_"), 2)) == 2;
|
|
|
|
assert-exception zeek::get_bool("Bar::does_not_exist");
|
|
assert-exception zeek::get_bool("Bar::string_");
|
|
|
|
# Test stringifcation.
|
|
print zeek::get_value("Bar::bool_");
|
|
print zeek::get_record("Bar::record_");
|
|
print zeek::get_set("Bar::set_");
|
|
print zeek::get_table("Bar::table_");
|
|
print zeek::get_vector("Bar::vector_");
|
|
|
|
# @TEST-START-FILE globals.zeek
|
|
module Bar;
|
|
|
|
type Record: record {
|
|
x: string;
|
|
y: int &default=42;
|
|
z: bool &optional;
|
|
};
|
|
|
|
type Enum: enum { Foo, Bar };
|
|
|
|
const address_: addr = 1.2.3.4;
|
|
const bool_: bool = T;
|
|
const count_: count = 42;
|
|
const double_: double = 42.0;
|
|
const enum_: Enum = Foo;
|
|
const int_: int = 42;
|
|
const interval_: interval = 42sec;
|
|
const port_: port = 42/tcp;
|
|
const record_: Record = [$x="foo"];
|
|
const set_: set[string] = set("foo", "bar");
|
|
const string_: string = "xxx";
|
|
const subnet_: subnet = 1.2.3.4/16;
|
|
const table_: table[string] of string = table(["foo"] = "bar");
|
|
const time_: time = double_to_time(42.0);
|
|
const vector_: vector of count = vector(0, 1, 2);
|
|
|
|
# @TEST-END-FILE
|