1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-2013 Sourcefire, Inc.
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.
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.
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 //--------------------------------------------------------------------------
29 #include "detection/detection_engine.h"
30 #include "flow/flow_cache.h"
31 #include "flow/flow_control.h"
32 #include "flow/flow_key.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"
48 #include "tcp/tcp_session.h"
49 #include "tcp/tcp_stream_session.h"
50 #include "tcp/tcp_stream_tracker.h"
52 using namespace snort
;
54 #define IDLE_PRUNE_MAX 400
56 // this should not be publicly accessible
57 extern THREAD_LOCAL
class FlowControl
* flow_con
;
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;
68 static StreamImpl stream
;
69 static std::mutex stream_xtra_mutex
;
71 //-------------------------------------------------------------------------
73 //-------------------------------------------------------------------------
75 Flow
* Stream::get_flow(const FlowKey
* key
)
76 { return flow_con
->find_flow(key
); }
78 Flow
* Stream::new_flow(const FlowKey
* key
)
79 { return flow_con
->new_flow(key
); }
81 void Stream::delete_flow(const FlowKey
* key
)
82 { flow_con
->release_flow(key
); }
84 void Stream::delete_flow(Flow
* flow
)
86 flow_con
->release_flow(flow
, PruneReason::NONE
);
89 //-------------------------------------------------------------------------
91 //-------------------------------------------------------------------------
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
)
101 const SnortConfig
* sc
= SnortConfig::get_conf();
103 key
.init(sc
, type
, proto
, srcIP
, srcPort
, dstIP
, dstPort
, vlan
, mplsId
,
104 addressSpaceId
, ingress_group
, egress_group
);
105 return get_flow(&key
);
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
)
115 const SnortConfig
* sc
= SnortConfig::get_conf();
117 key
.init(sc
, type
, proto
, srcIP
, srcPort
, dstIP
, dstPort
, vlan
, mplsId
,
119 return get_flow(&key
);
122 void Stream::populate_flow_key(const Packet
* p
, FlowKey
* key
)
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,
138 FlowKey
* Stream::get_flow_key(Packet
* p
)
140 FlowKey
* key
= (FlowKey
*)snort_calloc(sizeof(*key
));
141 populate_flow_key(p
, key
);
145 //-------------------------------------------------------------------------
147 //-------------------------------------------------------------------------
149 FlowData
* Stream::get_flow_data(
150 const FlowKey
* key
, unsigned flowdata_id
)
152 Flow
* flow
= get_flow(key
);
155 return flow
->get_flow_data(flowdata_id
);
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
)
166 Flow
* flow
= get_flow(
167 type
, proto
, srcIP
, srcPort
, dstIP
, dstPort
,
168 vlan
, mplsId
, addressSpaceID
, ingress_group
,
174 return flow
->get_flow_data(flowdata_id
);
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
)
184 Flow
* flow
= get_flow(
185 type
, proto
, srcIP
, srcPort
, dstIP
, dstPort
,
191 return flow
->get_flow_data(flowdata_id
);
194 //-------------------------------------------------------------------------
195 //-------------------------------------------------------------------------
197 //-------------------------------------------------------------------------
199 void Stream::check_flow_closed(Packet
* p
)
201 Flow
* flow
= p
->flow
;
203 if ( !flow
or (flow
->session_state
& STREAM_STATE_RELEASING
) )
206 flow
->session_state
|= STREAM_STATE_RELEASING
;
208 if (flow
->session_state
& STREAM_STATE_CLOSED
)
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
;
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() )
222 flow_con
->release_flow(flow
, PruneReason::NONE
);
226 else if (flow
->session_state
& STREAM_STATE_BLOCK_PENDING
)
228 flow
->session
->clear();
229 flow
->free_flow_data();
230 flow
->set_state(Flow::FlowState::BLOCK
);
232 if ( !(p
->packet_flags
& PKT_STATELESS
) )
234 drop_traffic(p
, SSN_DIR_BOTH
);
236 p
->active
->set_drop_reason("stream");
237 if (PacketTracer::is_active())
238 PacketTracer::log("Stream: pending block, drop\n");
240 flow
->clear_session_state(STREAM_STATE_BLOCK_PENDING
);
243 flow
->session_state
&= ~STREAM_STATE_RELEASING
;
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
)
254 return flow_con
->add_expected_ignore(
255 ctrlPkt
, type
, ip_proto
, srcIP
, srcPort
, dstIP
, dstPort
, direction
, fd
);
258 void Stream::stop_inspection(
259 Flow
* flow
, Packet
* p
, char dir
,
260 int32_t /*bytes*/, int /*response*/)
262 assert(flow
&& flow
->session
);
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"));
271 case SSN_DIR_FROM_CLIENT
:
272 case SSN_DIR_FROM_SERVER
:
273 flow
->ssn_state
.ignore_direction
= dir
;
277 /* Flush any queued data on the client and/or server */
278 if (flow
->pkt_type
== PktType::TCP
)
280 if (flow
->ssn_state
.ignore_direction
& SSN_DIR_FROM_CLIENT
)
281 flow
->session
->flush_client(p
);
283 if (flow
->ssn_state
.ignore_direction
& SSN_DIR_FROM_SERVER
)
284 flow
->session
->flush_server(p
);
287 /* FIXIT-M handle bytes/response parameters */
289 DetectionEngine::disable_all(p
);
290 flow
->set_state(Flow::FlowState::ALLOW
);
293 uint32_t Stream::get_packet_direction(Packet
* p
)
295 if (!p
|| !(p
->flow
))
298 p
->flow
->set_direction(p
);
300 return (p
->packet_flags
& (PKT_FROM_SERVER
|PKT_FROM_CLIENT
));
303 void Stream::drop_traffic(const Packet
* p
, char dir
)
305 Flow
* flow
= p
->flow
;
310 if ((dir
& SSN_DIR_FROM_CLIENT
) && !(flow
->ssn_state
.session_flags
& SSNFLAG_DROP_CLIENT
))
311 flow
->ssn_state
.session_flags
|= SSNFLAG_DROP_CLIENT
;
313 if ((dir
& SSN_DIR_FROM_SERVER
) && !(flow
->ssn_state
.session_flags
& SSNFLAG_DROP_SERVER
))
314 flow
->ssn_state
.session_flags
|= SSNFLAG_DROP_SERVER
;
317 void Stream::block_flow(const Packet
* p
)
319 Flow
* flow
= p
->flow
;
324 // Postpone clear till inspection is completed
325 flow
->session_state
|= STREAM_STATE_BLOCK_PENDING
;
327 flow
->disable_inspection();
330 void Stream::drop_flow(const Packet
* p
)
332 Flow
* flow
= p
->flow
;
337 flow
->session_state
|= STREAM_STATE_BLOCK_PENDING
;
338 flow
->session
->clear();
339 flow
->set_state(Flow::FlowState::BLOCK
);
341 flow
->disable_inspection();
343 if ( !(p
->packet_flags
& PKT_STATELESS
) )
344 drop_traffic(p
, SSN_DIR_BOTH
);
346 p
->active
->set_drop_reason("stream");
347 if (PacketTracer::is_active())
348 PacketTracer::log("Stream: session has been dropped\n");
351 //-------------------------------------------------------------------------
353 //-------------------------------------------------------------------------
355 void Stream::init_active_response(const Packet
* p
, Flow
* flow
)
360 flow
->response_count
= 1;
362 if ( p
->context
->conf
->max_responses
> 1 )
363 flow
->set_expire(p
, p
->context
->conf
->min_interval
);
366 void Stream::purge_flows()
369 flow_con
->purge_flows();
372 void Stream::handle_timeouts(bool idle
)
375 packet_gettimeofday(&cur_time
);
377 // FIXIT-M batch here or loop vs looping over idle?
381 flow_con
->timeout_flows(IDLE_PRUNE_MAX
, cur_time
.tv_sec
);
383 flow_con
->timeout_flows(1, cur_time
.tv_sec
);
386 int max_remove
= idle
? -1 : 1; // -1 = all eligible
387 TcpStreamTracker::release_held_packets(cur_time
, max_remove
);
390 bool Stream::prune_flows()
395 return flow_con
->prune_multiple(PruneReason::MEMCAP
, false);
398 //-------------------------------------------------------------------------
400 //-------------------------------------------------------------------------
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
)
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
);
416 void Stream::set_snort_protocol_id_from_ha(
417 Flow
* flow
, const SnortProtocolId snort_protocol_id
)
422 if (flow
->ssn_state
.snort_protocol_id
!= UNKNOWN_PROTOCOL_ID
)
425 if (flow
->ssn_state
.ipprotocol
== 0)
426 set_ip_protocol(flow
);
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;
434 SnortProtocolId
Stream::get_snort_protocol_id(Flow
* flow
)
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
441 return UNKNOWN_PROTOCOL_ID
;
443 if ( flow
->ssn_state
.snort_protocol_id
== INVALID_PROTOCOL_ID
)
444 return UNKNOWN_PROTOCOL_ID
;
446 if (flow
->ssn_state
.snort_protocol_id
!= UNKNOWN_PROTOCOL_ID
)
447 return flow
->ssn_state
.snort_protocol_id
;
449 if (flow
->ssn_state
.ipprotocol
== 0)
450 set_ip_protocol(flow
);
453 if (HostAttributesManager::get_host_attributes(flow
->server_ip
, flow
->server_port
, &host
))
455 set_snort_protocol_id_from_ha(flow
, host
.snort_protocol_id
);
457 if (flow
->ssn_state
.snort_protocol_id
!= UNKNOWN_PROTOCOL_ID
)
458 return flow
->ssn_state
.snort_protocol_id
;
461 if (HostAttributesManager::get_host_attributes(flow
->client_ip
, flow
->client_port
, &host
))
463 set_snort_protocol_id_from_ha(flow
, host
.snort_protocol_id
);
465 if (flow
->ssn_state
.snort_protocol_id
!= UNKNOWN_PROTOCOL_ID
)
466 return flow
->ssn_state
.snort_protocol_id
;
469 flow
->ssn_state
.snort_protocol_id
= INVALID_PROTOCOL_ID
;
470 return UNKNOWN_PROTOCOL_ID
;
473 SnortProtocolId
Stream::set_snort_protocol_id(Flow
* flow
, SnortProtocolId id
, bool is_appid_service
)
476 return UNKNOWN_PROTOCOL_ID
;
478 if (flow
->ssn_state
.snort_protocol_id
!= id
)
479 flow
->flags
.snort_proto_id_set_by_ha
= false;
481 flow
->ssn_state
.snort_protocol_id
= id
;
483 if (!flow
->ssn_state
.ipprotocol
)
484 set_ip_protocol(flow
);
486 if ( !flow
->is_proxied() and !flow
->flags
.snort_proto_id_set_by_ha
)
488 HostAttributesManager::update_service
489 (flow
->server_ip
, flow
->server_port
, flow
->ssn_state
.ipprotocol
, id
, is_appid_service
);
495 //-------------------------------------------------------------------------
497 //-------------------------------------------------------------------------
499 void Stream::set_splitter(Flow
* flow
, bool to_server
, StreamSplitter
* ss
)
501 assert(flow
&& flow
->session
);
502 return flow
->session
->set_splitter(to_server
, ss
);
505 StreamSplitter
* Stream::get_splitter(Flow
* flow
, bool to_server
)
507 assert(flow
&& flow
->session
);
508 StreamSplitter
* ss
= flow
->session
->get_splitter(to_server
);
512 //-------------------------------------------------------------------------
514 //-------------------------------------------------------------------------
516 void Stream::log_extra_data(
517 Flow
* flow
, uint32_t mask
, const AlertInfo
& alert_info
)
519 if ( mask
&& stream
.extra_data_log
)
521 stream
.extra_data_log(
522 flow
, stream
.extra_data_context
, stream
.xtradata_map
,
523 stream
.xtradata_func_count
, mask
, alert_info
);
527 uint32_t Stream::reg_xtra_data_cb(LogFunction f
)
530 while (i
< stream
.xtradata_func_count
)
532 if (stream
.xtradata_map
[i
++] == f
)
535 if ( stream
.xtradata_func_count
== MAX_LOG_FN
)
540 stream
.xtradata_map
[stream
.xtradata_func_count
++] = f
;
541 return stream
.xtradata_func_count
;
544 uint32_t Stream::get_xtra_data_map(LogFunction
*& f
)
546 f
= stream
.xtradata_map
;
547 return stream
.xtradata_func_count
;
550 void Stream::reg_xtra_data_log(LogExtraData f
, void* config
)
552 const std::lock_guard
<std::mutex
> xtra_lock(stream_xtra_mutex
);
553 stream
.extra_data_log
= f
;
554 stream
.extra_data_context
= config
;
557 //-------------------------------------------------------------------------
559 //-------------------------------------------------------------------------
561 uint8_t Stream::get_flow_ttl(Flow
* flow
, char dir
, bool outer
)
566 if ( FROM_CLIENT
== dir
)
567 return outer
? flow
->outer_client_ttl
: flow
->inner_client_ttl
;
569 return outer
? flow
->outer_server_ttl
: flow
->inner_server_ttl
;
572 //-------------------------------------------------------------------------
573 // flow disposition logic
574 //-------------------------------------------------------------------------
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
)
581 uint8_t max
= p
->context
->conf
->max_responses
;
583 if ( p
->is_from_client() )
584 lwssn
->session_state
|= STREAM_STATE_DROP_CLIENT
;
586 lwssn
->session_state
|= STREAM_STATE_DROP_SERVER
;
588 if ( (lwssn
->response_count
< max
) && lwssn
->expired(p
) )
590 uint32_t delay
= p
->context
->conf
->min_interval
;
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
596 p
->active
->kill_session(p
, flags
);
597 ++lwssn
->response_count
;
598 lwssn
->set_expire(p
, delay
);
600 lwssn
->clear_session_state(STREAM_STATE_DROP_CLIENT
|STREAM_STATE_DROP_SERVER
);
604 bool Stream::blocked_flow(Packet
* p
)
606 Flow
* flow
= p
->flow
;
608 if ( !(flow
->ssn_state
.session_flags
& (SSNFLAG_DROP_CLIENT
|SSNFLAG_DROP_SERVER
)) )
612 ((p
->is_from_server()) &&
613 (flow
->ssn_state
.session_flags
& SSNFLAG_DROP_SERVER
)) ||
615 ((p
->is_from_client()) &&
616 (flow
->ssn_state
.session_flags
& SSNFLAG_DROP_CLIENT
)) )
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");
629 bool Stream::ignored_flow(Flow
* flow
, Packet
* p
)
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
)) )
636 DetectionEngine::disable_all(p
);
643 static int StreamExpire(Packet
* p
, Flow
* lwssn
)
645 if ( !lwssn
->expired(p
) )
648 if ( HighAvailabilityManager::in_standby(lwssn
) )
651 lwssn
->ssn_state
.session_flags
|= SSNFLAG_TIMEDOUT
;
652 lwssn
->session_state
|= STREAM_STATE_TIMEDOUT
;
657 bool Stream::expired_flow(Flow
* flow
, Packet
* p
)
659 if ( (flow
->session_state
& STREAM_STATE_TIMEDOUT
)
660 || StreamExpire(p
, flow
) )
662 flow
->ssn_state
.session_flags
|= SSNFLAG_TIMEDOUT
;
668 //-------------------------------------------------------------------------
669 // TCP, UDP, ICMP only
670 //-------------------------------------------------------------------------
672 /* This should preferably only be called when ipprotocol is 0. */
673 void Stream::set_ip_protocol(Flow
* flow
)
675 switch (flow
->pkt_type
)
678 flow
->ssn_state
.ipprotocol
= SNORT_PROTO_TCP
;
682 flow
->ssn_state
.ipprotocol
= SNORT_PROTO_UDP
;
686 flow
->ssn_state
.ipprotocol
= SNORT_PROTO_ICMP
;
694 //-------------------------------------------------------------------------
696 //-------------------------------------------------------------------------
698 static bool ok_to_flush(Packet
* p
)
700 if ( p
->packet_flags
& PKT_REBUILT_STREAM
)
703 if ( p
->type() != PktType::TCP
)
709 void Stream::flush_client(Packet
* p
)
711 if ( !ok_to_flush(p
) )
714 if ( p
->is_from_client() )
715 p
->flow
->session
->flush_talker(p
);
717 else if ( p
->is_from_server() )
718 p
->flow
->session
->flush_listener(p
);
721 void Stream::flush_server(Packet
* p
)
723 if ( !ok_to_flush(p
) )
726 if ( p
->is_from_client() )
727 p
->flow
->session
->flush_listener(p
);
729 else if ( p
->is_from_server() )
730 p
->flow
->session
->flush_talker(p
);
733 // return true if added
734 bool Stream::add_flow_alert(
735 Flow
* flow
, Packet
* p
, uint32_t gid
, uint32_t sid
)
740 return flow
->session
->add_alert(p
, gid
, sid
);
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
)
750 return flow
->session
->check_alerted(p
, gid
, sid
);
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
)
758 assert(flow
&& flow
->session
);
759 return flow
->session
->update_alert(p
, gid
, sid
, event_id
, event_second
);
762 void Stream::set_extra_data(
763 Flow
* flow
, Packet
* p
, uint32_t flag
)
765 assert(flow
&& flow
->session
);
766 flow
->session
->set_extra_data(p
, flag
);
769 void Stream::disable_reassembly(Flow
* flow
)
771 assert(flow
&& flow
->session
);
772 return flow
->session
->disable_reassembly(flow
);
775 char Stream::get_reassembly_direction(Flow
* flow
)
777 assert(flow
&& flow
->session
);
778 return flow
->session
->get_reassembly_direction();
781 bool Stream::is_stream_sequenced(Flow
* flow
, uint8_t dir
)
783 assert(flow
&& flow
->session
);
784 return flow
->session
->is_sequenced(dir
);
787 int Stream::missing_in_reassembled(Flow
* flow
, uint8_t dir
)
789 assert(flow
&& flow
->session
);
790 return flow
->session
->missing_in_reassembled(dir
);
793 bool Stream::missed_packets(Flow
* flow
, uint8_t dir
)
795 assert(flow
&& flow
->session
);
796 return flow
->session
->are_packets_missing(dir
);
799 uint16_t Stream::get_mss(Flow
* flow
, bool to_server
)
801 assert(flow
and flow
->session
and flow
->pkt_type
== PktType::TCP
);
803 TcpStreamSession
* tcp_session
= (TcpStreamSession
*)flow
->session
;
804 return tcp_session
->get_mss(to_server
);
807 uint8_t Stream::get_tcp_options_len(Flow
* flow
, bool to_server
)
809 assert(flow
and flow
->session
and flow
->pkt_type
== PktType::TCP
);
811 TcpStreamSession
* tcp_session
= (TcpStreamSession
*)flow
->session
;
812 return tcp_session
->get_tcp_options_len(to_server
);
815 bool Stream::set_packet_action_to_hold(Packet
* p
)
817 if ( !p
or !p
->flow
or !p
->flow
->session
)
820 return p
->flow
->session
->set_packet_action_to_hold(p
);
823 bool Stream::can_set_no_ack_mode(Flow
* flow
)
825 assert(flow
and flow
->session
and flow
->pkt_type
== PktType::TCP
);
827 TcpStreamSession
* tcp_session
= (TcpStreamSession
*)flow
->session
;
828 return tcp_session
->can_set_no_ack();
831 bool Stream::set_no_ack_mode(Flow
* flow
, bool on_off
)
833 assert(flow
and flow
->session
and flow
->pkt_type
== PktType::TCP
);
835 TcpStreamSession
* tcp_session
= (TcpStreamSession
*)flow
->session
;
836 return tcp_session
->set_no_ack(on_off
);
839 void Stream::partial_flush(Flow
* flow
, bool to_server
)
841 if ( flow
->pkt_type
== PktType::TCP
)
844 ((TcpStreamSession
*)flow
->session
)->server
.perform_partial_flush();
846 ((TcpStreamSession
*)flow
->session
)->client
.perform_partial_flush();
850 bool Stream::get_held_pkt_seq(Flow
* flow
, uint32_t& seq
)
852 if (!flow
or !flow
->session
or !(flow
->pkt_type
== PktType::TCP
))
855 TcpStreamSession
* tcp_session
= (TcpStreamSession
*)flow
->session
;
857 if (tcp_session
->held_packet_dir
== SSN_DIR_NONE
)
860 if (tcp_session
->held_packet_dir
== SSN_DIR_FROM_CLIENT
)
862 seq
= tcp_session
->server
.held_pkt_seq
;
863 tcp_session
->held_packet_dir
= SSN_DIR_NONE
;
867 if (tcp_session
->held_packet_dir
== SSN_DIR_FROM_SERVER
)
869 seq
= tcp_session
->client
.held_pkt_seq
;
870 tcp_session
->held_packet_dir
= SSN_DIR_NONE
;
877 //-------------------------------------------------------------------------
879 //-------------------------------------------------------------------------
881 static unsigned stream_pub_id
= 0;
883 void Stream::set_pub_id()
884 { stream_pub_id
= DataBus::get_id(stream_pub_key
); }
886 unsigned Stream::get_pub_id()
887 { return stream_pub_id
; }
889 //-------------------------------------------------------------------------
891 //-------------------------------------------------------------------------
893 #include "catch/snort_catch.h"
894 #include "tcp/test/stream_tcp_test_utils.h"
896 TEST_CASE("Stream API", "[stream_api][stream]")
898 // initialization code here
899 Flow
* flow
= new Flow
;
901 SECTION("set/get ignore direction")
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
) );
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
) );
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
) );
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
) );
924 SECTION("stop inspection")
926 Packet
* pkt
= get_syn_packet(flow
);
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
) );
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
) );
942 SECTION("stop inspection from server - client packet")
944 Packet
* pkt
= get_syn_packet(flow
);
946 Stream::stop_inspection(flow
, pkt
, SSN_DIR_FROM_SERVER
, 0, 0);
947 bool ignored
= Stream::ignored_flow(flow
, pkt
);
953 SECTION("stop inspection from server - server packet")
955 Packet
* pkt
= get_syn_ack_packet(flow
);
957 Stream::stop_inspection(flow
, pkt
, SSN_DIR_FROM_SERVER
, 0, 0);
958 bool ignored
= Stream::ignored_flow(flow
, pkt
);
964 SECTION("stop inspection from client - client packet")
966 Packet
* pkt
= get_syn_packet(flow
);
968 Stream::stop_inspection(flow
, pkt
, SSN_DIR_FROM_CLIENT
, 0, 0);
969 bool ignored
= Stream::ignored_flow(flow
, pkt
);
975 SECTION("stop inspection from client - server packet")
977 Packet
* pkt
= get_syn_ack_packet(flow
);
979 Stream::stop_inspection(flow
, pkt
, SSN_DIR_FROM_CLIENT
, 0, 0);
980 bool ignored
= Stream::ignored_flow(flow
, pkt
);
986 SECTION("stop inspection both - client packet")
988 Packet
* pkt
= get_syn_packet(flow
);
990 Stream::stop_inspection(flow
, pkt
, SSN_DIR_BOTH
, 0, 0);
991 bool ignored
= Stream::ignored_flow(flow
, pkt
);
997 SECTION("stop inspection both - server packet")
999 Packet
* pkt
= get_syn_ack_packet(flow
);
1001 Stream::stop_inspection(flow
, pkt
, SSN_DIR_BOTH
, 0, 0);
1002 bool ignored
= Stream::ignored_flow(flow
, pkt
);
1005 release_packet(pkt
);