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