1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // tcp_segment.cc author davis mcpherson <davmcphe@cisco.com>
20 // Created on: Sep 21, 2015
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "tcp_segment_node.h"
27
28 #include "main/thread.h"
29 #include "memory/memory_cap.h"
30 #include "utils/util.h"
31
32 #include "segment_overlap_editor.h"
33 #include "tcp_module.h"
34
35 #define USE_RESERVE
36 #ifdef USE_RESERVE
37 static THREAD_LOCAL TcpSegmentNode* reserved = nullptr;
38 static THREAD_LOCAL unsigned reserve_sz = 0;
39
40 static constexpr unsigned num_res = 4096;
41 static constexpr unsigned res_min = 1024;
42 static constexpr unsigned res_max = 1460;
43 #endif
44
setup()45 void TcpSegmentNode::setup()
46 {
47 #ifdef USE_RESERVE
48 reserved = nullptr;
49 reserve_sz = 0;
50 #endif
51 }
52
clear()53 void TcpSegmentNode::clear()
54 {
55 #ifdef USE_RESERVE
56 while ( reserved )
57 {
58 TcpSegmentNode* tsn = reserved;
59 reserved = reserved->next;
60 tcpStats.mem_in_use -= tsn->size;
61 snort_free(tsn);
62 }
63 reserve_sz = 0;
64 #endif
65 }
66
67 //-------------------------------------------------------------------------
68 // TcpSegment stuff
69 //-------------------------------------------------------------------------
70
create(const struct timeval & tv,const uint8_t * payload,uint16_t len)71 TcpSegmentNode* TcpSegmentNode::create(
72 const struct timeval& tv, const uint8_t* payload, uint16_t len)
73 {
74 TcpSegmentNode* tsn;
75
76 #ifdef USE_RESERVE
77 if ( reserved and len > res_min and len <= res_max )
78 {
79 tsn = reserved;
80 reserved = tsn->next;
81 --reserve_sz;
82 }
83 else
84 #endif
85 {
86 size_t size = sizeof(*tsn) + len;
87 tsn = (TcpSegmentNode*)snort_alloc(size);
88 tsn->size = len;
89 tcpStats.mem_in_use += len;
90 }
91 tsn->tv = tv;
92 tsn->i_len = tsn->c_len = len;
93 memcpy(tsn->data, payload, len);
94
95 tsn->prev = tsn->next = nullptr;
96 tsn->i_seq = tsn->c_seq = 0;
97 tsn->offset = 0;
98 tsn->ts = 0;
99
100 return tsn;
101 }
102
init(const TcpSegmentDescriptor & tsd)103 TcpSegmentNode* TcpSegmentNode::init(const TcpSegmentDescriptor& tsd)
104 {
105 return create(tsd.get_pkt()->pkth->ts, tsd.get_pkt()->data, tsd.get_len());
106 }
107
init(TcpSegmentNode & tns)108 TcpSegmentNode* TcpSegmentNode::init(TcpSegmentNode& tns)
109 {
110 return create(tns.tv, tns.payload(), tns.c_len);
111 }
112
term()113 void TcpSegmentNode::term()
114 {
115 #ifdef USE_RESERVE
116 if ( size == res_max and reserve_sz < num_res )
117 {
118 next = reserved;
119 reserved = this;
120 reserve_sz++;
121 }
122 else
123 #endif
124 {
125 tcpStats.mem_in_use -= size;
126 snort_free(this);
127 }
128 tcpStats.segs_released++;
129 }
130
is_retransmit(const uint8_t * rdata,uint16_t rsize,uint32_t rseq,uint16_t orig_dsize,bool * full_retransmit)131 bool TcpSegmentNode::is_retransmit(const uint8_t* rdata, uint16_t rsize,
132 uint32_t rseq, uint16_t orig_dsize, bool *full_retransmit)
133 {
134 // retransmit must have same payload at same place
135 if ( !SEQ_EQ(i_seq, rseq) )
136 return false;
137
138 if ( orig_dsize == c_len )
139 {
140 uint16_t cmp_len = ( c_len <= rsize ) ? c_len : rsize;
141 if ( !memcmp(data, rdata, cmp_len) )
142 return true;
143 }
144 //Checking for a possible split of segment in which case
145 //we compare complete data of the segment to find a retransmission
146 else if ( (orig_dsize == rsize) and !memcmp(data, rdata, rsize) )
147 {
148 if ( full_retransmit )
149 *full_retransmit = true;
150 return true;
151 }
152
153 return false;
154 }
155