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