]> git.ipfire.org Git - thirdparty/snort3.git/blob - src/stream/stream.cc
19f67e2a75e953257e3ef8d083ecf95aaa2f9e96
[thirdparty/snort3.git] / src / stream / stream.cc
1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "stream.h"
25
26 #include <cassert>
27 #include <mutex>
28
29 #include "detection/detection_engine.h"
30 #include "flow/flow_cache.h"
31 #include "flow/flow_control.h"
32 #include "flow/flow_key.h"
33 #include "flow/ha.h"
34 #include "flow/prune_stats.h"
35 #include "framework/data_bus.h"
36 #include "main/snort.h"
37 #include "main/snort_config.h"
38 #include "network_inspectors/packet_tracer/packet_tracer.h"
39 #include "packet_io/active.h"
40 #include "protocols/vlan.h"
41 #include "pub_sub/stream_event_ids.h"
42 #include "stream/base/stream_module.h"
43 #include "target_based/host_attributes.h"
44 #include "target_based/snort_protocols.h"
45 #include "trace/trace_api.h"
46 #include "utils/util.h"
47
48 #include "tcp/tcp_session.h"
49 #include "tcp/tcp_stream_session.h"
50 #include "tcp/tcp_stream_tracker.h"
51
52 using namespace snort;
53
54 #define IDLE_PRUNE_MAX 400
55
56 // this should not be publicly accessible
57 extern THREAD_LOCAL class FlowControl* flow_con;
58
59 struct StreamImpl
60 {
61 public:
62 uint32_t xtradata_func_count = 0;
63 LogFunction xtradata_map[MAX_LOG_FN];
64 LogExtraData extra_data_log = nullptr;
65 void* extra_data_context = nullptr;
66 };
67
68 static StreamImpl stream;
69 static std::mutex stream_xtra_mutex;
70
71 //-------------------------------------------------------------------------
72 // session foo
73 //-------------------------------------------------------------------------
74
75 Flow* Stream::get_flow(const FlowKey* key)
76 { return flow_con->find_flow(key); }
77
78 Flow* Stream::new_flow(const FlowKey* key)
79 { return flow_con->new_flow(key); }
80
81 void Stream::delete_flow(const FlowKey* key)
82 { flow_con->release_flow(key); }
83
84 void Stream::delete_flow(Flow* flow)
85 {
86 flow_con->release_flow(flow, PruneReason::NONE);
87 }
88
89 //-------------------------------------------------------------------------
90 // key foo
91 //-------------------------------------------------------------------------
92
93 Flow* Stream::get_flow(
94 PktType type, IpProtocol proto,
95 const SfIp* srcIP, uint16_t srcPort,
96 const SfIp* dstIP, uint16_t dstPort,
97 uint16_t vlan, uint32_t mplsId, uint32_t addressSpaceId,
98 int16_t ingress_group, int16_t egress_group)
99 {
100 FlowKey key;
101 const SnortConfig* sc = SnortConfig::get_conf();
102
103 key.init(sc, type, proto, srcIP, srcPort, dstIP, dstPort, vlan, mplsId,
104 addressSpaceId, ingress_group, egress_group);
105 return get_flow(&key);
106 }
107
108 Flow* Stream::get_flow(
109 PktType type, IpProtocol proto,
110 const SfIp* srcIP, uint16_t srcPort,
111 const SfIp* dstIP, uint16_t dstPort,
112 uint16_t vlan, uint32_t mplsId, const DAQ_PktHdr_t& pkth)
113 {
114 FlowKey key;
115 const SnortConfig* sc = SnortConfig::get_conf();
116
117 key.init(sc, type, proto, srcIP, srcPort, dstIP, dstPort, vlan, mplsId,
118 pkth);
119 return get_flow(&key);
120 }
121
122 void Stream::populate_flow_key(const Packet* p, FlowKey* key)
123 {
124 if (!key || !p)
125 return;
126
127 key->init(
128 SnortConfig::get_conf(),
129 p->type(), p->get_ip_proto_next(),
130 p->ptrs.ip_api.get_src(), p->ptrs.sp,
131 p->ptrs.ip_api.get_dst(), p->ptrs.dp,
132 // if the vlan protocol bit is defined, vlan layer guaranteed to exist
133 (p->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(p)->vid() : 0,
134 (p->proto_bits & PROTO_BIT__MPLS) ? p->ptrs.mplsHdr.label : 0,
135 *p->pkth);
136 }
137
138 FlowKey* Stream::get_flow_key(Packet* p)
139 {
140 FlowKey* key = (FlowKey*)snort_calloc(sizeof(*key));
141 populate_flow_key(p, key);
142 return key;
143 }
144
145 //-------------------------------------------------------------------------
146 // app data foo
147 //-------------------------------------------------------------------------
148
149 FlowData* Stream::get_flow_data(
150 const FlowKey* key, unsigned flowdata_id)
151 {
152 Flow* flow = get_flow(key);
153 if (!flow)
154 return nullptr;
155 return flow->get_flow_data(flowdata_id);
156 }
157
158 FlowData* Stream::get_flow_data(
159 PktType type, IpProtocol proto,
160 const SfIp* srcIP, uint16_t srcPort,
161 const SfIp* dstIP, uint16_t dstPort,
162 uint16_t vlan, uint32_t mplsId,
163 uint32_t addressSpaceID, unsigned flowdata_id,
164 int16_t ingress_group, int16_t egress_group)
165 {
166 Flow* flow = get_flow(
167 type, proto, srcIP, srcPort, dstIP, dstPort,
168 vlan, mplsId, addressSpaceID, ingress_group,
169 egress_group);
170
171 if (!flow)
172 return nullptr;
173
174 return flow->get_flow_data(flowdata_id);
175 }
176
177 FlowData* Stream::get_flow_data(
178 PktType type, IpProtocol proto,
179 const SfIp* srcIP, uint16_t srcPort,
180 const SfIp* dstIP, uint16_t dstPort,
181 uint16_t vlan, uint32_t mplsId,
182 unsigned flowdata_id, const DAQ_PktHdr_t& pkth)
183 {
184 Flow* flow = get_flow(
185 type, proto, srcIP, srcPort, dstIP, dstPort,
186 vlan, mplsId, pkth);
187
188 if (!flow)
189 return nullptr;
190
191 return flow->get_flow_data(flowdata_id);
192 }
193
194 //-------------------------------------------------------------------------
195 //-------------------------------------------------------------------------
196 // session status
197 //-------------------------------------------------------------------------
198
199 void Stream::check_flow_closed(Packet* p)
200 {
201 Flow* flow = p->flow;
202
203 if ( !flow or (flow->session_state & STREAM_STATE_RELEASING) )
204 return;
205
206 flow->session_state |= STREAM_STATE_RELEASING;
207
208 if (flow->session_state & STREAM_STATE_CLOSED)
209 {
210 assert(flow_con);
211
212 // Will no longer have flow so save use_direct_inject state on packet.
213 if ( flow->flags.use_direct_inject )
214 p->packet_flags |= PKT_USE_DIRECT_INJECT;
215
216 p->flow = nullptr;
217
218 // this will get called on each onload
219 // eventually all onloads will occur and delete will be called
220 if ( not flow->is_suspended() )
221 {
222 flow_con->release_flow(flow, PruneReason::NONE);
223 return;
224 }
225 }
226 else if (flow->session_state & STREAM_STATE_BLOCK_PENDING)
227 {
228 flow->session->clear();
229 flow->free_flow_data();
230 flow->set_state(Flow::FlowState::BLOCK);
231
232 if ( !(p->packet_flags & PKT_STATELESS) )
233 {
234 drop_traffic(p, SSN_DIR_BOTH);
235 if (p->active)
236 p->active->set_drop_reason("stream");
237 if (PacketTracer::is_active())
238 PacketTracer::log("Stream: pending block, drop\n");
239 }
240 flow->clear_session_state(STREAM_STATE_BLOCK_PENDING);
241 }
242
243 flow->session_state &= ~STREAM_STATE_RELEASING;
244 }
245
246 int Stream::ignore_flow(
247 const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
248 const SfIp* srcIP, uint16_t srcPort,
249 const SfIp* dstIP, uint16_t dstPort,
250 char direction, FlowData* fd)
251 {
252 assert(flow_con);
253
254 return flow_con->add_expected_ignore(
255 ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort, direction, fd);
256 }
257
258 void Stream::stop_inspection(
259 Flow* flow, Packet* p, char dir,
260 int32_t /*bytes*/, int /*response*/)
261 {
262 assert(flow && flow->session);
263
264 debug_logf(stream_trace, TRACE_BASE, p, "stop inspection on flow, dir %s \n",
265 dir == SSN_DIR_BOTH ? "BOTH" :
266 ((dir == SSN_DIR_FROM_CLIENT) ? "FROM_CLIENT" : "FROM_SERVER"));
267
268 switch (dir)
269 {
270 case SSN_DIR_BOTH:
271 case SSN_DIR_FROM_CLIENT:
272 case SSN_DIR_FROM_SERVER:
273 flow->ssn_state.ignore_direction = dir;
274 break;
275 }
276
277 /* Flush any queued data on the client and/or server */
278 if (flow->pkt_type == PktType::TCP)
279 {
280 if (flow->ssn_state.ignore_direction & SSN_DIR_FROM_CLIENT)
281 flow->session->flush_client(p);
282
283 if (flow->ssn_state.ignore_direction & SSN_DIR_FROM_SERVER)
284 flow->session->flush_server(p);
285 }
286
287 /* FIXIT-M handle bytes/response parameters */
288
289 DetectionEngine::disable_all(p);
290 flow->set_state(Flow::FlowState::ALLOW);
291 }
292
293 uint32_t Stream::get_packet_direction(Packet* p)
294 {
295 if (!p || !(p->flow))
296 return 0;
297
298 p->flow->set_direction(p);
299
300 return (p->packet_flags & (PKT_FROM_SERVER|PKT_FROM_CLIENT));
301 }
302
303 void Stream::drop_traffic(const Packet* p, char dir)
304 {
305 Flow* flow = p->flow;
306
307 if ( !flow )
308 return;
309
310 if ((dir & SSN_DIR_FROM_CLIENT) && !(flow->ssn_state.session_flags & SSNFLAG_DROP_CLIENT))
311 flow->ssn_state.session_flags |= SSNFLAG_DROP_CLIENT;
312
313 if ((dir & SSN_DIR_FROM_SERVER) && !(flow->ssn_state.session_flags & SSNFLAG_DROP_SERVER))
314 flow->ssn_state.session_flags |= SSNFLAG_DROP_SERVER;
315 }
316
317 void Stream::block_flow(const Packet* p)
318 {
319 Flow* flow = p->flow;
320
321 if (!flow)
322 return;
323
324 // Postpone clear till inspection is completed
325 flow->session_state |= STREAM_STATE_BLOCK_PENDING;
326
327 flow->disable_inspection();
328 }
329
330 void Stream::drop_flow(const Packet* p)
331 {
332 Flow* flow = p->flow;
333
334 if (!flow)
335 return;
336
337 flow->session_state |= STREAM_STATE_BLOCK_PENDING;
338 flow->session->clear();
339 flow->set_state(Flow::FlowState::BLOCK);
340
341 flow->disable_inspection();
342
343 if ( !(p->packet_flags & PKT_STATELESS) )
344 drop_traffic(p, SSN_DIR_BOTH);
345
346 p->active->set_drop_reason("stream");
347 if (PacketTracer::is_active())
348 PacketTracer::log("Stream: session has been dropped\n");
349 }
350
351 //-------------------------------------------------------------------------
352 // misc support
353 //-------------------------------------------------------------------------
354
355 void Stream::init_active_response(const Packet* p, Flow* flow)
356 {
357 if ( !flow )
358 return;
359
360 flow->response_count = 1;
361
362 if ( p->context->conf->max_responses > 1 )
363 flow->set_expire(p, p->context->conf->min_interval);
364 }
365
366 void Stream::purge_flows()
367 {
368 if ( flow_con )
369 flow_con->purge_flows();
370 }
371
372 void Stream::handle_timeouts(bool idle)
373 {
374 timeval cur_time;
375 packet_gettimeofday(&cur_time);
376
377 // FIXIT-M batch here or loop vs looping over idle?
378 if (flow_con)
379 {
380 if (idle)
381 flow_con->timeout_flows(IDLE_PRUNE_MAX, cur_time.tv_sec);
382 else
383 flow_con->timeout_flows(1, cur_time.tv_sec);
384 }
385
386 int max_remove = idle ? -1 : 1; // -1 = all eligible
387 TcpStreamTracker::release_held_packets(cur_time, max_remove);
388 }
389
390 bool Stream::prune_flows()
391 {
392 if ( !flow_con )
393 return false;
394
395 return flow_con->prune_multiple(PruneReason::MEMCAP, false);
396 }
397
398 //-------------------------------------------------------------------------
399 // app proto id foo
400 //-------------------------------------------------------------------------
401
402 int Stream::set_snort_protocol_id_expected(
403 const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
404 const SfIp* srcIP, uint16_t srcPort,
405 const SfIp* dstIP, uint16_t dstPort,
406 SnortProtocolId snort_protocol_id, FlowData* fd, bool swap_app_direction, bool expect_multi,
407 bool bidirectional, bool expect_persist)
408 {
409 assert(flow_con);
410
411 return flow_con->add_expected(
412 ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort, snort_protocol_id, fd,
413 swap_app_direction, expect_multi, bidirectional, expect_persist);
414 }
415
416 void Stream::set_snort_protocol_id_from_ha(
417 Flow* flow, const SnortProtocolId snort_protocol_id)
418 {
419 if (!flow )
420 return;
421
422 if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
423 return;
424
425 if (flow->ssn_state.ipprotocol == 0)
426 set_ip_protocol(flow);
427
428 flow->ssn_state.snort_protocol_id = snort_protocol_id;
429 if ( snort_protocol_id != UNKNOWN_PROTOCOL_ID &&
430 snort_protocol_id != INVALID_PROTOCOL_ID )
431 flow->flags.snort_proto_id_set_by_ha = true;
432 }
433
434 SnortProtocolId Stream::get_snort_protocol_id(Flow* flow)
435 {
436 /* Not caching the source and dest host_entry in the session so we can
437 * swap the table out after processing this packet if we need
438 * to. */
439
440 if (!flow)
441 return UNKNOWN_PROTOCOL_ID;
442
443 if ( flow->ssn_state.snort_protocol_id == INVALID_PROTOCOL_ID )
444 return UNKNOWN_PROTOCOL_ID;
445
446 if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
447 return flow->ssn_state.snort_protocol_id;
448
449 if (flow->ssn_state.ipprotocol == 0)
450 set_ip_protocol(flow);
451
452 HostAttriInfo host;
453 if (HostAttributesManager::get_host_attributes(flow->server_ip, flow->server_port, &host))
454 {
455 set_snort_protocol_id_from_ha(flow, host.snort_protocol_id);
456
457 if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
458 return flow->ssn_state.snort_protocol_id;
459 }
460
461 if (HostAttributesManager::get_host_attributes(flow->client_ip, flow->client_port, &host))
462 {
463 set_snort_protocol_id_from_ha(flow, host.snort_protocol_id);
464
465 if (flow->ssn_state.snort_protocol_id != UNKNOWN_PROTOCOL_ID)
466 return flow->ssn_state.snort_protocol_id;
467 }
468
469 flow->ssn_state.snort_protocol_id = INVALID_PROTOCOL_ID;
470 return UNKNOWN_PROTOCOL_ID;
471 }
472
473 SnortProtocolId Stream::set_snort_protocol_id(Flow* flow, SnortProtocolId id, bool is_appid_service)
474 {
475 if (!flow)
476 return UNKNOWN_PROTOCOL_ID;
477
478 if (flow->ssn_state.snort_protocol_id != id)
479 flow->flags.snort_proto_id_set_by_ha = false;
480
481 flow->ssn_state.snort_protocol_id = id;
482
483 if (!flow->ssn_state.ipprotocol)
484 set_ip_protocol(flow);
485
486 if ( !flow->is_proxied() and !flow->flags.snort_proto_id_set_by_ha )
487 {
488 HostAttributesManager::update_service
489 (flow->server_ip, flow->server_port, flow->ssn_state.ipprotocol, id, is_appid_service);
490 }
491
492 return id;
493 }
494
495 //-------------------------------------------------------------------------
496 // splitter foo
497 //-------------------------------------------------------------------------
498
499 void Stream::set_splitter(Flow* flow, bool to_server, StreamSplitter* ss)
500 {
501 assert(flow && flow->session);
502 return flow->session->set_splitter(to_server, ss);
503 }
504
505 StreamSplitter* Stream::get_splitter(Flow* flow, bool to_server)
506 {
507 assert(flow && flow->session);
508 StreamSplitter* ss = flow->session->get_splitter(to_server);
509 return ss;
510 }
511
512 //-------------------------------------------------------------------------
513 // extra data foo
514 //-------------------------------------------------------------------------
515
516 void Stream::log_extra_data(
517 Flow* flow, uint32_t mask, const AlertInfo& alert_info)
518 {
519 if ( mask && stream.extra_data_log )
520 {
521 stream.extra_data_log(
522 flow, stream.extra_data_context, stream.xtradata_map,
523 stream.xtradata_func_count, mask, alert_info);
524 }
525 }
526
527 uint32_t Stream::reg_xtra_data_cb(LogFunction f)
528 {
529 uint32_t i = 0;
530 while (i < stream.xtradata_func_count)
531 {
532 if (stream.xtradata_map[i++] == f)
533 return i;
534 }
535 if ( stream.xtradata_func_count == MAX_LOG_FN)
536 {
537 return 0;
538 }
539
540 stream.xtradata_map[stream.xtradata_func_count++] = f;
541 return stream.xtradata_func_count;
542 }
543
544 uint32_t Stream::get_xtra_data_map(LogFunction*& f)
545 {
546 f = stream.xtradata_map;
547 return stream.xtradata_func_count;
548 }
549
550 void Stream::reg_xtra_data_log(LogExtraData f, void* config)
551 {
552 const std::lock_guard<std::mutex> xtra_lock(stream_xtra_mutex);
553 stream.extra_data_log = f;
554 stream.extra_data_context = config;
555 }
556
557 //-------------------------------------------------------------------------
558 // other foo
559 //-------------------------------------------------------------------------
560
561 uint8_t Stream::get_flow_ttl(Flow* flow, char dir, bool outer)
562 {
563 if ( !flow )
564 return 0;
565
566 if ( FROM_CLIENT == dir )
567 return outer ? flow->outer_client_ttl : flow->inner_client_ttl;
568
569 return outer ? flow->outer_server_ttl : flow->inner_server_ttl;
570 }
571
572 //-------------------------------------------------------------------------
573 // flow disposition logic
574 //-------------------------------------------------------------------------
575
576 // *DROP* flags are set to mark the direction(s) for which traffic was
577 // seen since last reset and then cleared after sending new attempt so
578 // that we only send in the still active direction(s).
579 static void active_response(Packet* p, Flow* lwssn)
580 {
581 uint8_t max = p->context->conf->max_responses;
582
583 if ( p->is_from_client() )
584 lwssn->session_state |= STREAM_STATE_DROP_CLIENT;
585 else
586 lwssn->session_state |= STREAM_STATE_DROP_SERVER;
587
588 if ( (lwssn->response_count < max) && lwssn->expired(p) )
589 {
590 uint32_t delay = p->context->conf->min_interval;
591 EncodeFlags flags =
592 ( (lwssn->session_state & STREAM_STATE_DROP_CLIENT) &&
593 (lwssn->session_state & STREAM_STATE_DROP_SERVER) ) ?
594 ENC_FLAG_FWD : 0; // reverse dir is always true
595
596 p->active->kill_session(p, flags);
597 ++lwssn->response_count;
598 lwssn->set_expire(p, delay);
599
600 lwssn->clear_session_state(STREAM_STATE_DROP_CLIENT|STREAM_STATE_DROP_SERVER);
601 }
602 }
603
604 bool Stream::blocked_flow(Packet* p)
605 {
606 Flow* flow = p->flow;
607
608 if ( !(flow->ssn_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)) )
609 return false;
610
611 if (
612 ((p->is_from_server()) &&
613 (flow->ssn_state.session_flags & SSNFLAG_DROP_SERVER)) ||
614
615 ((p->is_from_client()) &&
616 (flow->ssn_state.session_flags & SSNFLAG_DROP_CLIENT)) )
617 {
618 DetectionEngine::disable_content(p);
619 p->active->drop_packet(p);
620 active_response(p, flow);
621 p->active->set_drop_reason("stream");
622 if (PacketTracer::is_active())
623 PacketTracer::log("Stream: session was already blocked\n");
624 return true;
625 }
626 return false;
627 }
628
629 bool Stream::ignored_flow(Flow* flow, Packet* p)
630 {
631 if (((p->is_from_server()) &&
632 (flow->ssn_state.ignore_direction & SSN_DIR_FROM_CLIENT)) ||
633 ((p->is_from_client()) &&
634 (flow->ssn_state.ignore_direction & SSN_DIR_FROM_SERVER)) )
635 {
636 DetectionEngine::disable_all(p);
637 return true;
638 }
639
640 return false;
641 }
642
643 static int StreamExpire(Packet* p, Flow* lwssn)
644 {
645 if ( !lwssn->expired(p) )
646 return 0;
647
648 if ( HighAvailabilityManager::in_standby(lwssn) )
649 return 1;
650
651 lwssn->ssn_state.session_flags |= SSNFLAG_TIMEDOUT;
652 lwssn->session_state |= STREAM_STATE_TIMEDOUT;
653
654 return 1;
655 }
656
657 bool Stream::expired_flow(Flow* flow, Packet* p)
658 {
659 if ( (flow->session_state & STREAM_STATE_TIMEDOUT)
660 || StreamExpire(p, flow) )
661 {
662 flow->ssn_state.session_flags |= SSNFLAG_TIMEDOUT;
663 return true;
664 }
665 return false;
666 }
667
668 //-------------------------------------------------------------------------
669 // TCP, UDP, ICMP only
670 //-------------------------------------------------------------------------
671
672 /* This should preferably only be called when ipprotocol is 0. */
673 void Stream::set_ip_protocol(Flow* flow)
674 {
675 switch (flow->pkt_type)
676 {
677 case PktType::TCP:
678 flow->ssn_state.ipprotocol = SNORT_PROTO_TCP;
679 break;
680
681 case PktType::UDP:
682 flow->ssn_state.ipprotocol = SNORT_PROTO_UDP;
683 break;
684
685 case PktType::ICMP:
686 flow->ssn_state.ipprotocol = SNORT_PROTO_ICMP;
687 break;
688
689 default:
690 break;
691 }
692 }
693
694 //-------------------------------------------------------------------------
695 // TCP only
696 //-------------------------------------------------------------------------
697
698 static bool ok_to_flush(Packet* p)
699 {
700 if ( p->packet_flags & PKT_REBUILT_STREAM )
701 return false;
702
703 if ( p->type() != PktType::TCP )
704 return false;
705
706 return true;
707 }
708
709 void Stream::flush_client(Packet* p)
710 {
711 if ( !ok_to_flush(p) )
712 return;
713
714 if ( p->is_from_client() )
715 p->flow->session->flush_talker(p);
716
717 else if ( p->is_from_server() )
718 p->flow->session->flush_listener(p);
719 }
720
721 void Stream::flush_server(Packet* p)
722 {
723 if ( !ok_to_flush(p) )
724 return;
725
726 if ( p->is_from_client() )
727 p->flow->session->flush_listener(p);
728
729 else if ( p->is_from_server() )
730 p->flow->session->flush_talker(p);
731 }
732
733 // return true if added
734 bool Stream::add_flow_alert(
735 Flow* flow, Packet* p, uint32_t gid, uint32_t sid)
736 {
737 if ( !flow )
738 return false;
739
740 return flow->session->add_alert(p, gid, sid);
741 }
742
743 // return true if gid/sid have already been seen
744 bool Stream::check_flow_alerted(
745 Flow* flow, Packet* p, uint32_t gid, uint32_t sid)
746 {
747 if ( !flow )
748 return false;
749
750 return flow->session->check_alerted(p, gid, sid);
751 }
752
753 int Stream::update_flow_alert(
754 Flow* flow, Packet* p,
755 uint32_t gid, uint32_t sid,
756 uint32_t event_id, uint32_t event_second)
757 {
758 assert(flow && flow->session);
759 return flow->session->update_alert(p, gid, sid, event_id, event_second);
760 }
761
762 void Stream::set_extra_data(
763 Flow* flow, Packet* p, uint32_t flag)
764 {
765 assert(flow && flow->session);
766 flow->session->set_extra_data(p, flag);
767 }
768
769 void Stream::disable_reassembly(Flow* flow)
770 {
771 assert(flow && flow->session);
772 return flow->session->disable_reassembly(flow);
773 }
774
775 char Stream::get_reassembly_direction(Flow* flow)
776 {
777 assert(flow && flow->session);
778 return flow->session->get_reassembly_direction();
779 }
780
781 bool Stream::is_stream_sequenced(Flow* flow, uint8_t dir)
782 {
783 assert(flow && flow->session);
784 return flow->session->is_sequenced(dir);
785 }
786
787 int Stream::missing_in_reassembled(Flow* flow, uint8_t dir)
788 {
789 assert(flow && flow->session);
790 return flow->session->missing_in_reassembled(dir);
791 }
792
793 bool Stream::missed_packets(Flow* flow, uint8_t dir)
794 {
795 assert(flow && flow->session);
796 return flow->session->are_packets_missing(dir);
797 }
798
799 uint16_t Stream::get_mss(Flow* flow, bool to_server)
800 {
801 assert(flow and flow->session and flow->pkt_type == PktType::TCP);
802
803 TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
804 return tcp_session->get_mss(to_server);
805 }
806
807 uint8_t Stream::get_tcp_options_len(Flow* flow, bool to_server)
808 {
809 assert(flow and flow->session and flow->pkt_type == PktType::TCP);
810
811 TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
812 return tcp_session->get_tcp_options_len(to_server);
813 }
814
815 bool Stream::set_packet_action_to_hold(Packet* p)
816 {
817 if ( !p or !p->flow or !p->flow->session )
818 return false;
819
820 return p->flow->session->set_packet_action_to_hold(p);
821 }
822
823 bool Stream::can_set_no_ack_mode(Flow* flow)
824 {
825 assert(flow and flow->session and flow->pkt_type == PktType::TCP);
826
827 TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
828 return tcp_session->can_set_no_ack();
829 }
830
831 bool Stream::set_no_ack_mode(Flow* flow, bool on_off)
832 {
833 assert(flow and flow->session and flow->pkt_type == PktType::TCP);
834
835 TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
836 return tcp_session->set_no_ack(on_off);
837 }
838
839 void Stream::partial_flush(Flow* flow, bool to_server)
840 {
841 if ( flow->pkt_type == PktType::TCP )
842 {
843 if ( to_server )
844 ((TcpStreamSession*)flow->session)->server.perform_partial_flush();
845 else
846 ((TcpStreamSession*)flow->session)->client.perform_partial_flush();
847 }
848 }
849
850 bool Stream::get_held_pkt_seq(Flow* flow, uint32_t& seq)
851 {
852 if (!flow or !flow->session or !(flow->pkt_type == PktType::TCP))
853 return false;
854
855 TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
856
857 if (tcp_session->held_packet_dir == SSN_DIR_NONE)
858 return false;
859
860 if (tcp_session->held_packet_dir == SSN_DIR_FROM_CLIENT)
861 {
862 seq = tcp_session->server.held_pkt_seq;
863 tcp_session->held_packet_dir = SSN_DIR_NONE;
864 return true;
865 }
866
867 if (tcp_session->held_packet_dir == SSN_DIR_FROM_SERVER)
868 {
869 seq = tcp_session->client.held_pkt_seq;
870 tcp_session->held_packet_dir = SSN_DIR_NONE;
871 return true;
872 }
873
874 return false;
875 }
876
877 //-------------------------------------------------------------------------
878 // pub sub foo
879 //-------------------------------------------------------------------------
880
881 static unsigned stream_pub_id = 0;
882
883 void Stream::set_pub_id()
884 { stream_pub_id = DataBus::get_id(stream_pub_key); }
885
886 unsigned Stream::get_pub_id()
887 { return stream_pub_id; }
888
889 //-------------------------------------------------------------------------
890 #ifdef UNIT_TEST
891 //-------------------------------------------------------------------------
892
893 #include "catch/snort_catch.h"
894 #include "tcp/test/stream_tcp_test_utils.h"
895
896 TEST_CASE("Stream API", "[stream_api][stream]")
897 {
898 // initialization code here
899 Flow* flow = new Flow;
900
901 SECTION("set/get ignore direction")
902 {
903 int dir = flow->set_ignore_direction(SSN_DIR_NONE);
904 CHECK( ( dir == SSN_DIR_NONE ) );
905 dir = flow->get_ignore_direction( );
906 CHECK( ( dir == SSN_DIR_NONE ) );
907
908 dir = flow->set_ignore_direction(SSN_DIR_FROM_CLIENT);
909 CHECK( ( dir == SSN_DIR_FROM_CLIENT ) );
910 dir = flow->get_ignore_direction( );
911 CHECK( ( dir == SSN_DIR_FROM_CLIENT ) );
912
913 dir = flow->set_ignore_direction(SSN_DIR_FROM_SERVER);
914 CHECK( ( dir == SSN_DIR_FROM_SERVER ) );
915 dir = flow->get_ignore_direction( );
916 CHECK( ( dir == SSN_DIR_FROM_SERVER ) );
917
918 dir = flow->set_ignore_direction(SSN_DIR_BOTH);
919 CHECK( ( dir == SSN_DIR_BOTH ) );
920 dir = flow->get_ignore_direction( );
921 CHECK( ( dir == SSN_DIR_BOTH ) );
922 }
923
924 SECTION("stop inspection")
925 {
926 Packet* pkt = get_syn_packet(flow);
927 int dir;
928
929 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_CLIENT, 0, 0);
930 dir = flow->get_ignore_direction( );
931 CHECK( ( dir == SSN_DIR_FROM_CLIENT ) );
932 CHECK( ( flow->flow_state == Flow::FlowState::ALLOW ) );
933
934 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_SERVER, 0, 0);
935 dir = flow->get_ignore_direction( );
936 CHECK( ( dir == SSN_DIR_FROM_SERVER ) );
937 CHECK( ( flow->flow_state == Flow::FlowState::ALLOW ) );
938
939 release_packet(pkt);
940 }
941
942 SECTION("stop inspection from server - client packet")
943 {
944 Packet* pkt = get_syn_packet(flow);
945
946 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_SERVER, 0, 0);
947 bool ignored = Stream::ignored_flow(flow, pkt);
948 CHECK(ignored);
949
950 release_packet(pkt);
951 }
952
953 SECTION("stop inspection from server - server packet")
954 {
955 Packet* pkt = get_syn_ack_packet(flow);
956
957 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_SERVER, 0, 0);
958 bool ignored = Stream::ignored_flow(flow, pkt);
959 CHECK(!ignored);
960
961 release_packet(pkt);
962 }
963
964 SECTION("stop inspection from client - client packet")
965 {
966 Packet* pkt = get_syn_packet(flow);
967
968 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_CLIENT, 0, 0);
969 bool ignored = Stream::ignored_flow(flow, pkt);
970 CHECK(!ignored);
971
972 release_packet(pkt);
973 }
974
975 SECTION("stop inspection from client - server packet")
976 {
977 Packet* pkt = get_syn_ack_packet(flow);
978
979 Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_CLIENT, 0, 0);
980 bool ignored = Stream::ignored_flow(flow, pkt);
981 CHECK(ignored);
982
983 release_packet(pkt);
984 }
985
986 SECTION("stop inspection both - client packet")
987 {
988 Packet* pkt = get_syn_packet(flow);
989
990 Stream::stop_inspection(flow, pkt, SSN_DIR_BOTH, 0, 0);
991 bool ignored = Stream::ignored_flow(flow, pkt);
992 CHECK(ignored);
993
994 release_packet(pkt);
995 }
996
997 SECTION("stop inspection both - server packet")
998 {
999 Packet* pkt = get_syn_ack_packet(flow);
1000
1001 Stream::stop_inspection(flow, pkt, SSN_DIR_BOTH, 0, 0);
1002 bool ignored = Stream::ignored_flow(flow, pkt);
1003 CHECK(ignored);
1004
1005 release_packet(pkt);
1006 }
1007
1008 delete flow;
1009 }
1010
1011 #endif
1012