1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2013-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 "flow.h"
25
26 #include "detection/detection_engine.h"
27 #include "flow/ha.h"
28 #include "flow/session.h"
29 #include "framework/data_bus.h"
30 #include "helpers/bitop.h"
31 #include "ips_options/ips_flowbits.h"
32 #include "memory/memory_cap.h"
33 #include "protocols/packet.h"
34 #include "protocols/tcp.h"
35 #include "sfip/sf_ip.h"
36 #include "utils/stats.h"
37 #include "utils/util.h"
38
39 using namespace snort;
40
Flow()41 Flow::Flow()
42 {
43 constexpr size_t offset = offsetof(Flow, key);
44 // FIXIT-L need a struct to zero here to make future proof
45 memset((uint8_t*)this+offset, 0, sizeof(*this)-offset);
46 }
47
~Flow()48 Flow::~Flow()
49 {
50 term();
51 }
52
init(PktType type)53 void Flow::init(PktType type)
54 {
55 pkt_type = type;
56 bitop = nullptr;
57
58 if ( HighAvailabilityManager::active() )
59 {
60 ha_state = new FlowHAState;
61 previous_ssn_state = ssn_state;
62 }
63 mpls_client.length = 0;
64 mpls_server.length = 0;
65
66 stash = new FlowStash;
67 }
68
term()69 void Flow::term()
70 {
71 if ( !session )
72 return;
73
74 delete session;
75 session = nullptr;
76
77 if ( flow_data )
78 free_flow_data();
79
80 if ( mpls_client.length )
81 delete[] mpls_client.start;
82
83 if ( mpls_server.length )
84 delete[] mpls_server.start;
85
86 if ( bitop )
87 delete bitop;
88
89 if ( ssn_client )
90 {
91 ssn_client->rem_ref();
92 ssn_client = nullptr;
93 }
94
95 if ( ssn_server )
96 {
97 ssn_server->rem_ref();
98 ssn_server = nullptr;
99 }
100
101 if ( clouseau )
102 clouseau->rem_ref();
103
104 if ( gadget )
105 gadget->rem_ref();
106
107 if (assistant_gadget)
108 assistant_gadget->rem_ref();
109
110 if ( data )
111 clear_data();
112
113 if ( ha_state )
114 delete ha_state;
115
116 if (stash)
117 {
118 delete stash;
119 stash = nullptr;
120 }
121 }
122
clean()123 inline void Flow::clean()
124 {
125 if ( mpls_client.length )
126 {
127 delete[] mpls_client.start;
128 mpls_client.length = 0;
129 }
130 if ( mpls_server.length )
131 {
132 delete[] mpls_server.start;
133 mpls_server.length = 0;
134 }
135 if ( bitop )
136 {
137 delete bitop;
138 bitop = nullptr;
139 }
140 filtering_state.clear();
141 }
142
flush(bool do_cleanup)143 void Flow::flush(bool do_cleanup)
144 {
145 if ( session )
146 {
147 DetectionEngine::onload(this);
148
149 if ( do_cleanup )
150 {
151 DetectionEngine::set_next_packet();
152 DetectionEngine de;
153
154 session->flush();
155 de.get_context()->clear_callbacks();
156 }
157 else
158 session->clear();
159 }
160
161 if ( was_blocked() )
162 free_flow_data();
163 }
164
reset(bool do_cleanup)165 void Flow::reset(bool do_cleanup)
166 {
167 if ( session )
168 {
169 DetectionEngine::onload(this);
170
171 if ( do_cleanup )
172 {
173 DetectionEngine::set_next_packet();
174 DetectionEngine de;
175
176 session->cleanup();
177
178 de.get_context()->clear_callbacks();
179 }
180 else
181 session->clear();
182 }
183
184 free_flow_data();
185 clean();
186
187 // FIXIT-M cleanup() winds up calling clear()
188 if ( ssn_client )
189 {
190 ssn_client->rem_ref();
191 ssn_client = nullptr;
192 }
193 if ( ssn_server )
194 {
195 ssn_server->rem_ref();
196 ssn_server = nullptr;
197 }
198 if ( clouseau )
199 clear_clouseau();
200
201 if ( gadget )
202 clear_gadget();
203
204 if ( data )
205 clear_data();
206
207 if ( ha_state )
208 ha_state->reset();
209
210 if ( stash )
211 stash->reset();
212
213 deferred_trust.clear();
214
215 constexpr size_t offset = offsetof(Flow, context_chain);
216 // FIXIT-L need a struct to zero here to make future proof
217 memset((uint8_t*)this+offset, 0, sizeof(Flow)-offset);
218 }
219
restart(bool dump_flow_data)220 void Flow::restart(bool dump_flow_data)
221 {
222 DetectionEngine::onload(this);
223
224 if ( dump_flow_data )
225 free_flow_data();
226
227 clean();
228
229 ssn_state.ignore_direction = 0;
230 ssn_state.session_flags = SSNFLAG_NONE;
231
232 session_state = STREAM_STATE_NONE;
233 expire_time = 0;
234 previous_ssn_state = ssn_state;
235 }
236
clear(bool dump_flow_data)237 void Flow::clear(bool dump_flow_data)
238 {
239 restart(dump_flow_data);
240 set_state(FlowState::SETUP);
241
242 if ( ssn_client )
243 {
244 ssn_client->rem_ref();
245 ssn_client = nullptr;
246 }
247 if ( ssn_server )
248 {
249 ssn_server->rem_ref();
250 ssn_server = nullptr;
251 }
252 if ( clouseau )
253 clear_clouseau();
254
255 if ( gadget )
256 clear_gadget();
257 }
258
trust()259 void Flow::trust()
260 {
261 set_ignore_direction(SSN_DIR_BOTH);
262 set_state(Flow::FlowState::ALLOW);
263 disable_inspection();
264 }
265
set_flow_data(FlowData * fd)266 int Flow::set_flow_data(FlowData* fd)
267 {
268 FlowData* old = get_flow_data(fd->get_id());
269 assert(old != fd);
270
271 if (old)
272 free_flow_data(old);
273
274 fd->prev = nullptr;
275 fd->next = flow_data;
276
277 if ( flow_data )
278 flow_data->prev = fd;
279
280 flow_data = fd;
281 return 0;
282 }
283
get_flow_data(unsigned id) const284 FlowData* Flow::get_flow_data(unsigned id) const
285 {
286 FlowData* fd = flow_data;
287
288 while (fd)
289 {
290 if (fd->get_id() == id)
291 return fd;
292
293 fd = fd->next;
294 }
295 return nullptr;
296 }
297
298 // FIXIT-L: implement doubly linked list with STL to cut down on code we maintain
free_flow_data(FlowData * fd)299 void Flow::free_flow_data(FlowData* fd)
300 {
301 if ( fd == flow_data )
302 {
303 flow_data = fd->next;
304 if ( flow_data )
305 flow_data->prev = nullptr;
306 }
307 else if ( !fd->next )
308 {
309 fd->prev->next = nullptr;
310 }
311 else
312 {
313 fd->prev->next = fd->next;
314 fd->next->prev = fd->prev;
315 }
316 delete fd;
317 }
318
free_flow_data(uint32_t proto)319 void Flow::free_flow_data(uint32_t proto)
320 {
321 FlowData* fd = get_flow_data(proto);
322
323 if ( fd )
324 free_flow_data(fd);
325 }
326
free_flow_data()327 void Flow::free_flow_data()
328 {
329 while (flow_data)
330 {
331 FlowData* tmp = flow_data;
332 flow_data = flow_data->next;
333 delete tmp;
334 }
335 }
336
call_handlers(Packet * p,bool eof)337 void Flow::call_handlers(Packet* p, bool eof)
338 {
339 FlowData* fd = flow_data;
340
341 while (fd)
342 {
343 if ( eof )
344 fd->handle_eof(p);
345 else
346 fd->handle_retransmit(p);
347
348 fd = fd->next;
349 }
350 }
351
markup_packet_flags(Packet * p)352 void Flow::markup_packet_flags(Packet* p)
353 {
354 if ( (ssn_state.session_flags & SSNFLAG_ESTABLISHED) != SSNFLAG_ESTABLISHED )
355 {
356 if ( (ssn_state.session_flags & (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT)) !=
357 (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT) )
358 {
359 p->packet_flags |= PKT_STREAM_UNEST_UNI;
360 }
361 }
362 else
363 {
364 p->packet_flags |= PKT_STREAM_EST;
365
366 if ( p->packet_flags & PKT_STREAM_UNEST_UNI )
367 p->packet_flags ^= PKT_STREAM_UNEST_UNI;
368 }
369 }
370
set_client_initiate(Packet * p)371 void Flow::set_client_initiate(Packet* p)
372 {
373 if (p->pkth->flags & DAQ_PKT_FLAG_REV_FLOW)
374 flags.client_initiated = p->is_from_server();
375 // If we are tracking on syn, client initiated follows from client
376 else if (p->context->conf->track_on_syn())
377 flags.client_initiated = p->is_from_client();
378 // If not tracking on SYN and the packet is a SYN-ACK, assume the SYN did not create a
379 // session and client initiated follows from server
380 else if (p->is_tcp() and p->ptrs.tcph->is_syn_ack())
381 flags.client_initiated = p->is_from_server();
382 // Otherwise, client initiated follows from client
383 else
384 flags.client_initiated = p->is_from_client();
385 }
386
set_direction(Packet * p)387 void Flow::set_direction(Packet* p)
388 {
389 ip::IpApi* ip_api = &p->ptrs.ip_api;
390
391 // FIXIT-M This does not work properly for NAT "real" v6 addresses on top of v4 packet data
392 // (it will only compare a portion of the address)
393 if (ip_api->is_ip4())
394 {
395 if (ip_api->get_src()->fast_eq4(client_ip))
396 {
397 if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
398 p->packet_flags |= PKT_FROM_CLIENT;
399
400 else if (p->ptrs.sp == client_port)
401 p->packet_flags |= PKT_FROM_CLIENT;
402
403 else
404 p->packet_flags |= PKT_FROM_SERVER;
405 }
406 else if (ip_api->get_dst()->fast_eq4(client_ip))
407 {
408 if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
409 p->packet_flags |= PKT_FROM_SERVER;
410
411 else if (p->ptrs.dp == client_port)
412 p->packet_flags |= PKT_FROM_SERVER;
413
414 else
415 p->packet_flags |= PKT_FROM_CLIENT;
416 }
417 }
418 else /* IS_IP6(p) */
419 {
420 if (ip_api->get_src()->fast_eq6(client_ip))
421 {
422 if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
423 p->packet_flags |= PKT_FROM_CLIENT;
424
425 else if (p->ptrs.sp == client_port)
426 p->packet_flags |= PKT_FROM_CLIENT;
427
428 else
429 p->packet_flags |= PKT_FROM_SERVER;
430 }
431 else if (ip_api->get_dst()->fast_eq6(client_ip))
432 {
433 if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
434 p->packet_flags |= PKT_FROM_SERVER;
435
436 else if (p->ptrs.dp == client_port)
437 p->packet_flags |= PKT_FROM_SERVER;
438
439 else
440 p->packet_flags |= PKT_FROM_CLIENT;
441 }
442 }
443 }
444
set_expire(const Packet * p,uint32_t timeout)445 void Flow::set_expire(const Packet* p, uint32_t timeout)
446 {
447 expire_time = (uint64_t)p->pkth->ts.tv_sec + timeout;
448 }
449
expired(const Packet * p)450 bool Flow::expired(const Packet* p)
451 {
452 if ( !expire_time )
453 return false;
454
455 if ( (uint64_t)p->pkth->ts.tv_sec > expire_time )
456 return true;
457
458 return false;
459 }
460
set_ttl(Packet * p,bool client)461 void Flow::set_ttl(Packet* p, bool client)
462 {
463 uint8_t inner_ttl = 0, outer_ttl = 0;
464
465 ip::IpApi outer_ip_api;
466 int8_t tmp = 0;
467 layer::set_outer_ip_api(p, outer_ip_api, tmp);
468
469 /*
470 * If there is only one IP layer, then
471 * outer_ip == inner_ip ==> both are true.
472 *
473 * If there are no IP layers, then
474 * outer_ip.is_valid() == inner_ip.is_valid() == false
475 */
476 if (outer_ip_api.is_ip())
477 {
478 // FIXIT-L do we want more than just the outermost and innermost ttl()?
479 outer_ttl = outer_ip_api.ttl();
480 inner_ttl = p->ptrs.ip_api.ttl();
481 }
482
483 if ( client )
484 {
485 outer_client_ttl = outer_ttl;
486 inner_client_ttl = inner_ttl;
487 }
488 else
489 {
490 outer_server_ttl = outer_ttl;
491 inner_server_ttl = inner_ttl;
492 }
493 }
494
set_mpls_layer_per_dir(Packet * p)495 void Flow::set_mpls_layer_per_dir(Packet* p)
496 {
497 const Layer* mpls_lyr = layer::get_mpls_layer(p);
498
499 if ( !mpls_lyr || !(mpls_lyr->start) )
500 return;
501
502 if ( p->packet_flags & PKT_FROM_CLIENT )
503 {
504 if ( !mpls_client.length )
505 {
506 mpls_client.length = mpls_lyr->length;
507 mpls_client.prot_id = mpls_lyr->prot_id;
508 mpls_client.start = new uint8_t[mpls_lyr->length];
509 memcpy((void *)mpls_client.start, mpls_lyr->start, mpls_lyr->length);
510 }
511 }
512 else
513 {
514 if ( !mpls_server.length )
515 {
516 mpls_server.length = mpls_lyr->length;
517 mpls_server.prot_id = mpls_lyr->prot_id;
518 mpls_server.start = new uint8_t[mpls_lyr->length];
519 memcpy((void *)mpls_server.start, mpls_lyr->start, mpls_lyr->length);
520 }
521 }
522 }
523
get_mpls_layer_per_dir(bool client)524 Layer Flow::get_mpls_layer_per_dir(bool client)
525 {
526 if ( client )
527 return mpls_client;
528 else
529 return mpls_server;
530 }
531
is_pdu_inorder(uint8_t dir)532 bool Flow::is_pdu_inorder(uint8_t dir)
533 {
534 return ( (session != nullptr) && session->is_sequenced(dir)
535 && (session->missing_in_reassembled(dir) == SSN_MISSING_NONE)
536 && !(ssn_state.session_flags & SSNFLAG_MIDSTREAM));
537 }
538
is_direction_aborted(bool from_client) const539 bool Flow::is_direction_aborted(bool from_client) const
540 {
541 const uint32_t session_flags = get_session_flags();
542
543 if (from_client)
544 return (session_flags & SSNFLAG_ABORT_SERVER);
545
546 return (session_flags & SSNFLAG_ABORT_CLIENT);
547 }
548
set_service(Packet * pkt,const char * new_service)549 void Flow::set_service(Packet* pkt, const char* new_service)
550 {
551 service = new_service;
552 DataBus::publish(FLOW_SERVICE_CHANGE_EVENT, pkt);
553 }
554
swap_roles()555 void Flow::swap_roles()
556 {
557 std::swap(flowstats.client_pkts, flowstats.server_pkts);
558 std::swap(flowstats.client_bytes, flowstats.server_bytes);
559 std::swap(mpls_client, mpls_server);
560 std::swap(client_ip, server_ip);
561 std::swap(client_intf, server_intf);
562 std::swap(client_group, server_group);
563 std::swap(client_port, server_port);
564 std::swap(inner_client_ttl, inner_server_ttl);
565 std::swap(outer_client_ttl, outer_server_ttl);
566 flags.client_initiated = !flags.client_initiated;
567 }
568