/src/suricata8/src/flow-util.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2013 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Victor Julien <victor@inliniac.net> |
22 | | * |
23 | | * Flow utility functions |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "threads.h" |
28 | | |
29 | | #include "flow.h" |
30 | | #include "flow-private.h" |
31 | | #include "flow-util.h" |
32 | | #include "flow-callbacks.h" |
33 | | #include "flow-var.h" |
34 | | #include "app-layer.h" |
35 | | |
36 | | #include "util-var.h" |
37 | | #include "util-debug.h" |
38 | | #include "util-macset.h" |
39 | | #include "util-flow-rate.h" |
40 | | #include "flow-storage.h" |
41 | | |
42 | | #include "detect.h" |
43 | | #include "detect-engine-state.h" |
44 | | |
45 | | #include "decode-icmpv4.h" |
46 | | |
47 | | #include "util-validate.h" |
48 | | |
49 | | /** \brief allocate a flow |
50 | | * |
51 | | * We check against the memuse counter. If it passes that check we increment |
52 | | * the counter first, then we try to alloc. |
53 | | * |
54 | | * \retval f the flow or NULL on out of memory |
55 | | */ |
56 | | Flow *FlowAlloc(void) |
57 | 481k | { |
58 | 481k | Flow *f; |
59 | 481k | size_t size = sizeof(Flow) + FlowStorageSize(); |
60 | | |
61 | 481k | if (!(FLOW_CHECK_MEMCAP(size))) { |
62 | 0 | return NULL; |
63 | 0 | } |
64 | | |
65 | 481k | (void) SC_ATOMIC_ADD(flow_memuse, size); |
66 | | |
67 | 481k | f = SCCalloc(1, size); |
68 | 481k | if (unlikely(f == NULL)) { |
69 | 0 | (void)SC_ATOMIC_SUB(flow_memuse, size); |
70 | 0 | return NULL; |
71 | 0 | } |
72 | | |
73 | | /* coverity[missing_lock] */ |
74 | 481k | FLOW_INITIALIZE(f); |
75 | 481k | return f; |
76 | 481k | } |
77 | | |
78 | | |
79 | | /** |
80 | | * \brief cleanup & free the memory of a flow |
81 | | * |
82 | | * \param f flow to clear & destroy |
83 | | */ |
84 | | void FlowFree(Flow *f) |
85 | 437k | { |
86 | 437k | FLOW_DESTROY(f); |
87 | 437k | SCFree(f); |
88 | | |
89 | 437k | size_t size = sizeof(Flow) + FlowStorageSize(); |
90 | 437k | (void) SC_ATOMIC_SUB(flow_memuse, size); |
91 | 437k | } |
92 | | |
93 | | /** |
94 | | * \brief Function to map the protocol to the defined FLOW_PROTO_* enumeration. |
95 | | * |
96 | | * \param proto protocol which is needed to be mapped |
97 | | */ |
98 | | |
99 | | uint8_t FlowGetProtoMapping(uint8_t proto) |
100 | 3.33G | { |
101 | 3.33G | switch (proto) { |
102 | 2.43G | case IPPROTO_TCP: |
103 | 2.43G | return FLOW_PROTO_TCP; |
104 | 898M | case IPPROTO_UDP: |
105 | 898M | return FLOW_PROTO_UDP; |
106 | 10.8k | case IPPROTO_ICMP: |
107 | 10.8k | return FLOW_PROTO_ICMP; |
108 | 41.9k | default: |
109 | 41.9k | return FLOW_PROTO_DEFAULT; |
110 | 3.33G | } |
111 | 3.33G | } |
112 | | |
113 | | uint8_t FlowGetReverseProtoMapping(uint8_t rproto) |
114 | 4.22M | { |
115 | 4.22M | switch (rproto) { |
116 | 1.40M | case FLOW_PROTO_TCP: |
117 | 1.40M | return IPPROTO_TCP; |
118 | 1.40M | case FLOW_PROTO_UDP: |
119 | 1.40M | return IPPROTO_UDP; |
120 | 1.40M | case FLOW_PROTO_ICMP: |
121 | 1.40M | return IPPROTO_ICMP; |
122 | 0 | default: |
123 | 0 | exit(EXIT_FAILURE); |
124 | 4.22M | } |
125 | 4.22M | } |
126 | | |
127 | | static inline void FlowSetICMPv4CounterPart(Flow *f) |
128 | 5.57k | { |
129 | 5.57k | int ctype = ICMPv4GetCounterpart(f->icmp_s.type); |
130 | 5.57k | if (ctype == -1) |
131 | 2.51k | return; |
132 | | |
133 | 3.06k | f->icmp_d.type = (uint8_t)ctype; |
134 | 3.06k | } |
135 | | |
136 | | static inline void FlowSetICMPv6CounterPart(Flow *f) |
137 | 17.9k | { |
138 | 17.9k | int ctype = ICMPv6GetCounterpart(f->icmp_s.type); |
139 | 17.9k | if (ctype == -1) |
140 | 11.1k | return; |
141 | | |
142 | 6.75k | f->icmp_d.type = (uint8_t)ctype; |
143 | 6.75k | } |
144 | | |
145 | | /* initialize the flow from the first packet |
146 | | * we see from it. */ |
147 | | void FlowInit(ThreadVars *tv, Flow *f, const Packet *p) |
148 | 485k | { |
149 | 485k | SCEnter(); |
150 | 485k | SCLogDebug("flow %p", f); |
151 | | |
152 | 485k | f->proto = p->proto; |
153 | 485k | f->recursion_level = p->recursion_level; |
154 | 485k | memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id)); |
155 | 485k | f->vlan_idx = p->vlan_idx; |
156 | | |
157 | 485k | f->thread_id[0] = (FlowThreadId)tv->id; |
158 | | |
159 | 485k | f->livedev = p->livedev; |
160 | | |
161 | 485k | if (PacketIsIPv4(p)) { |
162 | 411k | const IPV4Hdr *ip4h = PacketGetIPv4(p); |
163 | 411k | FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(ip4h, &f->src); |
164 | 411k | FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(ip4h, &f->dst); |
165 | 411k | f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_RAW_IPTTL(ip4h); |
166 | 411k | f->flags |= FLOW_IPV4; |
167 | 411k | } else if (PacketIsIPv6(p)) { |
168 | 74.4k | const IPV6Hdr *ip6h = PacketGetIPv6(p); |
169 | 74.4k | FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(ip6h, &f->src); |
170 | 74.4k | FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(ip6h, &f->dst); |
171 | 74.4k | f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_RAW_HLIM(ip6h); |
172 | 74.4k | f->flags |= FLOW_IPV6; |
173 | 74.4k | } else { |
174 | 0 | SCLogDebug("neither IPv4 or IPv6, weird"); |
175 | 0 | DEBUG_VALIDATE_BUG_ON(1); |
176 | 0 | } |
177 | | |
178 | 485k | if (PacketIsTCP(p) || PacketIsUDP(p)) { |
179 | 459k | f->sp = p->sp; |
180 | 459k | f->dp = p->dp; |
181 | 459k | } else if (PacketIsICMPv4(p)) { |
182 | 5.57k | f->icmp_s.type = p->icmp_s.type; |
183 | 5.57k | f->icmp_s.code = p->icmp_s.code; |
184 | 5.57k | FlowSetICMPv4CounterPart(f); |
185 | 21.1k | } else if (PacketIsICMPv6(p)) { |
186 | 17.9k | f->icmp_s.type = p->icmp_s.type; |
187 | 17.9k | f->icmp_s.code = p->icmp_s.code; |
188 | 17.9k | FlowSetICMPv6CounterPart(f); |
189 | 17.9k | } else if (PacketIsSCTP(p)) { |
190 | 856 | f->sp = p->sp; |
191 | 856 | f->dp = p->dp; |
192 | 2.36k | } else if (PacketIsESP(p)) { |
193 | 926 | f->esp.spi = ESP_GET_SPI(PacketGetESP(p)); |
194 | 1.44k | } else { |
195 | | /* nothing to do for this IP proto. */ |
196 | 1.44k | SCLogDebug("no special setup for IP proto %u", p->proto); |
197 | 1.44k | } |
198 | 485k | f->startts = p->ts; |
199 | | |
200 | 485k | f->protomap = FlowGetProtoMapping(f->proto); |
201 | 485k | f->timeout_policy = FlowGetTimeoutPolicy(f); |
202 | | |
203 | 485k | if (MacSetFlowStorageEnabled()) { |
204 | 0 | DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL); |
205 | 0 | MacSet *ms = MacSetInit(10); |
206 | 0 | FlowSetStorageById(f, MacSetGetFlowStorageID(), ms); |
207 | 0 | } |
208 | | |
209 | 485k | if (FlowRateStorageEnabled()) { |
210 | 0 | DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, FlowRateGetStorageID()) != NULL); |
211 | 0 | FlowRateStore *frs = FlowRateStoreInit(); |
212 | 0 | FlowSetStorageById(f, FlowRateGetStorageID(), frs); |
213 | 0 | } |
214 | | |
215 | 485k | SCFlowRunInitCallbacks(tv, f, p); |
216 | | |
217 | 485k | SCReturn; |
218 | 485k | } |
219 | | |
220 | | FlowStorageId g_bypass_info_id = { .id = -1 }; |
221 | | |
222 | | FlowStorageId GetFlowBypassInfoID(void) |
223 | 926k | { |
224 | 926k | return g_bypass_info_id; |
225 | 926k | } |
226 | | |
227 | | static void FlowBypassFree(void *x) |
228 | 0 | { |
229 | 0 | FlowBypassInfo *fb = (FlowBypassInfo *) x; |
230 | |
|
231 | 0 | if (fb == NULL) |
232 | 0 | return; |
233 | | |
234 | 0 | if (fb->bypass_data && fb->BypassFree) { |
235 | 0 | fb->BypassFree(fb->bypass_data); |
236 | 0 | } |
237 | 0 | SCFree(fb); |
238 | 0 | } |
239 | | |
240 | | void RegisterFlowBypassInfo(void) |
241 | 11 | { |
242 | 11 | g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *), |
243 | 11 | NULL, FlowBypassFree); |
244 | 11 | } |
245 | | |
246 | | void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec) |
247 | 5 | { |
248 | 25 | for (int i = 0; i < FLOW_STATE_SIZE; i++) { |
249 | 20 | const char *name = NULL; |
250 | 20 | if (i == FLOW_STATE_NEW) { |
251 | 5 | name = "flow.end.state.new"; |
252 | 15 | } else if (i == FLOW_STATE_ESTABLISHED) { |
253 | 5 | name = "flow.end.state.established"; |
254 | 10 | } else if (i == FLOW_STATE_CLOSED) { |
255 | 5 | name = "flow.end.state.closed"; |
256 | 5 | } else if (i == FLOW_STATE_LOCAL_BYPASSED) { |
257 | 5 | name = "flow.end.state.local_bypassed"; |
258 | | #ifdef CAPTURE_OFFLOAD |
259 | | } else if (i == FLOW_STATE_CAPTURE_BYPASSED) { |
260 | | name = "flow.end.state.capture_bypassed"; |
261 | | #endif |
262 | 5 | } |
263 | 20 | if (name) { |
264 | 20 | fec->flow_state[i] = StatsRegisterCounter(name, t); |
265 | 20 | } |
266 | 20 | } |
267 | | |
268 | 65 | for (enum TcpState i = TCP_NONE; i <= TCP_CLOSED; i++) { |
269 | 60 | const char *name = NULL; |
270 | 60 | switch (i) { |
271 | 5 | case TCP_NONE: |
272 | 5 | name = "flow.end.tcp_state.none"; |
273 | 5 | break; |
274 | 5 | case TCP_SYN_SENT: |
275 | 5 | name = "flow.end.tcp_state.syn_sent"; |
276 | 5 | break; |
277 | 5 | case TCP_SYN_RECV: |
278 | 5 | name = "flow.end.tcp_state.syn_recv"; |
279 | 5 | break; |
280 | 5 | case TCP_ESTABLISHED: |
281 | 5 | name = "flow.end.tcp_state.established"; |
282 | 5 | break; |
283 | 5 | case TCP_FIN_WAIT1: |
284 | 5 | name = "flow.end.tcp_state.fin_wait1"; |
285 | 5 | break; |
286 | 5 | case TCP_FIN_WAIT2: |
287 | 5 | name = "flow.end.tcp_state.fin_wait2"; |
288 | 5 | break; |
289 | 5 | case TCP_TIME_WAIT: |
290 | 5 | name = "flow.end.tcp_state.time_wait"; |
291 | 5 | break; |
292 | 5 | case TCP_LAST_ACK: |
293 | 5 | name = "flow.end.tcp_state.last_ack"; |
294 | 5 | break; |
295 | 5 | case TCP_CLOSE_WAIT: |
296 | 5 | name = "flow.end.tcp_state.close_wait"; |
297 | 5 | break; |
298 | 5 | case TCP_CLOSING: |
299 | 5 | name = "flow.end.tcp_state.closing"; |
300 | 5 | break; |
301 | 5 | case TCP_CLOSED: |
302 | 5 | name = "flow.end.tcp_state.closed"; |
303 | 5 | break; |
304 | 60 | } |
305 | | |
306 | 60 | fec->flow_tcp_state[i] = StatsRegisterCounter(name, t); |
307 | 60 | } |
308 | 5 | fec->flow_tcp_liberal = StatsRegisterCounter("flow.end.tcp_liberal", t); |
309 | 5 | } |