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