I am writing two zeek plugins for two consecutive protocol layers. The lower layer is implemented using spicy. The upper one using C++ (for reasons). The spicy parser now passes the data to the C++ plugin using zeek::protocol_data_in.
Unfortunately, the last parser needs to know the status of the upper protocol layer (a single integer). So how can I best get a byte from the Spicy parser to the C++ parser?
My idea was to do this via the connection object. But I can’t find a way to access the connection object from spicy (or the Zeek functions that can be provided to spicy). Only the ID of the connection seems to be available.
At the moment I have implemented it so that the status byte is prepended to the payload before it is passed on. This works well, but is pretty hacky.
There are a couple of ways you could do this:
- Raise an event from your Spicy parser (e.g., passing
connection
and your data) and handle it in your C++ plugin. The C++ code probably needs to handle events from not just the connection it is currently looking at, but also from later ones.
- Pass the data in band like you currently do. This has the downside that the C++ plugin does not “speak” exactly the protocol it is supposed to parse, but is probably the simplest approach to orchestrate.
- Have both Spicy and C++ code operate on some shared data in Zeek script. From Spicy code you can access values via functions like
zeek::get_value
(you probably want to use typed variants like e.g., zeek::get_table
though).
To add a fourth option - you can, in theory, get access to the connection object in spicy by defining a c++ function.
This is, for example, done by the Spicy TLS implementation.
The function that accesses the connection object is here: zeek/src/analyzer/protocol/ssl/spicy/support.cc at master · zeek/zeek · GitHub
You need to declare it in your spicy file like this: zeek/src/analyzer/protocol/ssl/spicy/SSL.spicy at master · zeek/zeek · GitHub
Wow, there are quick answers here!
The first option seems to me to be the cleanest. However, the event would have to be intercepted in the C++ code before DeliverPacket is called by zeek::protocol_data_in, so that I have the information available in DeliverPacket. I assumed that the events system works the other way around. So that I only get the event with the status information when it is already too late. If I’m wrong, then I’ll probably implement it that way.
Nevertheless, I still have a question about the third solution. The variables that I read using zeek::get_value are global. So I would create a table that maps the connection ID to my status byte. I would then give it an “expiration date” so that it would be removed again in any case.
Correct?
Thanks a lot for the help!
I’ve just realized that there’s a fourth option. Adding more functions to spicy could also be useful for me at another point. I will have a look at the linked code tomorrow.