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