suricata
app-layer-frames.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2024 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 
27 #include "flow.h"
28 #include "stream-tcp.h"
29 #include "rust.h"
30 #include "app-layer-frames.h"
31 #include "app-layer-parser.h"
32 #include "util-debug.h"
33 #include "util-validate.h"
34 
35 struct FrameConfig {
36  SC_ATOMIC_DECLARE(uint64_t, types);
37 };
38 /* This array should be allocated to contain g_alproto_max protocols. */
39 static struct FrameConfig *frame_config;
40 
41 void FrameConfigInit(void)
42 {
43  frame_config = SCCalloc(g_alproto_max, sizeof(struct FrameConfig));
44  if (unlikely(frame_config == NULL)) {
45  FatalError("Unable to alloc frame_config.");
46  }
47  for (AppProto p = 0; p < g_alproto_max; p++) {
48  SC_ATOMIC_INIT(frame_config[p].types);
49  }
50 }
51 
53 {
54  SCFree(frame_config);
55 }
56 
58 {
59  const uint64_t bits = UINT64_MAX;
60  for (AppProto p = 0; p < g_alproto_max; p++) {
61  struct FrameConfig *fc = &frame_config[p];
62  SC_ATOMIC_OR(fc->types, bits);
63  }
64 }
65 
66 void FrameConfigEnable(const AppProto p, const uint8_t type)
67 {
68  const uint64_t bits = BIT_U64(type);
69  struct FrameConfig *fc = &frame_config[p];
70  SC_ATOMIC_OR(fc->types, bits);
71 }
72 
73 static inline bool FrameConfigTypeIsEnabled(const AppProto p, const uint8_t type)
74 {
75  struct FrameConfig *fc = &frame_config[p];
76  const uint64_t bits = BIT_U64(type);
77  const bool enabled = (SC_ATOMIC_GET(fc->types) & bits) != 0;
78  return enabled;
79 }
80 
81 #ifdef DEBUG
82 static void FrameDebug(const char *prefix, const Frames *frames, const Frame *frame)
83 {
84  const char *type_name = "unknown";
85  if (frame->type == FRAME_STREAM_TYPE) {
86  type_name = "stream";
87  } else if (frames != NULL) {
88  type_name = AppLayerParserGetFrameNameById(frames->ipproto, frames->alproto, frame->type);
89  }
90  SCLogDebug("[%s] %p: frame:%p type:%u/%s id:%" PRIi64 " flags:%02x offset:%" PRIu64
91  ", len:%" PRIi64 ", inspect_progress:%" PRIu64 ", events:%u %u/%u/%u/%u",
92  prefix, frames, frame, frame->type, type_name, frame->id, frame->flags, frame->offset,
93  frame->len, frame->inspect_progress, frame->event_cnt, frame->events[0],
94  frame->events[1], frame->events[2], frame->events[3]);
95 }
96 #else
97 #define FrameDebug(prefix, frames, frame)
98 #endif
99 
100 /**
101  * \note "open" means a frame that has no length set (len == -1)
102  * \todo perhaps we can search backwards */
103 Frame *FrameGetLastOpenByType(Frames *frames, const uint8_t frame_type)
104 {
105  Frame *candidate = NULL;
106 
107  SCLogDebug(
108  "frames %p cnt %u, looking for last of type %" PRIu8, frames, frames->cnt, frame_type);
109  for (uint16_t i = 0; i < frames->cnt; i++) {
110  if (i < FRAMES_STATIC_CNT) {
111  Frame *frame = &frames->sframes[i];
112  FrameDebug("get_by_id(static)", frames, frame);
113  if (frame->type == frame_type && frame->len == -1)
114  candidate = frame;
115  } else {
116  const uint16_t o = i - FRAMES_STATIC_CNT;
117  Frame *frame = &frames->dframes[o];
118  FrameDebug("get_by_id(dynamic)", frames, frame);
119  if (frame->type == frame_type && frame->len == -1)
120  candidate = frame;
121  }
122  }
123  return candidate;
124 }
125 
126 Frame *FrameGetById(Frames *frames, const int64_t id)
127 {
128  SCLogDebug("frames %p cnt %u, looking for %" PRIi64, frames, frames->cnt, id);
129  for (uint16_t i = 0; i < frames->cnt; i++) {
130  if (i < FRAMES_STATIC_CNT) {
131  Frame *frame = &frames->sframes[i];
132  FrameDebug("get_by_id(static)", frames, frame);
133  if (frame->id == id)
134  return frame;
135  } else {
136  const uint16_t o = i - FRAMES_STATIC_CNT;
137  Frame *frame = &frames->dframes[o];
138  FrameDebug("get_by_id(dynamic)", frames, frame);
139  if (frame->id == id)
140  return frame;
141  }
142  }
143  return NULL;
144 }
145 
146 Frame *FrameGetByIndex(Frames *frames, const uint32_t idx)
147 {
148  if (idx >= frames->cnt)
149  return NULL;
150 
151  if (idx < FRAMES_STATIC_CNT) {
152  Frame *frame = &frames->sframes[idx];
153  FrameDebug("get_by_idx(s)", frames, frame);
154  return frame;
155  } else {
156  const uint32_t o = idx - FRAMES_STATIC_CNT;
157  Frame *frame = &frames->dframes[o];
158  FrameDebug("get_by_idx(d)", frames, frame);
159  return frame;
160  }
161 }
162 
163 static Frame *FrameNew(Frames *frames, uint64_t offset, int64_t len)
164 {
165  DEBUG_VALIDATE_BUG_ON(frames == NULL);
166 
167  if (frames->cnt < FRAMES_STATIC_CNT) {
168  Frame *frame = &frames->sframes[frames->cnt];
169  frames->sframes[frames->cnt].offset = offset;
170  frames->sframes[frames->cnt].len = len;
171  frames->sframes[frames->cnt].id = ++frames->base_id;
172  frames->cnt++;
173  return frame;
174  } else if (frames->dframes == NULL) {
175  DEBUG_VALIDATE_BUG_ON(frames->dyn_size != 0);
177 
178  frames->dframes = SCCalloc(8, sizeof(Frame));
179  if (frames->dframes == NULL) {
180  return NULL;
181  }
182  frames->cnt++;
184 
185  frames->dyn_size = 8;
186  frames->dframes[0].offset = offset;
187  frames->dframes[0].len = len;
188  frames->dframes[0].id = ++frames->base_id;
189  return &frames->dframes[0];
190  } else {
192 
193  /* need to handle dynamic storage of frames now */
194  const uint16_t dyn_cnt = frames->cnt - FRAMES_STATIC_CNT;
195  if (dyn_cnt < frames->dyn_size) {
196  DEBUG_VALIDATE_BUG_ON(frames->dframes == NULL);
197 
198  // fall through
199  } else {
200  if (frames->dyn_size == 256) {
201  SCLogDebug("limit reached! 256 dynamic frames already");
202  // limit reached
203  // TODO figure out if this should lead to an event of sorts
204  return NULL;
205  }
206 
207  /* realloc time */
208  uint16_t new_dyn_size = frames->dyn_size * 2;
209  uint32_t new_alloc_size = new_dyn_size * sizeof(Frame);
210 
211  void *ptr = SCRealloc(frames->dframes, new_alloc_size);
212  if (ptr == NULL) {
213  return NULL;
214  }
215 
216  memset((uint8_t *)ptr + (frames->dyn_size * sizeof(Frame)), 0x00,
217  (frames->dyn_size * sizeof(Frame)));
218  frames->dframes = ptr;
219  frames->dyn_size = new_dyn_size;
220  }
221 
222  frames->cnt++;
223  frames->dframes[dyn_cnt].offset = offset;
224  frames->dframes[dyn_cnt].len = len;
225  frames->dframes[dyn_cnt].id = ++frames->base_id;
226  return &frames->dframes[dyn_cnt];
227  }
228 }
229 
230 static void FrameClean(Frame *frame)
231 {
232  memset(frame, 0, sizeof(*frame));
233 }
234 
235 static void FrameCopy(Frame *dst, Frame *src)
236 {
238  memcpy(dst, src, sizeof(*dst));
239 }
240 
241 #ifdef DEBUG
242 static void AppLayerFrameDumpForFrames(const char *prefix, const Frames *frames)
243 {
244  SCLogDebug("prefix: %s", prefix);
245  for (uint16_t i = 0; i < frames->cnt; i++) {
246  if (i < FRAMES_STATIC_CNT) {
247  const Frame *frame = &frames->sframes[i];
248  FrameDebug(prefix, frames, frame);
249  } else {
250  const uint16_t o = i - FRAMES_STATIC_CNT;
251  const Frame *frame = &frames->dframes[o];
252  FrameDebug(prefix, frames, frame);
253  }
254  }
255  SCLogDebug("prefix: %s", prefix);
256 }
257 #endif
258 
259 static inline uint64_t FrameLeftEdge(const TcpStream *stream, const Frame *frame)
260 {
261  const int64_t app_progress = STREAM_APP_PROGRESS(stream);
262 
263  const int64_t frame_offset = frame->offset;
264  const int64_t frame_data = app_progress - frame_offset;
265 
266  SCLogDebug("frame_offset %" PRIi64 ", frame_data %" PRIi64 ", frame->len %" PRIi64,
267  frame_offset, frame_data, frame->len);
268  DEBUG_VALIDATE_BUG_ON(frame_offset > app_progress);
269 
270  /* length unknown, make sure to have at least 2500 */
271  if (frame->len < 0) {
272  if (frame_data <= 2500) {
273  SCLogDebug("got <= 2500 bytes (%" PRIu64 "), returning offset %" PRIu64, frame_data,
274  frame_offset);
275  return frame_offset;
276  } else {
277  SCLogDebug("got > 2500 bytes (%" PRIu64 "), returning offset %" PRIu64, frame_data,
278  (frame_offset + (frame_data - 2500)));
279  return frame_offset + (frame_data - 2500);
280  }
281 
282  /* length specified */
283  } else {
284  /* have all data for the frame, we can skip it */
285  if (frame->len <= frame_data) {
286  uint64_t x = frame_offset + frame_data;
287  SCLogDebug("x %" PRIu64, x);
288  return x;
289  /*
290 
291  [ stream <frame_data> ]
292  [ frame .......]
293 
294  */
295  } else if (frame_data < 2500) {
296  uint64_t x = frame_offset;
297  SCLogDebug("x %" PRIu64, x);
298  return x;
299  } else {
300  uint64_t x = frame_offset + (frame_data - 2500);
301  SCLogDebug("x %" PRIu64, x);
302  return x;
303  }
304  }
305 }
306 
307 /** Stream buffer slides forward, we need to update and age out
308  * frame offsets/frames. Aging out means we move existing frames
309  * into the slots we'd free up.
310  *
311  * Start:
312  *
313  * [ stream ]
314  * [ frame ...........]
315  * offset: 2
316  * len: 19
317  *
318  * Slide:
319  * [ stream ]
320  * [ frame .... .]
321  * offset: 2
322  * len: 19
323  *
324  * Slide:
325  * [ stream ]
326  * [ frame ........... ]
327  * offset: 2
328  * len: 19
329  */
330 static int FrameSlide(const char *ds, Frames *frames, const TcpStream *stream, const uint32_t slide)
331 {
332  SCLogDebug("start: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
333  ", next %" PRIu64,
334  (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
335  STREAM_BASE_OFFSET(stream), STREAM_BASE_OFFSET(stream) + slide);
336  DEBUG_VALIDATE_BUG_ON(frames == NULL);
337  SCLogDebug("%s frames %p: sliding %u bytes", ds, frames, slide);
338  uint64_t le = STREAM_APP_PROGRESS(stream);
339  const uint64_t next_base = STREAM_BASE_OFFSET(stream) + slide;
340 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
341  const uint16_t start = frames->cnt;
342  uint16_t removed = 0;
343 #endif
344  uint16_t x = 0;
345  for (uint16_t i = 0; i < frames->cnt; i++) {
346  if (i < FRAMES_STATIC_CNT) {
347  Frame *frame = &frames->sframes[i];
348  FrameDebug("slide(s)", frames, frame);
349  if (frame->len >= 0 && frame->offset + frame->len <= next_base) {
350  // remove by not incrementing 'x'
351  SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
352  FrameClean(frame);
353 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
354  removed++;
355 #endif
356  } else {
357  Frame *nframe = &frames->sframes[x];
358  if (frame != nframe) {
359  FrameCopy(nframe, frame);
360  FrameClean(frame);
361  }
362  le = MIN(le, FrameLeftEdge(stream, nframe));
363  x++;
364  }
365  } else {
366  const uint16_t o = i - FRAMES_STATIC_CNT;
367  Frame *frame = &frames->dframes[o];
368  FrameDebug("slide(d)", frames, frame);
369  if (frame->len >= 0 && frame->offset + frame->len <= next_base) {
370  // remove by not incrementing 'x'
371  SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
372  FrameClean(frame);
373 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
374  removed++;
375 #endif
376  } else {
377  Frame *nframe;
378  if (x >= FRAMES_STATIC_CNT) {
379  nframe = &frames->dframes[x - FRAMES_STATIC_CNT];
380  } else {
381  nframe = &frames->sframes[x];
382  }
383  if (frame != nframe) {
384  FrameCopy(nframe, frame);
385  FrameClean(frame);
386  }
387  le = MIN(le, FrameLeftEdge(stream, nframe));
388  x++;
389  }
390  }
391  }
392  frames->cnt = x;
393  uint64_t o = STREAM_BASE_OFFSET(stream) + slide;
394  DEBUG_VALIDATE_BUG_ON(o > le);
395  DEBUG_VALIDATE_BUG_ON(le - o > UINT32_MAX);
396  frames->left_edge_rel = (uint32_t)(le - o);
397 
398 #ifdef DEBUG
399  SCLogDebug("end: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
400  " (+slide), cnt %u, removed %u, start %u",
401  (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream) + slide,
402  frames->left_edge_rel, STREAM_BASE_OFFSET(stream) + slide, frames->cnt, removed, start);
403  char pf[32] = "";
404  snprintf(pf, sizeof(pf), "%s:post_slide", ds);
405  AppLayerFrameDumpForFrames(pf, frames);
406 #endif
407  DEBUG_VALIDATE_BUG_ON(x != start - removed);
408  return 0;
409 }
410 
411 void AppLayerFramesSlide(Flow *f, const uint32_t slide, const uint8_t direction)
412 {
413  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
414  if (frames_container == NULL)
415  return;
416  Frames *frames;
417  TcpSession *ssn = f->protoctx;
418  TcpStream *stream;
419  if (direction == STREAM_TOSERVER) {
420  stream = &ssn->client;
421  frames = &frames_container->toserver;
422  FrameSlide("toserver", frames, stream, slide);
423  } else {
424  stream = &ssn->server;
425  frames = &frames_container->toclient;
426  FrameSlide("toclient", frames, stream, slide);
427  }
428 }
429 
430 static void FrameFreeSingleFrame(Frames *frames, Frame *r)
431 {
432  FrameDebug("free", frames, r);
433  FrameClean(r);
434 }
435 
436 static void FramesClear(Frames *frames)
437 {
438  DEBUG_VALIDATE_BUG_ON(frames == NULL);
439 
440  SCLogDebug("frames %u", frames->cnt);
441  for (uint16_t i = 0; i < frames->cnt; i++) {
442  if (i < FRAMES_STATIC_CNT) {
443  Frame *r = &frames->sframes[i];
444  SCLogDebug("removing frame %p", r);
445  FrameFreeSingleFrame(frames, r);
446  } else {
447  const uint16_t o = i - FRAMES_STATIC_CNT;
448  Frame *r = &frames->dframes[o];
449  SCLogDebug("removing frame %p", r);
450  FrameFreeSingleFrame(frames, r);
451  }
452  }
453  frames->cnt = 0;
454 }
455 
456 void FramesFree(Frames *frames)
457 {
458  DEBUG_VALIDATE_BUG_ON(frames == NULL);
459  FramesClear(frames);
460  SCFree(frames->dframes);
461  frames->dframes = NULL;
462 }
463 
464 /** \brief create new frame using a pointer to start of the frame
465  */
467  const uint8_t *frame_start, const int64_t len, int dir, uint8_t frame_type)
468 {
469  SCLogDebug("frame_start:%p stream_slice->input:%p stream_slice->offset:%" PRIu64, frame_start,
470  stream_slice->input, stream_slice->offset);
471 
472  if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
473  return NULL;
474 
475  /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
476 #if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
477  if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
478  return NULL;
479  if (frame_start < stream_slice->input ||
480  frame_start > stream_slice->input + stream_slice->input_len)
481  return NULL;
482 #endif
483  DEBUG_VALIDATE_BUG_ON(frame_start < stream_slice->input);
484  DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
485  DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
486 
487  ptrdiff_t ptr_offset = frame_start - stream_slice->input;
488 #ifdef DEBUG
489  uint64_t offset = ptr_offset + stream_slice->offset;
490  SCLogDebug("flow %p direction %s frame %p starting at %" PRIu64 " len %" PRIi64
491  " (offset %" PRIu64 ")",
492  f, dir == 0 ? "toserver" : "toclient", frame_start, offset, len, stream_slice->offset);
493 #endif
494  DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
495 
496  FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
497  if (frames_container == NULL)
498  return NULL;
499 
500  Frames *frames;
501  if (dir == 0) {
502  frames = &frames_container->toserver;
503  } else {
504  frames = &frames_container->toclient;
505  }
506 
507  uint64_t abs_frame_offset = stream_slice->offset + ptr_offset;
508 
509  Frame *r = FrameNew(frames, abs_frame_offset, len);
510  if (r != NULL) {
511  r->type = frame_type;
512  FrameDebug("new_by_ptr", frames, r);
513  }
514  return r;
515 }
516 
517 static Frame *AppLayerFrameUdp(
518  Flow *f, const uint32_t frame_start_rel, const int64_t len, int dir, uint8_t frame_type)
519 {
520  DEBUG_VALIDATE_BUG_ON(f->proto != IPPROTO_UDP);
521 
522  if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
523  return NULL;
524 
525  FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
526  if (frames_container == NULL)
527  return NULL;
528 
529  Frames *frames;
530  if (dir == 0) {
531  frames = &frames_container->toserver;
532  } else {
533  frames = &frames_container->toclient;
534  }
535 
536  Frame *r = FrameNew(frames, frame_start_rel, len);
537  if (r != NULL) {
538  r->type = frame_type;
539  }
540  return r;
541 }
542 
543 /** \brief create new frame using a relative offset from the start of the stream slice
544  */
545 Frame *SCAppLayerFrameNewByRelativeOffset(Flow *f, const void *ss, const uint32_t frame_start_rel,
546  const int64_t len, int dir, uint8_t frame_type)
547 {
548  // need to hide StreamSlice argument
549  // as we cannot bindgen a C function with an argument whose type
550  // is defined in rust (at least before a suricata_core crate)
551  const StreamSlice *stream_slice = (const StreamSlice *)ss;
552  if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
553  return NULL;
554 
555  /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
556 #if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
557  if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
558  return NULL;
559  if (stream_slice->input == NULL)
560  return NULL;
561 #else
562  DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
563 #endif
564  DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
565  DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
566 
567  if (f->proto == IPPROTO_UDP) {
568  return AppLayerFrameUdp(f, frame_start_rel, len, dir, frame_type);
569  }
570 
571  FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
572  if (frames_container == NULL)
573  return NULL;
574 
575  Frames *frames;
576  if (dir == 0) {
577  frames = &frames_container->toserver;
578  } else {
579  frames = &frames_container->toclient;
580  }
581 
582  const uint64_t frame_abs_offset = (uint64_t)frame_start_rel + stream_slice->offset;
583 #ifdef DEBUG_VALIDATION
584  const TcpSession *ssn = f->protoctx;
585  const TcpStream *stream = dir == 0 ? &ssn->client : &ssn->server;
586  BUG_ON(stream_slice->offset != STREAM_APP_PROGRESS(stream));
587  BUG_ON(frame_abs_offset > STREAM_APP_PROGRESS(stream) + stream_slice->input_len);
588 #endif
589  Frame *r = FrameNew(frames, frame_abs_offset, len);
590  if (r != NULL) {
591  r->type = frame_type;
592  }
593  return r;
594 }
595 
597 {
598 #ifdef DEBUG
599  if (f->proto == IPPROTO_TCP && f->protoctx && f->alparser) {
600  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
601  if (frames_container != NULL) {
602  AppLayerFrameDumpForFrames("toserver::dump", &frames_container->toserver);
603  AppLayerFrameDumpForFrames("toclient::dump", &frames_container->toclient);
604  }
605  }
606 #endif
607 }
608 
609 /** \brief create new frame using the absolute offset from the start of the stream
610  */
612  const uint64_t frame_start, const int64_t len, int dir, uint8_t frame_type)
613 {
614  if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
615  return NULL;
616 
617  /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
618 #if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
619  if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
620  return NULL;
621  if (stream_slice->input == NULL)
622  return NULL;
623 #else
624  DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
625 #endif
626  DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
627  DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
628  DEBUG_VALIDATE_BUG_ON(frame_start < stream_slice->offset);
629  DEBUG_VALIDATE_BUG_ON(frame_start - stream_slice->offset >= (uint64_t)INT_MAX);
630 
631  FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
632  if (frames_container == NULL)
633  return NULL;
634 
635  Frames *frames;
636  if (dir == 0) {
637  frames = &frames_container->toserver;
638  } else {
639  frames = &frames_container->toclient;
640  }
641 
642  SCLogDebug("flow %p direction %s frame type %u offset %" PRIu64 " len %" PRIi64
643  " (slice offset %" PRIu64 ")",
644  f, dir == 0 ? "toserver" : "toclient", frame_type, frame_start, len,
645  stream_slice->offset);
646  Frame *r = FrameNew(frames, frame_start, len);
647  if (r != NULL) {
648  r->type = frame_type;
649  }
650  return r;
651 }
652 
653 void AppLayerFrameAddEvent(Frame *r, uint8_t e)
654 {
655  if (r != NULL) {
656  if (r->event_cnt < 4) { // TODO
657  r->events[r->event_cnt++] = e;
658  }
659  FrameDebug("add_event", NULL, r);
660  }
661 }
662 
663 void SCAppLayerFrameAddEventById(const Flow *f, const int dir, const FrameId id, uint8_t e)
664 {
665  Frame *frame = AppLayerFrameGetById(f, dir, id);
666  AppLayerFrameAddEvent(frame, e);
667 }
668 
669 void AppLayerFrameSetLength(Frame *frame, int64_t len)
670 {
671  if (frame != NULL) {
672  frame->len = len;
673  FrameDebug("set_length", NULL, frame);
674  }
675 }
676 
677 void SCAppLayerFrameSetLengthById(const Flow *f, const int dir, const FrameId id, int64_t len)
678 {
679  Frame *frame = AppLayerFrameGetById(f, dir, id);
680  AppLayerFrameSetLength(frame, len);
681 }
682 
683 void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
684 {
685  if (r != NULL) {
687  r->tx_id = tx_id;
688  FrameDebug("set_txid", NULL, r);
689  }
690 }
691 
692 void SCAppLayerFrameSetTxIdById(const Flow *f, const int dir, const FrameId id, uint64_t tx_id)
693 {
694  Frame *frame = AppLayerFrameGetById(f, dir, id);
695  AppLayerFrameSetTxId(frame, tx_id);
696 }
697 
698 Frame *AppLayerFrameGetById(const Flow *f, const int dir, const FrameId frame_id)
699 {
700  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
701  SCLogDebug("get frame_id %" PRIi64 " direction %u/%s frames_container %p", frame_id, dir,
702  dir == 0 ? "toserver" : "toclient", frames_container);
703  if (frames_container == NULL)
704  return NULL;
705 
706  Frames *frames;
707  if (dir == 0) {
708  frames = &frames_container->toserver;
709  } else {
710  frames = &frames_container->toclient;
711  }
712  SCLogDebug("frames %p", frames);
713  return FrameGetById(frames, frame_id);
714 }
715 
716 Frame *AppLayerFrameGetLastOpenByType(Flow *f, const int dir, const uint8_t frame_type)
717 {
718  if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
719  return NULL;
720 
721  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
722  SCLogDebug("get frame_type %" PRIu8 " direction %u/%s frames_container %p", frame_type, dir,
723  dir == 0 ? "toserver" : "toclient", frames_container);
724  if (frames_container == NULL)
725  return NULL;
726 
727  Frames *frames;
728  if (dir == 0) {
729  frames = &frames_container->toserver;
730  } else {
731  frames = &frames_container->toclient;
732  }
733  SCLogDebug("frames %p", frames);
734  return FrameGetLastOpenByType(frames, frame_type);
735 }
736 
737 static inline bool FrameIsDone(const Frame *frame, const uint64_t abs_right_edge)
738 {
739  /* frame with negative length means we don't know the size yet. */
740  if (frame->len < 0)
741  return false;
742 
743  const int64_t frame_abs_offset = frame->offset;
744  const int64_t frame_right_edge = frame_abs_offset + frame->len;
745  if ((uint64_t)frame_right_edge <= abs_right_edge) {
746  SCLogDebug("frame %p id %" PRIi64 " is done", frame, frame->id);
747  return true;
748  }
749  return false;
750 }
751 
752 static void FramePrune(Frames *frames, const TcpStream *stream, const bool eof)
753 {
754 #ifdef DEBUG_VALIDATION
755  const uint64_t frames_le_start = (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream);
756 #endif
757  SCLogDebug("start: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64,
758  (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
759  STREAM_BASE_OFFSET(stream));
760  const uint64_t acked = StreamTcpGetUsable(stream, eof);
761  uint64_t le = STREAM_APP_PROGRESS(stream);
762 
763 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
764  const uint16_t start = frames->cnt;
765  uint16_t removed = 0;
766 #endif
767  uint16_t x = 0;
768  for (uint16_t i = 0; i < frames->cnt; i++) {
769  if (i < FRAMES_STATIC_CNT) {
770  Frame *frame = &frames->sframes[i];
771  FrameDebug("prune(s)", frames, frame);
772  if (eof || FrameIsDone(frame, acked)) {
773  // remove by not incrementing 'x'
774  SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
775  FrameDebug("remove(s)", frames, frame);
776  FrameClean(frame);
777 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
778  removed++;
779 #endif
780  } else {
781  const uint64_t fle = FrameLeftEdge(stream, frame);
782  le = MIN(le, fle);
783  SCLogDebug("le %" PRIu64 ", frame fle %" PRIu64, le, fle);
784  Frame *nframe = &frames->sframes[x];
785  if (frame != nframe) {
786  FrameCopy(nframe, frame);
787  FrameClean(frame);
788  }
789  x++;
790  }
791  } else {
792  const uint16_t o = i - FRAMES_STATIC_CNT;
793  Frame *frame = &frames->dframes[o];
794  FrameDebug("prune(d)", frames, frame);
795  if (eof || FrameIsDone(frame, acked)) {
796  // remove by not incrementing 'x'
797  SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
798  FrameDebug("remove(d)", frames, frame);
799  FrameClean(frame);
800 #if defined(DEBUG) || defined(DEBUG_VALIDATION)
801  removed++;
802 #endif
803  } else {
804  const uint64_t fle = FrameLeftEdge(stream, frame);
805  le = MIN(le, fle);
806  SCLogDebug("le %" PRIu64 ", frame fle %" PRIu64, le, fle);
807  Frame *nframe;
808  if (x >= FRAMES_STATIC_CNT) {
809  nframe = &frames->dframes[x - FRAMES_STATIC_CNT];
810  } else {
811  nframe = &frames->sframes[x];
812  }
813  if (frame != nframe) {
814  FrameCopy(nframe, frame);
815  FrameClean(frame);
816  }
817  x++;
818  }
819  }
820  }
821  frames->cnt = x;
823  DEBUG_VALIDATE_BUG_ON(le - STREAM_BASE_OFFSET(stream) > UINT32_MAX);
824  frames->left_edge_rel = (uint32_t)(le - STREAM_BASE_OFFSET(stream));
825 #ifdef DEBUG
826  SCLogDebug("end: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
827  ", cnt %u, removed %u, start %u",
828  (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
829  STREAM_BASE_OFFSET(stream), frames->cnt, removed, start);
830  AppLayerFrameDumpForFrames("post_slide", frames);
831 #endif
832  if (frames->cnt > 0) { // if we removed all this can fail
833  DEBUG_VALIDATE_BUG_ON(frames_le_start > le);
834  }
835  DEBUG_VALIDATE_BUG_ON(x != start - removed);
836 }
837 
839 {
840  if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
841  return;
842  FramesContainer *frames_container = AppLayerFramesGetContainer(f);
843  if (frames_container == NULL)
844  return;
845 
846  Frames *frames;
847 
848  if (p->proto == IPPROTO_UDP) {
849  SCLogDebug("clearing all UDP frames");
850  if (PKT_IS_TOSERVER(p)) {
851  frames = &frames_container->toserver;
852  } else {
853  frames = &frames_container->toclient;
854  }
855  FramesClear(frames);
856  return;
857  }
858 
859  TcpSession *ssn = f->protoctx;
860 
862  (p->flags & PKT_PSEUDO_DETECTLOG_FLUSH) == 0) {
864  return;
865  }
866 
867  TcpStream *stream;
868  if (PKT_IS_TOSERVER(p)) {
869  stream = &ssn->client;
870  frames = &frames_container->toserver;
871  } else {
872  stream = &ssn->server;
873  frames = &frames_container->toclient;
874  }
875 
876  const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
877  SCLogDebug("eof %s", eof ? "TRUE" : "false");
878  FramePrune(frames, stream, eof);
879 }
StreamSlice
Definition: app-layer-parser.h:126
Packet_::proto
uint8_t proto
Definition: decode.h:538
TcpStream_
Definition: stream-tcp-private.h:106
Frame::inspect_progress
uint64_t inspect_progress
Definition: app-layer-frames.h:59
len
uint8_t len
Definition: app-layer-dnp3.h:2
SCAppLayerFrameAddEventById
void SCAppLayerFrameAddEventById(const Flow *f, const int dir, const FrameId id, uint8_t e)
Definition: app-layer-frames.c:663
Frame::tx_id
uint64_t tx_id
Definition: app-layer-frames.h:58
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
FrameConfig::SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, types)
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
FramesFree
void FramesFree(Frames *frames)
Definition: app-layer-frames.c:456
AppLayerFrameAddEvent
void AppLayerFrameAddEvent(Frame *r, uint8_t e)
Definition: app-layer-frames.c:653
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1364
stream-tcp.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
AppLayerFramesGetContainer
FramesContainer * AppLayerFramesGetContainer(const Flow *f)
Definition: app-layer-parser.c:209
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
Frame::events
uint8_t events[4]
Definition: app-layer-frames.h:54
Flow_::proto
uint8_t proto
Definition: flow.h:381
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:87
FramesContainer::toserver
Frames toserver
Definition: app-layer-frames.h:78
Packet_::flags
uint32_t flags
Definition: decode.h:562
AppLayerFramesSetupContainer
FramesContainer * AppLayerFramesSetupContainer(Flow *f)
Definition: app-layer-parser.c:216
type
uint8_t type
Definition: decode-sctp.h:0
ssn
TcpSession ssn
Definition: fuzz_dataset.c:31
Frame::offset
uint64_t offset
Definition: app-layer-frames.h:55
Frame
Definition: app-layer-frames.h:49
Flow_
Flow data structure.
Definition: flow.h:359
FrameConfig
Definition: app-layer-frames.c:35
SCAppLayerFrameSetLengthById
void SCAppLayerFrameSetLengthById(const Flow *f, const int dir, const FrameId id, int64_t len)
Definition: app-layer-frames.c:677
Frames::cnt
uint16_t cnt
Definition: app-layer-frames.h:65
AppLayerFrameSetTxId
void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
Definition: app-layer-frames.c:683
Frame::id
int64_t id
Definition: app-layer-frames.h:57
FrameGetByIndex
Frame * FrameGetByIndex(Frames *frames, const uint32_t idx)
Definition: app-layer-frames.c:146
rust.h
MIN
#define MIN(x, y)
Definition: suricata-common.h:413
Frames
Definition: app-layer-frames.h:64
FramesContainer
Definition: app-layer-frames.h:77
p
Packet * p
Definition: fuzz_dataset.c:30
Frames::left_edge_rel
uint32_t left_edge_rel
Definition: app-layer-frames.h:67
AppLayerFrameNewByAbsoluteOffset
Frame * AppLayerFrameNewByAbsoluteOffset(Flow *f, const StreamSlice *stream_slice, const uint64_t frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using the absolute offset from the start of the stream
Definition: app-layer-frames.c:611
AppLayerFrameGetLastOpenByType
Frame * AppLayerFrameGetLastOpenByType(Flow *f, const int dir, const uint8_t frame_type)
Definition: app-layer-frames.c:716
Flow_::protoctx
void * protoctx
Definition: flow.h:438
StreamTcpGetUsable
uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof)
Definition: stream-tcp-reassemble.c:423
Frames::dframes
Frame * dframes
Definition: app-layer-frames.h:70
TcpSession_::flags
uint32_t flags
Definition: stream-tcp-private.h:294
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:483
FramesContainer::toclient
Frames toclient
Definition: app-layer-frames.h:79
StreamSlice::input_len
uint32_t input_len
Definition: app-layer-parser.h:128
util-debug.h
StreamSlice::offset
uint64_t offset
Definition: app-layer-parser.h:131
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:239
AppLayerParserGetFrameNameById
const char * AppLayerParserGetFrameNameById(uint8_t ipproto, AppProto alproto, const uint8_t id)
Definition: app-layer-parser.c:1866
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:32
AppLayerFramesFreeContainer
void AppLayerFramesFreeContainer(Flow *f)
Definition: app-layer-parser.c:201
FrameGetById
Frame * FrameGetById(Frames *frames, const int64_t id)
Definition: app-layer-frames.c:126
FRAME_FLAG_TX_ID_SET
#define FRAME_FLAG_TX_ID_SET
Definition: app-layer-frames.h:42
STREAM_BASE_OFFSET
#define STREAM_BASE_OFFSET(stream)
Definition: stream-tcp-private.h:144
SCAppLayerFrameNewByRelativeOffset
Frame * SCAppLayerFrameNewByRelativeOffset(Flow *f, const void *ss, const uint32_t frame_start_rel, const int64_t len, int dir, uint8_t frame_type)
create new frame using a relative offset from the start of the stream slice
Definition: app-layer-frames.c:545
AppLayerFrameGetById
Frame * AppLayerFrameGetById(const Flow *f, const int dir, const FrameId frame_id)
Definition: app-layer-frames.c:698
TcpSession_::state
uint8_t state
Definition: stream-tcp-private.h:285
FrameId
int64_t FrameId
Definition: app-layer-frames.h:38
AppLayerFramesSlide
void AppLayerFramesSlide(Flow *f, const uint32_t slide, const uint8_t direction)
Definition: app-layer-frames.c:411
app-layer-parser.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:322
FRAMES_STATIC_CNT
#define FRAMES_STATIC_CNT
Definition: app-layer-frames.h:62
Packet_
Definition: decode.h:516
StreamSlice::input
const uint8_t * input
Definition: app-layer-parser.h:127
Frame::len
int64_t len
Definition: app-layer-frames.h:56
Frame
struct Frame Frame
BIT_U64
#define BIT_U64(n)
Definition: suricata-common.h:423
SCAppLayerFrameSetTxIdById
void SCAppLayerFrameSetTxIdById(const Flow *f, const int dir, const FrameId id, uint64_t tx_id)
Definition: app-layer-frames.c:692
Frame::flags
uint8_t flags
Definition: app-layer-frames.h:51
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
TCP_CLOSED
@ TCP_CLOSED
Definition: stream-tcp-private.h:162
app-layer-frames.h
Frame::type
uint8_t type
Definition: app-layer-frames.h:50
suricata-common.h
Frame::event_cnt
uint8_t event_cnt
Definition: app-layer-frames.h:52
FatalError
#define FatalError(...)
Definition: util-debug.h:517
Frames::sframes
Frame sframes[FRAMES_STATIC_CNT]
Definition: app-layer-frames.h:69
AppLayerFrameNewByPointer
Frame * AppLayerFrameNewByPointer(Flow *f, const StreamSlice *stream_slice, const uint8_t *frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using a pointer to start of the frame
Definition: app-layer-frames.c:466
FrameConfigEnableAll
void FrameConfigEnableAll(void)
Definition: app-layer-frames.c:57
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:297
FrameConfigInit
void FrameConfigInit(void)
Definition: app-layer-frames.c:41
util-validate.h
FRAME_STREAM_TYPE
#define FRAME_STREAM_TYPE
Definition: app-layer-frames.h:36
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:296
PKT_PSEUDO_DETECTLOG_FLUSH
#define PKT_PSEUDO_DETECTLOG_FLUSH
Definition: decode.h:1353
FramesPrune
void FramesPrune(Flow *f, Packet *p)
Definition: app-layer-frames.c:838
SCFree
#define SCFree(p)
Definition: util-mem.h:61
FrameGetLastOpenByType
Frame * FrameGetLastOpenByType(Frames *frames, const uint8_t frame_type)
Definition: app-layer-frames.c:103
Frames::base_id
uint64_t base_id
Definition: app-layer-frames.h:68
src
uint16_t src
Definition: app-layer-dnp3.h:5
FrameConfigEnable
void FrameConfigEnable(const AppProto p, const uint8_t type)
Definition: app-layer-frames.c:66
AppLayerFrameDump
void AppLayerFrameDump(Flow *f)
Definition: app-layer-frames.c:596
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:201
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:145
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
TcpSession_
Definition: stream-tcp-private.h:283
FrameConfigDeInit
void FrameConfigDeInit(void)
Definition: app-layer-frames.c:52
flow.h
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
Frames::dyn_size
uint16_t dyn_size
Definition: app-layer-frames.h:66
AppLayerFrameSetLength
void AppLayerFrameSetLength(Frame *frame, int64_t len)
Definition: app-layer-frames.c:669
SC_ATOMIC_OR
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
Definition: util-atomic.h:350
f
Flow f
Definition: fuzz_dataset.c:32
FrameDebug
#define FrameDebug(prefix, frames, frame)
Definition: app-layer-frames.c:97