/src/suricata7/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-var.h" |
33 | | #include "app-layer.h" |
34 | | |
35 | | #include "util-var.h" |
36 | | #include "util-debug.h" |
37 | | #include "util-macset.h" |
38 | | #include "flow-storage.h" |
39 | | |
40 | | #include "detect.h" |
41 | | #include "detect-engine-state.h" |
42 | | |
43 | | #include "decode-icmpv4.h" |
44 | | |
45 | | #include "util-validate.h" |
46 | | |
47 | | /** \brief allocate a flow |
48 | | * |
49 | | * We check against the memuse counter. If it passes that check we increment |
50 | | * the counter first, then we try to alloc. |
51 | | * |
52 | | * \retval f the flow or NULL on out of memory |
53 | | */ |
54 | | Flow *FlowAlloc(void) |
55 | 1.46M | { |
56 | 1.46M | Flow *f; |
57 | 1.46M | size_t size = sizeof(Flow) + FlowStorageSize(); |
58 | | |
59 | 1.46M | if (!(FLOW_CHECK_MEMCAP(size))) { |
60 | 0 | return NULL; |
61 | 0 | } |
62 | | |
63 | 1.46M | (void) SC_ATOMIC_ADD(flow_memuse, size); |
64 | | |
65 | 1.46M | f = SCMalloc(size); |
66 | 1.46M | if (unlikely(f == NULL)) { |
67 | 0 | (void)SC_ATOMIC_SUB(flow_memuse, size); |
68 | 0 | return NULL; |
69 | 0 | } |
70 | 1.46M | memset(f, 0, size); |
71 | | |
72 | | /* coverity[missing_lock] */ |
73 | 1.46M | FLOW_INITIALIZE(f); |
74 | 1.46M | return f; |
75 | 1.46M | } |
76 | | |
77 | | |
78 | | /** |
79 | | * \brief cleanup & free the memory of a flow |
80 | | * |
81 | | * \param f flow to clear & destroy |
82 | | */ |
83 | | void FlowFree(Flow *f) |
84 | 786k | { |
85 | 786k | FLOW_DESTROY(f); |
86 | 786k | SCFree(f); |
87 | | |
88 | 786k | size_t size = sizeof(Flow) + FlowStorageSize(); |
89 | 786k | (void) SC_ATOMIC_SUB(flow_memuse, size); |
90 | 786k | } |
91 | | |
92 | | /** |
93 | | * \brief Function to map the protocol to the defined FLOW_PROTO_* enumeration. |
94 | | * |
95 | | * \param proto protocol which is needed to be mapped |
96 | | */ |
97 | | |
98 | | uint8_t FlowGetProtoMapping(uint8_t proto) |
99 | 6.08G | { |
100 | 6.08G | switch (proto) { |
101 | 3.92G | case IPPROTO_TCP: |
102 | 3.92G | return FLOW_PROTO_TCP; |
103 | 2.15G | case IPPROTO_UDP: |
104 | 2.15G | return FLOW_PROTO_UDP; |
105 | 54.1k | case IPPROTO_ICMP: |
106 | 54.1k | return FLOW_PROTO_ICMP; |
107 | 167k | default: |
108 | 167k | return FLOW_PROTO_DEFAULT; |
109 | 6.08G | } |
110 | 6.08G | } |
111 | | |
112 | | uint8_t FlowGetReverseProtoMapping(uint8_t rproto) |
113 | 5.51M | { |
114 | 5.51M | switch (rproto) { |
115 | 1.83M | case FLOW_PROTO_TCP: |
116 | 1.83M | return IPPROTO_TCP; |
117 | 1.83M | case FLOW_PROTO_UDP: |
118 | 1.83M | return IPPROTO_UDP; |
119 | 1.83M | case FLOW_PROTO_ICMP: |
120 | 1.83M | return IPPROTO_ICMP; |
121 | 0 | default: |
122 | 0 | exit(EXIT_FAILURE); |
123 | 5.51M | } |
124 | 5.51M | } |
125 | | |
126 | | static inline void FlowSetICMPv4CounterPart(Flow *f) |
127 | 4.91k | { |
128 | 4.91k | int ctype = ICMPv4GetCounterpart(f->icmp_s.type); |
129 | 4.91k | if (ctype == -1) |
130 | 2.21k | return; |
131 | | |
132 | 2.70k | f->icmp_d.type = (uint8_t)ctype; |
133 | 2.70k | } |
134 | | |
135 | | static inline void FlowSetICMPv6CounterPart(Flow *f) |
136 | 17.9k | { |
137 | 17.9k | int ctype = ICMPv6GetCounterpart(f->icmp_s.type); |
138 | 17.9k | if (ctype == -1) |
139 | 10.2k | return; |
140 | | |
141 | 7.65k | f->icmp_d.type = (uint8_t)ctype; |
142 | 7.65k | } |
143 | | |
144 | | /* initialize the flow from the first packet |
145 | | * we see from it. */ |
146 | | void FlowInit(ThreadVars *tv, Flow *f, const Packet *p) |
147 | 243k | { |
148 | 243k | SCEnter(); |
149 | 243k | SCLogDebug("flow %p", f); |
150 | | |
151 | 243k | f->proto = p->proto; |
152 | 243k | f->recursion_level = p->recursion_level; |
153 | 243k | memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id)); |
154 | 243k | f->vlan_idx = p->vlan_idx; |
155 | | |
156 | 243k | f->thread_id[0] = (FlowThreadId)tv->id; |
157 | | |
158 | 243k | f->livedev = p->livedev; |
159 | | |
160 | 243k | if (PKT_IS_IPV4(p)) { |
161 | 212k | FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, &f->src); |
162 | 212k | FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, &f->dst); |
163 | 212k | f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_IPTTL((p)); |
164 | 212k | f->flags |= FLOW_IPV4; |
165 | 212k | } else if (PKT_IS_IPV6(p)) { |
166 | 30.4k | FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, &f->src); |
167 | 30.4k | FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, &f->dst); |
168 | 30.4k | f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_HLIM((p)); |
169 | 30.4k | f->flags |= FLOW_IPV6; |
170 | 30.4k | } else { |
171 | 0 | SCLogDebug("neither IPv4 or IPv6, weird"); |
172 | 0 | DEBUG_VALIDATE_BUG_ON(1); |
173 | 0 | } |
174 | | |
175 | 243k | if (p->tcph != NULL) { /* XXX MACRO */ |
176 | 204k | SET_TCP_SRC_PORT(p,&f->sp); |
177 | 204k | SET_TCP_DST_PORT(p,&f->dp); |
178 | 204k | } else if (p->udph != NULL) { /* XXX MACRO */ |
179 | 25.9k | SET_UDP_SRC_PORT(p,&f->sp); |
180 | 25.9k | SET_UDP_DST_PORT(p,&f->dp); |
181 | 25.9k | } else if (p->icmpv4h != NULL) { |
182 | 2.06k | f->icmp_s.type = p->icmp_s.type; |
183 | 2.06k | f->icmp_s.code = p->icmp_s.code; |
184 | 2.06k | FlowSetICMPv4CounterPart(f); |
185 | 10.9k | } else if (p->icmpv6h != NULL) { |
186 | 7.56k | f->icmp_s.type = p->icmp_s.type; |
187 | 7.56k | f->icmp_s.code = p->icmp_s.code; |
188 | 7.56k | FlowSetICMPv6CounterPart(f); |
189 | 7.56k | } else if (p->sctph != NULL) { /* XXX MACRO */ |
190 | 379 | SET_SCTP_SRC_PORT(p,&f->sp); |
191 | 379 | SET_SCTP_DST_PORT(p,&f->dp); |
192 | 3.03k | } else if (p->esph != NULL) { |
193 | 2.93k | f->esp.spi = ESP_GET_SPI(p); |
194 | 2.93k | } else { |
195 | | /* nothing to do for this IP proto. */ |
196 | 107 | SCLogDebug("no special setup for IP proto %u", p->proto); |
197 | 107 | } |
198 | 243k | f->startts = p->ts; |
199 | | |
200 | 243k | f->protomap = FlowGetProtoMapping(f->proto); |
201 | 243k | f->timeout_policy = FlowGetTimeoutPolicy(f); |
202 | 243k | const uint32_t timeout_at = (uint32_t)SCTIME_SECS(f->startts) + f->timeout_policy; |
203 | 243k | f->timeout_at = timeout_at; |
204 | | |
205 | 243k | if (MacSetFlowStorageEnabled()) { |
206 | 0 | DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL); |
207 | 0 | MacSet *ms = MacSetInit(10); |
208 | 0 | FlowSetStorageById(f, MacSetGetFlowStorageID(), ms); |
209 | 0 | } |
210 | | |
211 | 243k | SCReturn; |
212 | 243k | } |
213 | | |
214 | | FlowStorageId g_bypass_info_id = { .id = -1 }; |
215 | | |
216 | | FlowStorageId GetFlowBypassInfoID(void) |
217 | 1.03M | { |
218 | 1.03M | return g_bypass_info_id; |
219 | 1.03M | } |
220 | | |
221 | | static void FlowBypassFree(void *x) |
222 | 0 | { |
223 | 0 | FlowBypassInfo *fb = (FlowBypassInfo *) x; |
224 | |
|
225 | 0 | if (fb == NULL) |
226 | 0 | return; |
227 | | |
228 | 0 | if (fb->bypass_data && fb->BypassFree) { |
229 | 0 | fb->BypassFree(fb->bypass_data); |
230 | 0 | } |
231 | 0 | SCFree(fb); |
232 | 0 | } |
233 | | |
234 | | void RegisterFlowBypassInfo(void) |
235 | 74 | { |
236 | 74 | g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *), |
237 | 74 | NULL, FlowBypassFree); |
238 | 74 | } |
239 | | |
240 | | void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec) |
241 | 4 | { |
242 | 20 | for (int i = 0; i < FLOW_STATE_SIZE; i++) { |
243 | 16 | const char *name = NULL; |
244 | 16 | if (i == FLOW_STATE_NEW) { |
245 | 4 | name = "flow.end.state.new"; |
246 | 12 | } else if (i == FLOW_STATE_ESTABLISHED) { |
247 | 4 | name = "flow.end.state.established"; |
248 | 8 | } else if (i == FLOW_STATE_CLOSED) { |
249 | 4 | name = "flow.end.state.closed"; |
250 | 4 | } else if (i == FLOW_STATE_LOCAL_BYPASSED) { |
251 | 4 | name = "flow.end.state.local_bypassed"; |
252 | | #ifdef CAPTURE_OFFLOAD |
253 | | } else if (i == FLOW_STATE_CAPTURE_BYPASSED) { |
254 | | name = "flow.end.state.capture_bypassed"; |
255 | | #endif |
256 | 4 | } |
257 | 16 | if (name) { |
258 | 16 | fec->flow_state[i] = StatsRegisterCounter(name, t); |
259 | 16 | } |
260 | 16 | } |
261 | | |
262 | 52 | for (enum TcpState i = TCP_NONE; i <= TCP_CLOSED; i++) { |
263 | 48 | const char *name = NULL; |
264 | 48 | switch (i) { |
265 | 4 | case TCP_NONE: |
266 | 4 | name = "flow.end.tcp_state.none"; |
267 | 4 | break; |
268 | 4 | case TCP_SYN_SENT: |
269 | 4 | name = "flow.end.tcp_state.syn_sent"; |
270 | 4 | break; |
271 | 4 | case TCP_SYN_RECV: |
272 | 4 | name = "flow.end.tcp_state.syn_recv"; |
273 | 4 | break; |
274 | 4 | case TCP_ESTABLISHED: |
275 | 4 | name = "flow.end.tcp_state.established"; |
276 | 4 | break; |
277 | 4 | case TCP_FIN_WAIT1: |
278 | 4 | name = "flow.end.tcp_state.fin_wait1"; |
279 | 4 | break; |
280 | 4 | case TCP_FIN_WAIT2: |
281 | 4 | name = "flow.end.tcp_state.fin_wait2"; |
282 | 4 | break; |
283 | 4 | case TCP_TIME_WAIT: |
284 | 4 | name = "flow.end.tcp_state.time_wait"; |
285 | 4 | break; |
286 | 4 | case TCP_LAST_ACK: |
287 | 4 | name = "flow.end.tcp_state.last_ack"; |
288 | 4 | break; |
289 | 4 | case TCP_CLOSE_WAIT: |
290 | 4 | name = "flow.end.tcp_state.close_wait"; |
291 | 4 | break; |
292 | 4 | case TCP_CLOSING: |
293 | 4 | name = "flow.end.tcp_state.closing"; |
294 | 4 | break; |
295 | 4 | case TCP_CLOSED: |
296 | 4 | name = "flow.end.tcp_state.closed"; |
297 | 4 | break; |
298 | 48 | } |
299 | | |
300 | 48 | fec->flow_tcp_state[i] = StatsRegisterCounter(name, t); |
301 | 48 | } |
302 | 4 | fec->flow_tcp_liberal = StatsRegisterCounter("flow.end.tcp_liberal", t); |
303 | 4 | } |