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