In some cases, a thread module (like Decode, Detect, etc) has the need to create an extra packet. This packet is internal to the engine only. The easiest example is dealing with tunnel packets. In Suricata, when we encounter a ip6-in-ip4 packet for example, we process the embedded ip6 packet separately in the engine. It remains connected to the original, so that IPS mode can drop it. To enable this creation of extra packets, the api needs to support it. Each thread module is given 2 queues to put new packets in. The "pre" and "post" queues. The difference is only timing: when will the new fake packet be processed by the engine.
/* queue filled by the SlotFunc with packets that will * be processed futher _before_ the current packet. * The locks in the queue are NOT used */ PacketQueue slot_pre_pq;
These are processed right after the thread module finishes. So in case of the ip6-in-ip4 we have:
thread module starts:
- gets raw ipv4 packet
- runs Decode
=> decode creates fake ip6 pkt, places it into "pre"
- Decode completes
- pre queue packets are processed*
- original packet is processed further*
*) processing here means passing it on to the next module directly, or passing it to a queue to the next thread.
This makes sure that the ipv6 packet is processed before the original (and real) ipv4 packet.
/* queue filled by the SlotFunc with packets that will * be processed futher _after_ the current packet. The * locks in the queue are NOT used */ PacketQueue slot_post_pq;
Likewise, the packets in post_pq are processed after the original completed.
Note that completion here refers to the thread processing the packet. In some runmodes multiple threads process a packet sequentially.
As far as I can see now, the post_pq is really only used to inject fake packets in from the flow manager. The flow manager times out flows and injects fake packets to trigger final stream reassembly, detection and logging.
Packet Handler Threads¶