diff --git a/auxil/spicy b/auxil/spicy index f4ff0d0f83..937ca6794f 160000 --- a/auxil/spicy +++ b/auxil/spicy @@ -1 +1 @@ -Subproject commit f4ff0d0f83d736d7c7f2e31d89337b166102ee78 +Subproject commit 937ca6794fe9b0f4434ba727aefd581df8b3977d diff --git a/doc b/doc index 0dad81c85f..9f734f8a7a 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 0dad81c85fdc1140290af555c8cd400f5560059d +Subproject commit 9f734f8a7ab6f919eab7b3972c0542210d97dcd0 diff --git a/src/spicy/runtime-support.h b/src/spicy/runtime-support.h index d84d4258a5..3d943cbb8a 100644 --- a/src/spicy/runtime-support.h +++ b/src/spicy/runtime-support.h @@ -21,6 +21,7 @@ #include #include +#include "Val.h" #include "zeek/Desc.h" #include "zeek/spicy/cookie.h" #include "zeek/spicy/manager.h" @@ -929,6 +930,19 @@ inline ValPtr to_val(const T& t, TypePtr target) { return rval; } +/** Maps HILTI's `Protocol` enum to Zeek's `transport_proto` enum. */ +inline ValPtr to_val_for_transport_proto(int64_t val, const TypePtr& target) { + switch ( val ) { + case hilti::rt::Protocol::TCP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_TCP); + case hilti::rt::Protocol::UDP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_UDP); + case hilti::rt::Protocol::ICMP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_ICMP); + case hilti::rt::Protocol::Undef: [[fallthrough]]; // just for readability, make Undef explicit + default: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_UNKNOWN); + } + + hilti::rt::cannot_be_reached(); +} + /** * Converts a Spicy-side enum to a Zeek record value. The result is returned * with ref count +1. @@ -960,6 +974,14 @@ inline ValPtr to_val(const T& t, TypePtr target) { static_assert(std::is_signed>{}); auto it = static_cast(t); + // Special case: map enum values to Zeek's semantics. + if ( target->GetName() == "transport_proto" ) { + if ( ! std::is_same_v ) + throw TypeMismatch(hilti::rt::demangle(typeid(t).name()), target); + + return to_val_for_transport_proto(it, target); + } + // Zeek's enum can't be negative, so we swap in max_int for our Undef (-1). if ( it == std::numeric_limits::max() ) // can't allow this ... diff --git a/testing/btest/Baseline/spicy.export-protocol-enum/output b/testing/btest/Baseline/spicy.export-protocol-enum/output new file mode 100644 index 0000000000..949ebb220b --- /dev/null +++ b/testing/btest/Baseline/spicy.export-protocol-enum/output @@ -0,0 +1,9 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +icmp, 3 +icmp, 3 +tcp, 1 +tcp, 1 +udp, 2 +udp, 2 +unknown_transport, 0 +unknown_transport, 0 diff --git a/testing/btest/spicy/export-protocol-enum.zeek b/testing/btest/spicy/export-protocol-enum.zeek new file mode 100644 index 0000000000..a021dccbd5 --- /dev/null +++ b/testing/btest/spicy/export-protocol-enum.zeek @@ -0,0 +1,52 @@ +# @TEST-REQUIRES: have-spicy +# +# @TEST-EXEC: spicyz -d -o test.hlto dtest.spicy ./dtest.evt +# @TEST-EXEC: zeek -r ${TRACES}/ssh/single-conn.trace test.hlto %INPUT | sort >output +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Test special-casing the mapping of spicy::Protocol to Zeek's transport_proto. + +event dtest_one(x: transport_proto) { + print x, enum_to_int(x); +} + +event zeek_init() { + Analyzer::register_for_port(Analyzer::ANALYZER_SPICY_DTEST, 22/tcp); +} + +# @TEST-START-FILE dtest.evt + +import spicy; + +protocol analyzer spicy::dtest over TCP: + parse originator with dtest::Message; + +on dtest::Message -> event dtest_one(spicy::Protocol::TCP); +on dtest::Message -> event dtest_one(spicy::Protocol::UDP); +on dtest::Message -> event dtest_one(spicy::Protocol::ICMP); +on dtest::Message -> event dtest_one(spicy::Protocol::Undef); +on dtest::Message -> event dtest_one(self.p_tcp); +on dtest::Message -> event dtest_one(self.p_udp); +on dtest::Message -> event dtest_one(self.p_icmp); +on dtest::Message -> event dtest_one(self.p_undef); + +export spicy::Protocol; + +# @TEST-END-FILE +# @TEST-START-FILE dtest.spicy + +module dtest; + +import spicy; + +public type Message = unit { + sswitch: uint8; + result: uint8; + + var p_tcp: spicy::Protocol = spicy::Protocol::TCP; + var p_udp: spicy::Protocol = spicy::Protocol::UDP; + var p_icmp: spicy::Protocol = spicy::Protocol::ICMP; + var p_undef: spicy::Protocol = cast(42); +}; + +# @TEST-END-FILE