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