static void FrameDebug(const char *prefix, const Frames *frames, const Frame *frame)
{
#ifdef DEBUG
- const char *type_name =
- frames ? AppLayerParserGetFrameNameById(frames->ipproto, frames->alproto, frame->type)
- : "<unknown>";
+ const char *type_name = "unknown";
+ if (frame->type == FRAME_STREAM_TYPE) {
+ type_name = "stream";
+ } else if (frames != NULL) {
+ type_name = AppLayerParserGetFrameNameById(frames->ipproto, frames->alproto, frame->type);
+ }
SCLogDebug("[%s] %p: frame: %p type %u/%s id %" PRIi64 " flags %02x rel_offset:%" PRIi64
", len:%" PRIi64 ", events:%u %u/%u/%u/%u",
prefix, frames, frame, frame->type, type_name, frame->id, frame->flags,
Frame *FrameGetById(Frames *frames, const int64_t id)
{
+ SCLogDebug("frames %p cnt %u, looking for %" PRIi64, frames, frames->cnt, id);
for (uint16_t i = 0; i < frames->cnt; i++) {
if (i < FRAMES_STATIC_CNT) {
Frame *frame = &frames->sframes[i];
+ FrameDebug("get_by_id(static)", frames, frame);
if (frame->id == id)
return frame;
} else {
const uint16_t o = i - FRAMES_STATIC_CNT;
Frame *frame = &frames->dframes[o];
+ FrameDebug("get_by_id(dynamic)", frames, frame);
if (frame->id == id)
return frame;
}
const uint64_t frame_start_rel = frame_start - STREAM_BASE_OFFSET(stream);
#ifdef DEBUG
- SCLogDebug("flow %p direction %s frame offset %" PRIu64 " (abs %" PRIu64
+ SCLogDebug("flow %p direction %s frame type %u offset %" PRIu64 " (abs %" PRIu64
") starting at %" PRIu64 " len %" PRIi64 " (offset %" PRIu64 ")",
- f, dir == 0 ? "toserver" : "toclient", frame_start_rel, frame_start, frame_start, len,
- stream_slice->offset);
+ f, dir == 0 ? "toserver" : "toclient", frame_type, frame_start_rel, frame_start,
+ frame_start, len, stream_slice->offset);
#endif
Frame *r = FrameNew(frames, (uint32_t)frame_start_rel, len);
if (r != NULL) {
Frame *AppLayerFrameGetById(Flow *f, const int dir, const FrameId frame_id)
{
FramesContainer *frames_container = AppLayerFramesGetContainer(f);
+ SCLogDebug("get frame_id %" PRIi64 " direction %u/%s frames_container %p", frame_id, dir,
+ dir == 0 ? "toserver" : "toclient", frames_container);
if (frames_container == NULL)
return NULL;
} else {
frames = &frames_container->toclient;
}
+ SCLogDebug("frames %p", frames);
return FrameGetById(frames, frame_id);
}
#include "rust.h"
+#define FRAME_STREAM_TYPE 255
+/** always the first frame to be created. TODO but what about protocol upgrades? */
+#define FRAME_STREAM_ID 1
+
typedef int64_t FrameId;
enum {
}
}
+/** \internal
+ * \brief create/close stream frames
+ * On first invocation of TCP parser in a direction, create a <alproto>.stream frame.
+ * On STREAM_EOF, set the final length. */
+static void HandleStreamFrames(Flow *f, StreamSlice stream_slice, const uint8_t *input,
+ const uint32_t input_len, const uint8_t flags)
+{
+ const uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1;
+ AppLayerParserState *pstate = f->alparser;
+
+ /* setup the generic stream frame */
+ if (((direction == 0 && (pstate->flags & APP_LAYER_PARSER_SFRAME_TS) == 0) ||
+ (direction == 1 && (pstate->flags & APP_LAYER_PARSER_SFRAME_TC) == 0)) &&
+ input != NULL && f->proto == IPPROTO_TCP) {
+ Frame *frame = AppLayerFrameGetById(f, direction, FRAME_STREAM_ID);
+ if (frame == NULL) {
+ int64_t frame_len = -1;
+ if (flags & STREAM_EOF)
+ frame_len = input_len;
+
+ frame = AppLayerFrameNewByAbsoluteOffset(
+ f, &stream_slice, stream_slice.offset, frame_len, direction, FRAME_STREAM_TYPE);
+ if (frame) {
+ SCLogDebug("opened: frame %p id %" PRIi64, frame, frame->id);
+ frame->flags = FRAME_FLAG_ENDS_AT_EOF; // TODO logic is not yet implemented
+ DEBUG_VALIDATE_BUG_ON(
+ frame->id != 1); // should always be the first frame that is created
+ }
+ if (direction == 0) {
+ pstate->flags |= APP_LAYER_PARSER_SFRAME_TS;
+ } else {
+ pstate->flags |= APP_LAYER_PARSER_SFRAME_TC;
+ }
+ }
+ } else if (flags & STREAM_EOF) {
+ Frame *frame = AppLayerFrameGetById(f, direction, FRAME_STREAM_ID);
+ SCLogDebug("EOF closing: frame %p", frame);
+ if (frame) {
+ /* calculate final frame length */
+ const TcpSession *ssn = f->protoctx;
+ const TcpStream *stream = (direction == 0) ? &ssn->client : &ssn->server;
+ int64_t slice_o =
+ (int64_t)stream_slice.offset - (int64_t)stream->sb.region.stream_offset;
+ int64_t frame_len = slice_o + ((int64_t)-1 * frame->rel_offset) + (int64_t)input_len;
+ SCLogDebug("%s: EOF frame->rel_offset %" PRIi64 " -> %" PRIi64 ": o %" PRIi64,
+ AppProtoToString(f->alproto), frame->rel_offset, frame_len, slice_o);
+ frame->len = frame_len;
+ }
+ }
+}
+
static void Setup(Flow *f, const uint8_t direction, const uint8_t *input, uint32_t input_len,
const uint8_t flags, StreamSlice *as)
{
if (input_len > 0 || (flags & STREAM_EOF)) {
Setup(f, flags & (STREAM_TOSERVER | STREAM_TOCLIENT), input, input_len, flags,
&stream_slice);
+ HandleStreamFrames(f, stream_slice, input, input_len, flags);
+
#ifdef DEBUG
if (((stream_slice.flags & STREAM_TOSERVER) &&
stream_slice.offset >= g_eps_applayer_error_offset_ts)) {
#define APP_LAYER_PARSER_EOF_TC BIT_U16(6)
#define APP_LAYER_PARSER_TRUNC_TS BIT_U16(7)
#define APP_LAYER_PARSER_TRUNC_TC BIT_U16(8)
+#define APP_LAYER_PARSER_SFRAME_TS BIT_U16(9)
+#define APP_LAYER_PARSER_SFRAME_TC BIT_U16(10)
/* Flags for AppLayerParserProtoCtx. */
#define APP_LAYER_PARSER_OPT_ACCEPT_GAPS BIT_U32(0)
#include "decode.h"
#include "detect.h"
+#include "app-layer-frames.h"
#include "app-layer-parser.h"
#include "detect-parse.h"
const char *frame_str = is_short ? str : val;
int raw_frame_type = -1;
- if (is_tcp)
- raw_frame_type = AppLayerParserGetFrameIdByName(IPPROTO_TCP, keyword_alproto, frame_str);
+ if (is_tcp) {
+ if (strcmp(frame_str, "stream") == 0) {
+ raw_frame_type = FRAME_STREAM_TYPE;
+ } else {
+ raw_frame_type =
+ AppLayerParserGetFrameIdByName(IPPROTO_TCP, keyword_alproto, frame_str);
+ }
+ }
if (is_udp && raw_frame_type < 0)
raw_frame_type = AppLayerParserGetFrameIdByName(IPPROTO_UDP, keyword_alproto, frame_str);
if (raw_frame_type < 0) {
SCLogError("unknown frame '%s' for protocol '%s'", frame_str, proto);
return -1;
}
- BUG_ON(raw_frame_type >= UINT8_MAX);
+ BUG_ON(raw_frame_type > UINT8_MAX);
if (is_short) {
snprintf(buffer_name, sizeof(buffer_name), "%s.%s", AppProtoToString(s->alproto), str);