/src/ndpi/example/reader_util.c
Line | Count | Source |
1 | | /* |
2 | | * reader_util.c |
3 | | * |
4 | | * Copyright (C) 2011-25 - ntop.org |
5 | | * |
6 | | * This file is part of nDPI, an open source deep packet inspection |
7 | | * library based on the OpenDPI and PACE technology by ipoque GmbH |
8 | | * |
9 | | * nDPI is free software: you can redistribute it and/or modify |
10 | | * it under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation, either version 3 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * nDPI is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with nDPI. If not, see <http://www.gnu.org/licenses/>. |
21 | | * |
22 | | */ |
23 | | |
24 | | #include "ndpi_config.h" |
25 | | #include "ndpi_api.h" |
26 | | |
27 | | #include <stdlib.h> |
28 | | #include <math.h> |
29 | | #include <float.h> |
30 | | |
31 | | #ifdef WIN32 |
32 | | #include <winsock2.h> /* winsock.h is included automatically */ |
33 | | #include <windows.h> |
34 | | #include <ws2tcpip.h> |
35 | | #include <process.h> |
36 | | #include <io.h> |
37 | | #ifndef DISABLE_NPCAP |
38 | | #include <ip6_misc.h> |
39 | | #endif |
40 | | #else |
41 | | #include <unistd.h> |
42 | | #include <netinet/in.h> |
43 | | #include <netinet/ip.h> |
44 | | #endif |
45 | | #include <assert.h> |
46 | | #include <sys/stat.h> |
47 | | |
48 | | #include "reader_util.h" |
49 | | |
50 | 51.0k | #define SNAP 0XAA |
51 | 49.3k | #define BSTP 0x42 /* Bridge Spanning Tree Protocol */ |
52 | | |
53 | | /* Keep last 32 packets */ |
54 | 1.09M | #define DATA_ANALUYSIS_SLIDING_WINDOW 32 |
55 | | |
56 | | /* mask for FCF */ |
57 | 1.85k | #define WIFI_DATA 0x2 /* 0000 0010 */ |
58 | 1.85k | #define FCF_TYPE(fc) (((fc) >> 2) & 0x3) /* 0000 0011 = 0x3 */ |
59 | | #define FCF_SUBTYPE(fc) (((fc) >> 4) & 0xF) /* 0000 1111 = 0xF */ |
60 | 4.21k | #define FCF_TO_DS(fc) ((fc) & 0x0100) |
61 | 1.61k | #define FCF_FROM_DS(fc) ((fc) & 0x0200) |
62 | | |
63 | | /* mask for Bad FCF presence */ |
64 | 5.02k | #define BAD_FCS 0x50 /* 0101 0000 */ |
65 | | |
66 | 513k | #define GTP_U_V1_PORT 2152 |
67 | 474k | #define NDPI_CAPWAP_DATA_PORT 5247 |
68 | 476k | #define TZSP_PORT 37008 |
69 | | |
70 | | #ifndef DLT_LINUX_SLL |
71 | | #define DLT_LINUX_SLL 113 |
72 | | #endif |
73 | | |
74 | | #include "ndpi_main.h" |
75 | | #include "reader_util.h" |
76 | | #include "ndpi_classify.h" |
77 | | |
78 | | extern u_int8_t enable_flow_stats, enable_payload_analyzer; |
79 | | extern u_int8_t verbose, human_readeable_string_len; |
80 | | extern u_int8_t max_num_udp_dissected_pkts /* 24 */, max_num_tcp_dissected_pkts /* 80 */; |
81 | | static u_int32_t flow_id = 0; |
82 | | extern FILE *fingerprint_fp; |
83 | | extern char *addr_dump_path; |
84 | | extern u_int8_t enable_doh_dot_detection; |
85 | | extern int malloc_size_stats; |
86 | | extern int monitoring_enabled; |
87 | | |
88 | | /* ****************************************************** */ |
89 | | |
90 | | struct flow_id_stats { |
91 | | u_int32_t flow_id; |
92 | | UT_hash_handle hh; /* makes this structure hashable */ |
93 | | }; |
94 | | |
95 | | struct packet_id_stats { |
96 | | u_int32_t packet_id; |
97 | | UT_hash_handle hh; /* makes this structure hashable */ |
98 | | }; |
99 | | |
100 | | struct payload_stats { |
101 | | u_int8_t *pattern; |
102 | | u_int8_t pattern_len; |
103 | | u_int16_t num_occurrencies; |
104 | | struct flow_id_stats *flows; |
105 | | struct packet_id_stats *packets; |
106 | | UT_hash_handle hh; /* makes this structure hashable */ |
107 | | }; |
108 | | |
109 | | |
110 | | struct payload_stats *pstats = NULL; |
111 | | u_int32_t max_num_packets_per_flow = 10; /* ETTA requires min 10 pkts for record. */ |
112 | | u_int32_t max_packet_payload_dissection = 128; |
113 | | u_int32_t max_num_reported_top_payloads = 25; |
114 | | u_int16_t min_pattern_len = 4; |
115 | | u_int16_t max_pattern_len = 8; |
116 | | |
117 | | |
118 | | /* *********************************************************** */ |
119 | | |
120 | | int ndpi_analyze_payload(struct ndpi_flow_info *flow, |
121 | | u_int8_t *payload, |
122 | | u_int16_t payload_len, |
123 | 0 | u_int32_t packet_id) { |
124 | 0 | struct payload_stats *ret, *ret_found; |
125 | 0 | struct flow_id_stats *f, *f_found; |
126 | 0 | struct packet_id_stats *p, *p_found; |
127 | |
|
128 | | #ifdef DEBUG_PAYLOAD |
129 | | u_int16_t i; |
130 | | for(i=0; i<payload_len; i++) |
131 | | printf("%c", ndpi_isprint(payload[i]) ? payload[i] : '.'); |
132 | | printf("\n"); |
133 | | #endif |
134 | |
|
135 | 0 | HASH_FIND(hh, pstats, payload, payload_len, ret); |
136 | 0 | if(ret == NULL) { |
137 | 0 | if((ret = (struct payload_stats*)ndpi_calloc(1, sizeof(struct payload_stats))) == NULL) |
138 | 0 | return -1; /* OOM */ |
139 | | |
140 | 0 | if((ret->pattern = (u_int8_t*)ndpi_malloc(payload_len)) == NULL) { |
141 | 0 | ndpi_free(ret); |
142 | 0 | return -1; |
143 | 0 | } |
144 | | |
145 | 0 | memcpy(ret->pattern, payload, payload_len); |
146 | 0 | ret->pattern_len = payload_len; |
147 | 0 | ret->num_occurrencies = 1; |
148 | |
|
149 | 0 | HASH_ADD(hh, pstats, pattern[0], payload_len, ret); |
150 | |
|
151 | 0 | HASH_FIND(hh, pstats, payload, payload_len, ret_found); |
152 | 0 | if(ret_found == NULL) { /* The insertion failed (because of a memory allocation error) */ |
153 | 0 | ndpi_free(ret->pattern); |
154 | 0 | ndpi_free(ret); |
155 | 0 | return -1; |
156 | 0 | } |
157 | |
|
158 | | #ifdef DEBUG_PAYLOAD |
159 | | printf("Added element [total: %u]\n", HASH_COUNT(pstats)); |
160 | | #endif |
161 | 0 | } else { |
162 | 0 | ret->num_occurrencies++; |
163 | | // printf("==> %u\n", ret->num_occurrencies); |
164 | 0 | } |
165 | | |
166 | 0 | HASH_FIND_INT(ret->flows, &flow->flow_id, f); |
167 | 0 | if(f == NULL) { |
168 | 0 | if((f = (struct flow_id_stats*)ndpi_calloc(1, sizeof(struct flow_id_stats))) == NULL) |
169 | 0 | return -1; /* OOM */ |
170 | | |
171 | 0 | f->flow_id = flow->flow_id; |
172 | 0 | HASH_ADD_INT(ret->flows, flow_id, f); |
173 | |
|
174 | 0 | HASH_FIND_INT(ret->flows, &flow->flow_id, f_found); |
175 | 0 | if(f_found == NULL) { /* The insertion failed (because of a memory allocation error) */ |
176 | 0 | ndpi_free(f); |
177 | 0 | return -1; |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | 0 | HASH_FIND_INT(ret->packets, &packet_id, p); |
182 | 0 | if(p == NULL) { |
183 | 0 | if((p = (struct packet_id_stats*)ndpi_calloc(1, sizeof(struct packet_id_stats))) == NULL) |
184 | 0 | return -1; /* OOM */ |
185 | 0 | p->packet_id = packet_id; |
186 | |
|
187 | 0 | HASH_ADD_INT(ret->packets, packet_id, p); |
188 | |
|
189 | 0 | HASH_FIND_INT(ret->packets, &packet_id, p_found); |
190 | 0 | if(p_found == NULL) { /* The insertion failed (because of a memory allocation error) */ |
191 | 0 | ndpi_free(p); |
192 | 0 | } |
193 | 0 | } |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | /* *********************************************************** */ |
198 | | |
199 | | void ndpi_payload_analyzer(struct ndpi_flow_info *flow, |
200 | | u_int8_t *payload, u_int16_t payload_len, |
201 | 0 | u_int32_t packet_id) { |
202 | 0 | u_int16_t i, j; |
203 | 0 | u_int16_t scan_len = ndpi_min(max_packet_payload_dissection, payload_len); |
204 | |
|
205 | 0 | if((flow->src2dst_packets+flow->dst2src_packets) <= max_num_packets_per_flow) { |
206 | | #ifdef DEBUG_PAYLOAD |
207 | | printf("[hashval: %u][proto: %u][vlan: %u][%s:%u <-> %s:%u][direction: %s][payload_len: %u]\n", |
208 | | flow->hashval, flow->protocol, flow->vlan_id, |
209 | | flow->src_name ? flow->src_name : "", |
210 | | flow->src_port, |
211 | | flow->dst_name ? flow->dst_name : "", |
212 | | flow->dst_port, |
213 | | src_to_dst_direction ? "s2d" : "d2s", |
214 | | payload_len); |
215 | | #endif |
216 | 0 | } else |
217 | 0 | return; |
218 | | |
219 | 0 | for(i=0; i<scan_len; i++) { |
220 | 0 | for(j=min_pattern_len; j <= max_pattern_len; j++) { |
221 | 0 | if((i+j) < payload_len) { |
222 | 0 | if(ndpi_analyze_payload(flow, &payload[i], j, packet_id) == -1) { |
223 | 0 | LOG(NDPI_LOG_ERROR, "Error ndpi_analyze_payload (allocation failure)\n"); |
224 | 0 | } |
225 | 0 | } |
226 | 0 | } |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | /* ***************************************************** */ |
231 | | |
232 | 0 | static int payload_stats_sort_asc(void *_a, void *_b) { |
233 | 0 | struct payload_stats *a = (struct payload_stats *)_a; |
234 | 0 | struct payload_stats *b = (struct payload_stats *)_b; |
235 | | |
236 | | //return(a->num_occurrencies - b->num_occurrencies); |
237 | 0 | return(b->num_occurrencies - a->num_occurrencies); |
238 | 0 | } |
239 | | |
240 | | /* ***************************************************** */ |
241 | | |
242 | 0 | static void print_payload_stat(struct payload_stats *p, FILE *out) { |
243 | 0 | u_int i; |
244 | 0 | struct flow_id_stats *s, *tmp; |
245 | 0 | struct packet_id_stats *s1, *tmp1; |
246 | |
|
247 | 0 | fprintf(out, "\t["); |
248 | |
|
249 | 0 | for(i=0; i<p->pattern_len; i++) { |
250 | 0 | fprintf(out, "%c", ndpi_isprint(p->pattern[i]) ? p->pattern[i] : '.'); |
251 | 0 | } |
252 | |
|
253 | 0 | fprintf(out, "]"); |
254 | 0 | for(; i<16; i++) fprintf(out, " "); |
255 | 0 | fprintf(out, "["); |
256 | |
|
257 | 0 | for(i=0; i<p->pattern_len; i++) { |
258 | 0 | fprintf(out, "%s%02X", (i > 0) ? " " : "", ndpi_isprint(p->pattern[i]) ? p->pattern[i] : '.'); |
259 | 0 | } |
260 | |
|
261 | 0 | fprintf(out, "]"); |
262 | |
|
263 | 0 | for(; i<16; i++) fprintf(out, " "); |
264 | 0 | for(i=p->pattern_len; i<max_pattern_len; i++) fprintf(out, " "); |
265 | |
|
266 | 0 | fprintf(out, "[len: %u][num_occurrencies: %u][flowId: ", |
267 | 0 | p->pattern_len, p->num_occurrencies); |
268 | |
|
269 | 0 | i = 0; |
270 | 0 | HASH_ITER(hh, p->flows, s, tmp) { |
271 | 0 | fprintf(out, "%s%u", (i > 0) ? " " : "", s->flow_id); |
272 | 0 | i++; |
273 | 0 | } |
274 | |
|
275 | 0 | fprintf(out, "][packetIds: "); |
276 | | |
277 | | /* ******************************** */ |
278 | |
|
279 | 0 | i = 0; |
280 | 0 | HASH_ITER(hh, p->packets, s1, tmp1) { |
281 | 0 | fprintf(out, "%s%u", (i > 0) ? " " : "", s1->packet_id); |
282 | 0 | i++; |
283 | 0 | } |
284 | |
|
285 | 0 | fprintf(out, "]\n"); |
286 | | |
287 | |
|
288 | 0 | } |
289 | | |
290 | | /* ***************************************************** */ |
291 | | |
292 | 0 | void ndpi_report_payload_stats(FILE *out) { |
293 | 0 | struct payload_stats *p, *tmp; |
294 | 0 | u_int num = 0; |
295 | |
|
296 | 0 | if(out) |
297 | 0 | fprintf(out, "\n\nPayload Analysis\n"); |
298 | |
|
299 | 0 | HASH_SORT(pstats, payload_stats_sort_asc); |
300 | |
|
301 | 0 | HASH_ITER(hh, pstats, p, tmp) { |
302 | 0 | if(out && num <= max_num_reported_top_payloads) |
303 | 0 | print_payload_stat(p, out); |
304 | |
|
305 | 0 | ndpi_free(p->pattern); |
306 | |
|
307 | 0 | { |
308 | 0 | struct flow_id_stats *p1, *tmp1; |
309 | |
|
310 | 0 | HASH_ITER(hh, p->flows, p1, tmp1) { |
311 | 0 | HASH_DEL(p->flows, p1); |
312 | 0 | ndpi_free(p1); |
313 | 0 | } |
314 | 0 | } |
315 | |
|
316 | 0 | { |
317 | 0 | struct packet_id_stats *p1, *tmp1; |
318 | |
|
319 | 0 | HASH_ITER(hh, p->packets, p1, tmp1) { |
320 | 0 | HASH_DEL(p->packets, p1); |
321 | 0 | ndpi_free(p1); |
322 | 0 | } |
323 | 0 | } |
324 | |
|
325 | 0 | HASH_DEL(pstats, p); |
326 | 0 | ndpi_free(p); |
327 | 0 | num++; |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | /* ***************************************************** */ |
332 | | |
333 | 267k | void ndpi_free_flow_info_half(struct ndpi_flow_info *flow) { |
334 | 267k | if(flow->ndpi_flow) { ndpi_flow_free(flow->ndpi_flow); flow->ndpi_flow = NULL; } |
335 | 267k | } |
336 | | |
337 | | /* ***************************************************** */ |
338 | | |
339 | 0 | void ndpi_stats_free(ndpi_stats_t *s) { |
340 | 0 | if (s->protocol_counter) ndpi_free(s->protocol_counter); |
341 | 0 | if (s->protocol_counter_bytes) ndpi_free(s->protocol_counter_bytes); |
342 | 0 | if (s->protocol_flows) ndpi_free(s->protocol_flows); |
343 | 0 | if (s->fpc_protocol_counter) ndpi_free(s->fpc_protocol_counter); |
344 | 0 | if (s->fpc_protocol_counter_bytes) ndpi_free(s->fpc_protocol_counter_bytes); |
345 | 0 | if (s->fpc_protocol_flows) ndpi_free(s->fpc_protocol_flows); |
346 | |
|
347 | 0 | s->num_protocols = 0; |
348 | 0 | } |
349 | | |
350 | 0 | int ndpi_stats_init(ndpi_stats_t *s, uint32_t num_protocols) { |
351 | 0 | memset(s, 0, sizeof(*s)); |
352 | 0 | s->num_protocols = num_protocols; |
353 | |
|
354 | 0 | s->protocol_counter = ndpi_calloc(num_protocols, sizeof(u_int64_t)); |
355 | 0 | s->protocol_counter_bytes = ndpi_calloc(num_protocols, sizeof(u_int64_t)); |
356 | 0 | s->protocol_flows = ndpi_calloc(num_protocols, sizeof(u_int32_t)); |
357 | 0 | s->fpc_protocol_counter = ndpi_calloc(num_protocols, sizeof(u_int64_t)); |
358 | 0 | s->fpc_protocol_counter_bytes = ndpi_calloc(num_protocols, sizeof(u_int64_t)); |
359 | 0 | s->fpc_protocol_flows = ndpi_calloc(num_protocols, sizeof(u_int32_t)); |
360 | |
|
361 | 0 | if(!s->protocol_counter || !s->protocol_counter_bytes || !s->protocol_flows || |
362 | 0 | !s->fpc_protocol_counter || !s->fpc_protocol_counter_bytes || !s->fpc_protocol_flows) { |
363 | |
|
364 | 0 | LOG(NDPI_LOG_ERROR, "[NDPI] %s: error allocating memory for ndpi_stats\n", __FUNCTION__); |
365 | 0 | return 0; |
366 | 0 | } |
367 | 0 | return 1; |
368 | 0 | } |
369 | | |
370 | 0 | void ndpi_stats_reset(ndpi_stats_t *s) { |
371 | 0 | memset(s->flow_count, 0, sizeof(s->flow_count)); |
372 | 0 | s->guessed_flow_protocols = 0; |
373 | 0 | s->raw_packet_count = 0; |
374 | 0 | s->ip_packet_count = 0; |
375 | 0 | s->total_wire_bytes = 0; |
376 | 0 | s->total_ip_bytes = 0; |
377 | 0 | s->total_discarded_bytes = 0; |
378 | 0 | s->ndpi_flow_count = 0; |
379 | 0 | s->tcp_count = 0; |
380 | 0 | s->udp_count = 0; |
381 | 0 | s->mpls_count = 0; |
382 | 0 | s->pppoe_count = 0; |
383 | 0 | s->vlan_count = 0; |
384 | 0 | s->fragmented_count = 0; |
385 | 0 | s->max_packet_len = 0; |
386 | 0 | s->num_dissector_calls = 0; |
387 | |
|
388 | 0 | memset(s->packet_len, 0, sizeof(s->packet_len)); |
389 | 0 | memset(s->dpi_packet_count, 0, sizeof(s->dpi_packet_count)); |
390 | 0 | memset(s->flow_confidence, 0, sizeof(s->flow_confidence)); |
391 | 0 | memset(s->fpc_flow_confidence, 0, sizeof(s->fpc_flow_confidence)); |
392 | 0 | memset(s->category_counter, 0, sizeof(s->category_counter)); |
393 | 0 | memset(s->category_counter_bytes, 0, sizeof(s->category_counter_bytes)); |
394 | 0 | memset(s->category_flows, 0, sizeof(s->category_flows)); |
395 | 0 | memset(s->lru_stats, 0, sizeof(s->lru_stats)); |
396 | 0 | memset(s->automa_stats, 0, sizeof(s->automa_stats)); |
397 | 0 | memset(s->patricia_stats, 0, sizeof(s->patricia_stats)); |
398 | 0 | memset(s->hash_stats, 0, sizeof(s->hash_stats)); |
399 | |
|
400 | 0 | if (s->protocol_counter) memset(s->protocol_counter, 0, sizeof(u_int64_t) * s->num_protocols); |
401 | 0 | if (s->protocol_counter_bytes) memset(s->protocol_counter_bytes, 0, sizeof(u_int64_t) * s->num_protocols); |
402 | 0 | if (s->protocol_flows) memset(s->protocol_flows, 0, sizeof(u_int32_t) * s->num_protocols); |
403 | 0 | if (s->fpc_protocol_counter) memset(s->fpc_protocol_counter, 0, sizeof(u_int64_t) * s->num_protocols); |
404 | 0 | if (s->fpc_protocol_counter_bytes) memset(s->fpc_protocol_counter_bytes, 0, sizeof(u_int64_t) * s->num_protocols); |
405 | 0 | if (s->fpc_protocol_flows) memset(s->fpc_protocol_flows, 0, sizeof(u_int32_t) * s->num_protocols); |
406 | 0 | } |
407 | | |
408 | | /* ***************************************************** */ |
409 | | |
410 | | struct ndpi_workflow* ndpi_workflow_init(const struct ndpi_workflow_prefs * prefs, |
411 | | pcap_t * pcap_handle, int do_init_flows_root, |
412 | | ndpi_serialization_format serialization_format, |
413 | 1 | struct ndpi_global_context *g_ctx) { |
414 | 1 | struct ndpi_detection_module_struct * module; |
415 | 1 | struct ndpi_workflow * workflow; |
416 | | |
417 | 1 | module = ndpi_init_detection_module(g_ctx); |
418 | | |
419 | 1 | if(module == NULL) { |
420 | 0 | LOG(NDPI_LOG_ERROR, "global structure initialization failed\n"); |
421 | 0 | return NULL; |
422 | 0 | } |
423 | | |
424 | 1 | workflow = ndpi_calloc(1, sizeof(struct ndpi_workflow)); |
425 | 1 | if(workflow == NULL) { |
426 | 0 | LOG(NDPI_LOG_ERROR, "global structure initialization failed\n"); |
427 | 0 | ndpi_exit_detection_module(module); |
428 | 0 | return NULL; |
429 | 0 | } |
430 | | |
431 | 1 | workflow->pcap_handle = pcap_handle; |
432 | 1 | workflow->prefs = *prefs; |
433 | 1 | workflow->ndpi_struct = module; |
434 | | |
435 | 1 | ndpi_set_user_data(module, workflow); |
436 | | |
437 | 1 | if(do_init_flows_root) { |
438 | 0 | workflow->ndpi_flows_root = ndpi_calloc(workflow->prefs.num_roots, sizeof(void *)); |
439 | |
|
440 | 0 | if(!workflow->ndpi_flows_root) { |
441 | 0 | ndpi_exit_detection_module(module); |
442 | 0 | ndpi_free(workflow); |
443 | 0 | return NULL; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | 1 | workflow->ndpi_serialization_format = serialization_format; |
448 | | |
449 | 1 | return workflow; |
450 | 1 | } |
451 | | |
452 | | /* ***************************************************** */ |
453 | | |
454 | 219k | void ndpi_flow_info_freer(void *node) { |
455 | 219k | struct ndpi_flow_info *flow = (struct ndpi_flow_info*)node; |
456 | | |
457 | 219k | ndpi_flow_info_free_data(flow); |
458 | 219k | ndpi_free(flow); |
459 | 219k | } |
460 | | |
461 | | /* ***************************************************** */ |
462 | | |
463 | 219k | static void ndpi_free_flow_tls_data(struct ndpi_flow_info *flow) { |
464 | 219k | if(flow->dhcp_fingerprint) { |
465 | 234 | ndpi_free(flow->dhcp_fingerprint); |
466 | 234 | flow->dhcp_fingerprint = NULL; |
467 | 234 | } |
468 | | |
469 | 219k | if(flow->dhcp_class_ident) { |
470 | 143 | ndpi_free(flow->dhcp_class_ident); |
471 | 143 | flow->dhcp_class_ident = NULL; |
472 | 143 | } |
473 | | |
474 | 219k | if(flow->server_hostname) { |
475 | 5.83k | ndpi_free(flow->server_hostname); |
476 | 5.83k | flow->server_hostname = NULL; |
477 | 5.83k | } |
478 | | |
479 | 219k | if(flow->bittorent_hash) { |
480 | 98 | ndpi_free(flow->bittorent_hash); |
481 | 98 | flow->bittorent_hash = NULL; |
482 | 98 | } |
483 | | |
484 | 219k | if(flow->telnet.username) { |
485 | 66 | ndpi_free(flow->telnet.username); |
486 | 66 | flow->telnet.username = NULL; |
487 | 66 | } |
488 | | |
489 | 219k | if(flow->telnet.password) { |
490 | 30 | ndpi_free(flow->telnet.password); |
491 | 30 | flow->telnet.password = NULL; |
492 | 30 | } |
493 | | |
494 | 219k | if(flow->ssh_tls.server_names) { |
495 | 1.28k | ndpi_free(flow->ssh_tls.server_names); |
496 | 1.28k | flow->ssh_tls.server_names = NULL; |
497 | 1.28k | } |
498 | | |
499 | 219k | if(flow->ssh_tls.advertised_alpns) { |
500 | 6.14k | ndpi_free(flow->ssh_tls.advertised_alpns); |
501 | 6.14k | flow->ssh_tls.advertised_alpns = NULL; |
502 | 6.14k | } |
503 | | |
504 | 219k | if(flow->ssh_tls.negotiated_alpn) { |
505 | 864 | ndpi_free(flow->ssh_tls.negotiated_alpn); |
506 | 864 | flow->ssh_tls.negotiated_alpn = NULL; |
507 | 864 | } |
508 | | |
509 | 219k | if(flow->ssh_tls.tls_supported_versions) { |
510 | 5.37k | ndpi_free(flow->ssh_tls.tls_supported_versions); |
511 | 5.37k | flow->ssh_tls.tls_supported_versions = NULL; |
512 | 5.37k | } |
513 | | |
514 | 219k | if(flow->ssh_tls.tls_issuerDN) { |
515 | 1.50k | ndpi_free(flow->ssh_tls.tls_issuerDN); |
516 | 1.50k | flow->ssh_tls.tls_issuerDN = NULL; |
517 | 1.50k | } |
518 | | |
519 | 219k | if(flow->ssh_tls.tls_subjectDN) { |
520 | 1.60k | ndpi_free(flow->ssh_tls.tls_subjectDN); |
521 | 1.60k | flow->ssh_tls.tls_subjectDN = NULL; |
522 | 1.60k | } |
523 | | |
524 | 219k | if(flow->ssh_tls.ja4_client_raw) { |
525 | 8.18k | ndpi_free(flow->ssh_tls.ja4_client_raw); |
526 | 8.18k | flow->ssh_tls.ja4_client_raw = NULL; |
527 | 8.18k | } |
528 | | |
529 | 219k | if(flow->ndpi_fingerprint) { |
530 | 8.40k | ndpi_free(flow->ndpi_fingerprint); |
531 | 8.40k | flow->ndpi_fingerprint = NULL; |
532 | 8.40k | } |
533 | | |
534 | 219k | if(flow->stun.mapped_address.aps) { |
535 | 1.67k | ndpi_free(flow->stun.mapped_address.aps); |
536 | 1.67k | flow->stun.mapped_address.aps = NULL; |
537 | 1.67k | } |
538 | 219k | if(flow->stun.other_address.aps) { |
539 | 129 | ndpi_free(flow->stun.other_address.aps); |
540 | 129 | flow->stun.other_address.aps = NULL; |
541 | 129 | } |
542 | 219k | if(flow->stun.peer_address.aps) { |
543 | 563 | ndpi_free(flow->stun.peer_address.aps); |
544 | 563 | flow->stun.peer_address.aps = NULL; |
545 | 563 | } |
546 | 219k | if(flow->stun.relayed_address.aps) { |
547 | 694 | ndpi_free(flow->stun.relayed_address.aps); |
548 | 694 | flow->stun.relayed_address.aps = NULL; |
549 | 694 | } |
550 | 219k | if(flow->stun.response_origin.aps) { |
551 | 164 | ndpi_free(flow->stun.response_origin.aps); |
552 | 164 | flow->stun.response_origin.aps = NULL; |
553 | 164 | } |
554 | 219k | } |
555 | | |
556 | | /* ***************************************************** */ |
557 | | |
558 | 219k | static void ndpi_free_flow_data_analysis(struct ndpi_flow_info *flow) { |
559 | 219k | if(flow->iat_c_to_s) ndpi_free_data_analysis(flow->iat_c_to_s, 1); |
560 | 219k | if(flow->iat_s_to_c) ndpi_free_data_analysis(flow->iat_s_to_c, 1); |
561 | | |
562 | 219k | if(flow->pktlen_c_to_s) ndpi_free_data_analysis(flow->pktlen_c_to_s, 1); |
563 | 219k | if(flow->pktlen_s_to_c) ndpi_free_data_analysis(flow->pktlen_s_to_c, 1); |
564 | | |
565 | 219k | if(flow->iat_flow) ndpi_free_data_analysis(flow->iat_flow, 1); |
566 | | |
567 | 219k | if(flow->entropy) ndpi_free(flow->entropy); |
568 | 219k | if(flow->last_entropy) ndpi_free(flow->last_entropy); |
569 | 219k | } |
570 | | |
571 | | /* ***************************************************** */ |
572 | | |
573 | 219k | void ndpi_flow_info_free_data(struct ndpi_flow_info *flow) { |
574 | | |
575 | 219k | ndpi_free_flow_info_half(flow); |
576 | 219k | ndpi_term_serializer(&flow->ndpi_flow_serializer); |
577 | 219k | ndpi_free_flow_data_analysis(flow); |
578 | 219k | ndpi_free_flow_tls_data(flow); |
579 | | |
580 | | #ifdef DIRECTION_BINS |
581 | | ndpi_free_bin(&flow->payload_len_bin_src2dst); |
582 | | ndpi_free_bin(&flow->payload_len_bin_dst2src); |
583 | | #else |
584 | 219k | ndpi_free_bin(&flow->payload_len_bin); |
585 | 219k | #endif |
586 | | |
587 | 219k | if(flow->src_name) ndpi_free(flow->src_name); |
588 | 219k | if(flow->dst_name) ndpi_free(flow->dst_name); |
589 | 219k | if(flow->tcp_fingerprint) ndpi_free(flow->tcp_fingerprint); |
590 | 219k | if(flow->risk_str) ndpi_free(flow->risk_str); |
591 | 219k | if(flow->flow_payload) ndpi_free(flow->flow_payload); |
592 | 219k | } |
593 | | |
594 | | /* ***************************************************** */ |
595 | | |
596 | 0 | void ndpi_workflow_free(struct ndpi_workflow * workflow) { |
597 | 0 | u_int i; |
598 | |
|
599 | 0 | for(i=0; i<workflow->prefs.num_roots; i++) |
600 | 0 | ndpi_tdestroy(workflow->ndpi_flows_root[i], ndpi_flow_info_freer); |
601 | |
|
602 | 0 | if(addr_dump_path != NULL) |
603 | 0 | ndpi_cache_address_dump(workflow->ndpi_struct, addr_dump_path, 0); |
604 | |
|
605 | 0 | ndpi_exit_detection_module(workflow->ndpi_struct); |
606 | 0 | ndpi_free(workflow->ndpi_flows_root); |
607 | |
|
608 | 0 | ndpi_stats_free(&workflow->stats); |
609 | |
|
610 | 0 | ndpi_free(workflow); |
611 | 0 | } |
612 | | |
613 | 1.39M | static inline int cmp_n32(uint32_t a,uint32_t b) { |
614 | 1.39M | return a == b ? 0 : ntohl(a) < ntohl(b) ? -1:1; |
615 | 1.39M | } |
616 | 1.17M | static inline int cmp_n16(uint16_t a,uint16_t b) { |
617 | 1.17M | return a == b ? 0 : ntohs(a) < ntohs(b) ? -1:1; |
618 | 1.17M | } |
619 | | |
620 | | /* ***************************************************** */ |
621 | | |
622 | 5.43M | int ndpi_workflow_node_cmp(const void *a, const void *b) { |
623 | 5.43M | const struct ndpi_flow_info *fa = (const struct ndpi_flow_info*)a; |
624 | 5.43M | const struct ndpi_flow_info *fb = (const struct ndpi_flow_info*)b; |
625 | | |
626 | 5.43M | if(fa->hashval < fb->hashval) return(-1); else if(fa->hashval > fb->hashval) return(1); |
627 | | |
628 | | /* Flows have the same hash */ |
629 | | |
630 | 827k | if(fa->vlan_id < fb->vlan_id ) return(-1); else { if(fa->vlan_id > fb->vlan_id ) return(1); } |
631 | 825k | if(fa->protocol < fb->protocol ) return(-1); else { if(fa->protocol > fb->protocol ) return(1); } |
632 | | |
633 | 823k | int r; |
634 | 823k | r = cmp_n32(fa->src_ip, fb->src_ip); if(r) return r; |
635 | 607k | r = cmp_n16(fa->src_port, fb->src_port) ; if(r) return r; |
636 | 568k | r = cmp_n32(fa->dst_ip, fb->dst_ip); if(r) return r; |
637 | 567k | r = cmp_n16(fa->dst_port, fb->dst_port); |
638 | | |
639 | 567k | return(r); |
640 | 568k | } |
641 | | |
642 | | /* ***************************************************** */ |
643 | | |
644 | | /** |
645 | | * \brief Update the byte count for the flow record. |
646 | | * \param f Flow data |
647 | | * \param x Data to use for update |
648 | | * \param len Length of the data (in bytes) |
649 | | * \return none |
650 | | */ |
651 | | static void |
652 | | ndpi_flow_update_byte_count(struct ndpi_flow_info *flow, const void *x, |
653 | 786k | unsigned int len, u_int8_t src_to_dst_direction) { |
654 | | /* |
655 | | * implementation note: The spec says that 4000 octets is enough of a |
656 | | * sample size to accurately reflect the byte distribution. Also, to avoid |
657 | | * wrapping of the byte count at the 16-bit boundry, we stop counting once |
658 | | * the 4000th octet has been seen for a flow. |
659 | | */ |
660 | | |
661 | 786k | if((flow->entropy->src2dst_pkt_count+flow->entropy->dst2src_pkt_count) <= max_num_packets_per_flow) { |
662 | | /* octet count was already incremented before processing this payload */ |
663 | 786k | u_int32_t current_count; |
664 | | |
665 | 786k | if(src_to_dst_direction) { |
666 | 614k | current_count = flow->entropy->src2dst_l4_bytes - len; |
667 | 614k | } else { |
668 | 171k | current_count = flow->entropy->dst2src_l4_bytes - len; |
669 | 171k | } |
670 | | |
671 | 786k | if(current_count < ETTA_MIN_OCTETS) { |
672 | 740k | u_int32_t i; |
673 | 740k | const unsigned char *data = x; |
674 | | |
675 | 132M | for(i=0; i<len; i++) { |
676 | 131M | if(src_to_dst_direction) { |
677 | 85.3M | flow->entropy->src2dst_byte_count[data[i]]++; |
678 | 85.3M | } else { |
679 | 46.5M | flow->entropy->dst2src_byte_count[data[i]]++; |
680 | 46.5M | } |
681 | 131M | current_count++; |
682 | 131M | if(current_count >= ETTA_MIN_OCTETS) { |
683 | 8.82k | break; |
684 | 8.82k | } |
685 | 131M | } |
686 | 740k | } |
687 | 786k | } |
688 | 786k | } |
689 | | |
690 | | /* ***************************************************** */ |
691 | | |
692 | | /** |
693 | | * \brief Update the byte distribution mean for the flow record. |
694 | | * \param f Flow record |
695 | | * \param x Data to use for update |
696 | | * \param len Length of the data (in bytes) |
697 | | * \return none |
698 | | */ |
699 | | static void |
700 | | ndpi_flow_update_byte_dist_mean_var(ndpi_flow_info_t *flow, const void *x, |
701 | 786k | unsigned int len, u_int8_t src_to_dst_direction) { |
702 | 786k | const unsigned char *data = x; |
703 | | |
704 | 786k | if((flow->entropy->src2dst_pkt_count+flow->entropy->dst2src_pkt_count) <= max_num_packets_per_flow) { |
705 | 786k | unsigned int i; |
706 | | |
707 | 163M | for(i=0; i<len; i++) { |
708 | 162M | double delta; |
709 | | |
710 | 162M | if(src_to_dst_direction) { |
711 | 100M | flow->entropy->src2dst_num_bytes += 1; |
712 | 100M | delta = ((double)data[i] - flow->entropy->src2dst_bd_mean); |
713 | 100M | flow->entropy->src2dst_bd_mean += delta/((double)flow->entropy->src2dst_num_bytes); |
714 | 100M | flow->entropy->src2dst_bd_variance += delta*((double)data[i] - flow->entropy->src2dst_bd_mean); |
715 | 100M | } else { |
716 | 61.8M | flow->entropy->dst2src_num_bytes += 1; |
717 | 61.8M | delta = ((double)data[i] - flow->entropy->dst2src_bd_mean); |
718 | 61.8M | flow->entropy->dst2src_bd_mean += delta/((double)flow->entropy->dst2src_num_bytes); |
719 | 61.8M | flow->entropy->dst2src_bd_variance += delta*((double)data[i] - flow->entropy->dst2src_bd_mean); |
720 | 61.8M | } |
721 | 162M | } |
722 | 786k | } |
723 | 786k | } |
724 | | |
725 | | /* ***************************************************** */ |
726 | | |
727 | | static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow, |
728 | | const u_int8_t version, |
729 | | u_int16_t vlan_id, |
730 | | ndpi_packet_tunnel tunnel_type, |
731 | | const struct ndpi_iphdr *iph, |
732 | | const struct ndpi_ipv6hdr *iph6, |
733 | | u_int16_t ipsize, |
734 | | u_int16_t l4_packet_len, |
735 | | u_int16_t l4_offset, |
736 | | struct ndpi_tcphdr **tcph, |
737 | | struct ndpi_udphdr **udph, |
738 | | u_int16_t *sport, u_int16_t *dport, |
739 | | u_int8_t *proto, |
740 | | u_int8_t **payload, |
741 | | u_int16_t *payload_len, |
742 | | u_int8_t *src_to_dst_direction, |
743 | 793k | pkt_timeval when) { |
744 | 793k | u_int32_t idx, hashval; |
745 | 793k | struct ndpi_flow_info flow; |
746 | 793k | void *ret; |
747 | 793k | const u_int8_t *l3, *l4; |
748 | 793k | u_int32_t l4_data_len = 0XFEEDFACE; |
749 | | |
750 | | /* |
751 | | Note: to keep things simple (ndpiReader is just a demo app) |
752 | | we handle IPv6 a-la-IPv4. |
753 | | */ |
754 | 793k | if(version == IPVERSION) { |
755 | 723k | if(ipsize < 20) |
756 | 10 | return NULL; |
757 | | |
758 | 723k | if((iph->ihl * 4) > ipsize || ipsize < ntohs(iph->tot_len) |
759 | 723k | /* || (iph->frag_off & htons(0x1FFF)) != 0 */) |
760 | 6.74k | return NULL; |
761 | | |
762 | 716k | l3 = (const u_int8_t*)iph; |
763 | 716k | } else { |
764 | 70.5k | if(l4_offset > ipsize) |
765 | 0 | return NULL; |
766 | | |
767 | 70.5k | l3 = (const u_int8_t*)iph6; |
768 | 70.5k | } |
769 | 787k | if(ipsize < l4_offset + l4_packet_len) |
770 | 901 | return NULL; |
771 | | |
772 | 786k | *proto = iph->protocol; |
773 | | |
774 | 786k | if(l4_packet_len < 64) |
775 | 463k | workflow->stats.packet_len[0]++; |
776 | 322k | else if(l4_packet_len >= 64 && l4_packet_len < 128) |
777 | 89.7k | workflow->stats.packet_len[1]++; |
778 | 232k | else if(l4_packet_len >= 128 && l4_packet_len < 256) |
779 | 87.1k | workflow->stats.packet_len[2]++; |
780 | 145k | else if(l4_packet_len >= 256 && l4_packet_len < 1024) |
781 | 80.8k | workflow->stats.packet_len[3]++; |
782 | 64.8k | else if(l4_packet_len >= 1024 && l4_packet_len < 1500) |
783 | 60.8k | workflow->stats.packet_len[4]++; |
784 | 3.96k | else if(l4_packet_len >= 1500) |
785 | 3.96k | workflow->stats.packet_len[5]++; |
786 | | |
787 | 786k | if(l4_packet_len > workflow->stats.max_packet_len) |
788 | 238 | workflow->stats.max_packet_len = l4_packet_len; |
789 | | |
790 | 786k | l4 =& ((const u_int8_t *) l3)[l4_offset]; |
791 | | |
792 | 786k | if(*proto == IPPROTO_TCP && l4_packet_len >= sizeof(struct ndpi_tcphdr)) { |
793 | 453k | u_int tcp_len; |
794 | | |
795 | | // TCP |
796 | 453k | workflow->stats.tcp_count++; |
797 | 453k | *tcph = (struct ndpi_tcphdr *)l4; |
798 | 453k | *sport = ntohs((*tcph)->source), *dport = ntohs((*tcph)->dest); |
799 | 453k | tcp_len = ndpi_min(4*(*tcph)->doff, l4_packet_len); |
800 | 453k | *payload = (u_int8_t*)&l4[tcp_len]; |
801 | 453k | *payload_len = ndpi_max(0, l4_packet_len-4*(*tcph)->doff); |
802 | 453k | l4_data_len = l4_packet_len - sizeof(struct ndpi_tcphdr); |
803 | 453k | } else if(*proto == IPPROTO_UDP && l4_packet_len >= sizeof(struct ndpi_udphdr)) { |
804 | | // UDP |
805 | 299k | workflow->stats.udp_count++; |
806 | 299k | *udph = (struct ndpi_udphdr *)l4; |
807 | 299k | *sport = ntohs((*udph)->source), *dport = ntohs((*udph)->dest); |
808 | 299k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_udphdr)]; |
809 | 299k | *payload_len = (l4_packet_len > sizeof(struct ndpi_udphdr)) ? l4_packet_len-sizeof(struct ndpi_udphdr) : 0; |
810 | 299k | l4_data_len = l4_packet_len - sizeof(struct ndpi_udphdr); |
811 | 299k | } else if(*proto == IPPROTO_ICMP) { |
812 | 8.22k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_icmphdr )]; |
813 | 8.22k | *payload_len = (l4_packet_len > sizeof(struct ndpi_icmphdr)) ? l4_packet_len-sizeof(struct ndpi_icmphdr) : 0; |
814 | 8.22k | l4_data_len = l4_packet_len - sizeof(struct ndpi_icmphdr); |
815 | 8.22k | *sport = *dport = 0; |
816 | 25.0k | } else if(*proto == IPPROTO_ICMPV6) { |
817 | 5.38k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_icmp6hdr)]; |
818 | 5.38k | *payload_len = (l4_packet_len > sizeof(struct ndpi_icmp6hdr)) ? l4_packet_len-sizeof(struct ndpi_icmp6hdr) : 0; |
819 | 5.38k | l4_data_len = l4_packet_len - sizeof(struct ndpi_icmp6hdr); |
820 | 5.38k | *sport = *dport = 0; |
821 | 19.6k | } else { |
822 | | // non tcp/udp protocols |
823 | 19.6k | *sport = *dport = 0; |
824 | 19.6k | l4_data_len = 0; |
825 | 19.6k | } |
826 | | |
827 | 786k | flow.protocol = iph->protocol, flow.vlan_id = vlan_id; |
828 | 786k | flow.src_ip = iph->saddr, flow.dst_ip = iph->daddr; |
829 | 786k | flow.src_port = htons(*sport), flow.dst_port = htons(*dport); |
830 | 786k | flow.hashval = hashval = flow.protocol + ntohl(flow.src_ip) + ntohl(flow.dst_ip) |
831 | 786k | + ntohs(flow.src_port) + ntohs(flow.dst_port); |
832 | | |
833 | | #if 0 |
834 | | { |
835 | | char ip1[48],ip2[48]; |
836 | | inet_ntop(AF_INET, &flow.src_ip, ip1, sizeof(ip1)); |
837 | | inet_ntop(AF_INET, &flow.dst_ip, ip2, sizeof(ip2)); |
838 | | printf("hashval=%u [%u][%u][%s:%u][%s:%u]\n", hashval, flow.protocol, flow.vlan_id, |
839 | | ip1, ntohs(flow.src_port), ip2, ntohs(flow.dst_port)); |
840 | | } |
841 | | #endif |
842 | | |
843 | 786k | idx = hashval % workflow->prefs.num_roots; |
844 | 786k | ret = ndpi_tfind(&flow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp); |
845 | | |
846 | | /* to avoid two nodes in one binary tree for a flow */ |
847 | 786k | int is_changed = 0; |
848 | 786k | if(ret == NULL) { |
849 | 390k | u_int32_t orig_src_ip = flow.src_ip; |
850 | 390k | u_int16_t orig_src_port = flow.src_port; |
851 | 390k | u_int32_t orig_dst_ip = flow.dst_ip; |
852 | 390k | u_int16_t orig_dst_port = flow.dst_port; |
853 | | |
854 | 390k | flow.src_ip = orig_dst_ip; |
855 | 390k | flow.src_port = orig_dst_port; |
856 | 390k | flow.dst_ip = orig_src_ip; |
857 | 390k | flow.dst_port = orig_src_port; |
858 | | |
859 | 390k | is_changed = 1; |
860 | | |
861 | 390k | ret = ndpi_tfind(&flow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp); |
862 | 390k | } |
863 | | |
864 | 786k | if(ret == NULL) { |
865 | 219k | if(workflow->stats.ndpi_flow_count == workflow->prefs.max_ndpi_flows) { |
866 | 0 | LOG(NDPI_LOG_ERROR, |
867 | 0 | "maximum flow count (%u) has been exceeded\n", |
868 | 0 | workflow->prefs.max_ndpi_flows); |
869 | 0 | return NULL; |
870 | 219k | } else { |
871 | 219k | struct ndpi_flow_info *newflow = (struct ndpi_flow_info*)ndpi_malloc(sizeof(struct ndpi_flow_info)); |
872 | | |
873 | 219k | if(newflow == NULL) { |
874 | 0 | LOG(NDPI_LOG_ERROR, "[NDPI] %s(1): not enough memory\n", __FUNCTION__); |
875 | 0 | return(NULL); |
876 | 0 | } else |
877 | 219k | workflow->num_allocated_flows++; |
878 | | |
879 | 219k | memset(newflow, 0, sizeof(struct ndpi_flow_info)); |
880 | 219k | newflow->flow_id = flow_id++; |
881 | 219k | newflow->hashval = hashval; |
882 | 219k | newflow->tunnel_type = tunnel_type; |
883 | 219k | newflow->protocol = iph->protocol, newflow->vlan_id = vlan_id; |
884 | 219k | newflow->src_ip = iph->saddr, newflow->dst_ip = iph->daddr; |
885 | 219k | newflow->src_port = htons(*sport), newflow->dst_port = htons(*dport); |
886 | 219k | newflow->ip_version = version; |
887 | 219k | newflow->iat_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
888 | 219k | newflow->iat_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW); |
889 | 219k | newflow->pktlen_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
890 | 219k | newflow->pktlen_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
891 | 219k | newflow->iat_flow = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW); |
892 | | |
893 | | #ifdef DIRECTION_BINS |
894 | | ndpi_init_bin(&newflow->payload_len_bin_src2dst, ndpi_bin_family8, PLEN_NUM_BINS); |
895 | | ndpi_init_bin(&newflow->payload_len_bin_dst2src, ndpi_bin_family8, PLEN_NUM_BINS); |
896 | | #else |
897 | 219k | ndpi_init_bin(&newflow->payload_len_bin, ndpi_bin_family8, PLEN_NUM_BINS); |
898 | 219k | #endif |
899 | | |
900 | 219k | if (version == 4 || version == 6) { |
901 | 219k | uint16_t inet_addrlen = (version == 4) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; |
902 | 219k | newflow->src_name = ndpi_malloc(inet_addrlen); |
903 | 219k | newflow->dst_name = ndpi_malloc(inet_addrlen); |
904 | | |
905 | 219k | if(version == 4) { |
906 | 200k | if (newflow->src_name) |
907 | 200k | inet_ntop(AF_INET, &newflow->src_ip, newflow->src_name, inet_addrlen); |
908 | 200k | if (newflow->dst_name) |
909 | 200k | inet_ntop(AF_INET, &newflow->dst_ip, newflow->dst_name, inet_addrlen); |
910 | 200k | } else if (version == 6) { |
911 | 18.4k | newflow->src_ip6 = *(struct ndpi_in6_addr *)&iph6->ip6_src; |
912 | 18.4k | newflow->dst_ip6 = *(struct ndpi_in6_addr *)&iph6->ip6_dst; |
913 | | |
914 | 18.4k | if (newflow->src_name) |
915 | 18.4k | inet_ntop(AF_INET6, &newflow->src_ip6, newflow->src_name, inet_addrlen); |
916 | 18.4k | if (newflow->dst_name) |
917 | 18.4k | inet_ntop(AF_INET6, &newflow->dst_ip6, newflow->dst_name, inet_addrlen); |
918 | | |
919 | | /* For consistency across platforms replace :0: with :: */ |
920 | 18.4k | if (newflow->src_name) ndpi_patchIPv6Address(newflow->src_name); |
921 | 18.4k | if (newflow->dst_name) ndpi_patchIPv6Address(newflow->dst_name); |
922 | 18.4k | } |
923 | 219k | } |
924 | | |
925 | 219k | if((newflow->ndpi_flow = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT)) == NULL) { |
926 | 0 | LOG(NDPI_LOG_ERROR, "[NDPI] %s(2): not enough memory\n", __FUNCTION__); |
927 | 0 | ndpi_flow_info_free_data(newflow); |
928 | 0 | ndpi_free(newflow); |
929 | 0 | return(NULL); |
930 | 0 | } else |
931 | 219k | memset(newflow->ndpi_flow, 0, SIZEOF_FLOW_STRUCT); |
932 | | |
933 | 219k | if (workflow->ndpi_serialization_format != ndpi_serialization_format_unknown) |
934 | 219k | { |
935 | 219k | if (ndpi_init_serializer(&newflow->ndpi_flow_serializer, |
936 | 219k | workflow->ndpi_serialization_format) != 0) |
937 | 0 | { |
938 | 0 | LOG(NDPI_LOG_ERROR, "ndpi serializer init failed\n"); |
939 | 0 | ndpi_flow_info_free_data(newflow); |
940 | 0 | ndpi_free(newflow); |
941 | 0 | return(NULL); |
942 | 0 | } |
943 | 219k | } |
944 | | |
945 | 219k | if(ndpi_tsearch(newflow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp) == NULL) { /* Add */ |
946 | 0 | ndpi_flow_info_free_data(newflow); |
947 | 0 | ndpi_free(newflow); |
948 | 0 | return(NULL); |
949 | 0 | } |
950 | 219k | workflow->stats.ndpi_flow_count++; |
951 | 219k | if(*proto == IPPROTO_TCP) |
952 | 128k | workflow->stats.flow_count[0]++; |
953 | 90.8k | else if(*proto == IPPROTO_UDP) |
954 | 83.1k | workflow->stats.flow_count[1]++; |
955 | 7.67k | else |
956 | 7.67k | workflow->stats.flow_count[2]++; |
957 | | |
958 | 219k | if(enable_flow_stats) { |
959 | 219k | newflow->entropy = ndpi_calloc(1, sizeof(struct ndpi_entropy)); |
960 | 219k | newflow->last_entropy = ndpi_calloc(1, sizeof(struct ndpi_entropy)); |
961 | 219k | if(!newflow->entropy || !newflow->last_entropy) { |
962 | 0 | ndpi_tdelete(newflow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp); |
963 | 0 | ndpi_flow_info_free_data(newflow); |
964 | 0 | ndpi_free(newflow); |
965 | 0 | return(NULL); |
966 | 0 | } |
967 | 219k | newflow->entropy->src2dst_pkt_len[newflow->entropy->src2dst_pkt_count] = l4_data_len; |
968 | 219k | newflow->entropy->src2dst_pkt_time[newflow->entropy->src2dst_pkt_count] = when; |
969 | 219k | if(newflow->entropy->src2dst_pkt_count == 0) { |
970 | 219k | newflow->entropy->src2dst_start = when; |
971 | 219k | } |
972 | 219k | newflow->entropy->src2dst_pkt_count++; |
973 | | // Non zero app data. |
974 | 219k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
975 | 211k | newflow->entropy->src2dst_opackets++; |
976 | 211k | newflow->entropy->src2dst_l4_bytes += l4_data_len; |
977 | 211k | } |
978 | 219k | } |
979 | 219k | return newflow; |
980 | 219k | } |
981 | 567k | } else { |
982 | 567k | struct ndpi_flow_info *rflow = *(struct ndpi_flow_info**)ret; |
983 | | |
984 | 567k | if(is_changed) { |
985 | 171k | *src_to_dst_direction = 0, rflow->bidirectional |= 1; |
986 | 171k | } |
987 | 395k | else { |
988 | 395k | *src_to_dst_direction = 1; |
989 | 395k | } |
990 | 567k | if(enable_flow_stats) { |
991 | 567k | if(*src_to_dst_direction) { |
992 | 395k | if(rflow->entropy->src2dst_pkt_count < max_num_packets_per_flow) { |
993 | 395k | rflow->entropy->src2dst_pkt_len[rflow->entropy->src2dst_pkt_count] = l4_data_len; |
994 | 395k | rflow->entropy->src2dst_pkt_time[rflow->entropy->src2dst_pkt_count] = when; |
995 | 395k | rflow->entropy->src2dst_l4_bytes += l4_data_len; |
996 | 395k | rflow->entropy->src2dst_pkt_count++; |
997 | 395k | } |
998 | | // Non zero app data. |
999 | 395k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
1000 | 354k | rflow->entropy->src2dst_opackets++; |
1001 | 354k | } |
1002 | 395k | } else { |
1003 | 171k | if(rflow->entropy->dst2src_pkt_count < max_num_packets_per_flow) { |
1004 | 171k | rflow->entropy->dst2src_pkt_len[rflow->entropy->dst2src_pkt_count] = l4_data_len; |
1005 | 171k | rflow->entropy->dst2src_pkt_time[rflow->entropy->dst2src_pkt_count] = when; |
1006 | 171k | if(rflow->entropy->dst2src_pkt_count == 0) { |
1007 | 51.1k | rflow->entropy->dst2src_start = when; |
1008 | 51.1k | } |
1009 | 171k | rflow->entropy->dst2src_l4_bytes += l4_data_len; |
1010 | 171k | rflow->entropy->dst2src_pkt_count++; |
1011 | 171k | } |
1012 | | // Non zero app data. |
1013 | 171k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
1014 | 150k | rflow->entropy->dst2src_opackets++; |
1015 | 150k | } |
1016 | 171k | } |
1017 | 567k | } |
1018 | | |
1019 | 567k | return(rflow); |
1020 | 567k | } |
1021 | 786k | } |
1022 | | |
1023 | | /* ****************************************************** */ |
1024 | | |
1025 | | static struct ndpi_flow_info *get_ndpi_flow_info6(struct ndpi_workflow * workflow, |
1026 | | u_int16_t vlan_id, |
1027 | | ndpi_packet_tunnel tunnel_type, |
1028 | | const struct ndpi_ipv6hdr *iph6, |
1029 | | u_int16_t ipsize, |
1030 | | struct ndpi_tcphdr **tcph, |
1031 | | struct ndpi_udphdr **udph, |
1032 | | u_int16_t *sport, u_int16_t *dport, |
1033 | | u_int8_t *proto, |
1034 | | u_int8_t **payload, |
1035 | | u_int16_t *payload_len, |
1036 | | u_int8_t *src_to_dst_direction, |
1037 | 70.5k | pkt_timeval when) { |
1038 | 70.5k | struct ndpi_iphdr iph; |
1039 | | |
1040 | 70.5k | if(ipsize < 40) |
1041 | 10 | return(NULL); |
1042 | 70.5k | memset(&iph, 0, sizeof(iph)); |
1043 | 70.5k | iph.version = IPVERSION; |
1044 | 70.5k | iph.saddr = iph6->ip6_src.u6_addr.u6_addr32[2] + iph6->ip6_src.u6_addr.u6_addr32[3]; |
1045 | 70.5k | iph.daddr = iph6->ip6_dst.u6_addr.u6_addr32[2] + iph6->ip6_dst.u6_addr.u6_addr32[3]; |
1046 | 70.5k | u_int8_t l4proto = iph6->ip6_hdr.ip6_un1_nxt; |
1047 | 70.5k | u_int16_t ip_len = ntohs(iph6->ip6_hdr.ip6_un1_plen); |
1048 | 70.5k | const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr)); |
1049 | 70.5k | if(ipsize < sizeof(struct ndpi_ipv6hdr) + ip_len) |
1050 | 12 | return(NULL); |
1051 | 70.5k | if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &l4proto) != 0) { |
1052 | 26 | return(NULL); |
1053 | 26 | } |
1054 | 70.5k | iph.protocol = l4proto; |
1055 | | |
1056 | 70.5k | return(get_ndpi_flow_info(workflow, 6, vlan_id, tunnel_type, |
1057 | 70.5k | &iph, iph6, ipsize, |
1058 | 70.5k | ip_len, l4ptr - (const u_int8_t *)iph6, |
1059 | 70.5k | tcph, udph, sport, dport, |
1060 | 70.5k | proto, payload, |
1061 | 70.5k | payload_len, src_to_dst_direction, when)); |
1062 | 70.5k | } |
1063 | | |
1064 | | /* ****************************************************** */ |
1065 | | |
1066 | 837k | u_int8_t is_ndpi_proto(struct ndpi_flow_info *flow, u_int16_t id) { |
1067 | 837k | if((flow->detected_protocol.proto.master_protocol == id) |
1068 | 784k | || (flow->detected_protocol.proto.app_protocol == id)) |
1069 | 73.0k | return(1); |
1070 | 764k | else |
1071 | 764k | return(0); |
1072 | 837k | } |
1073 | | |
1074 | | /* ****************************************************** */ |
1075 | | |
1076 | 12.3k | void correct_csv_data_field(char* data) { |
1077 | | /* Replace , with ; to avoid issues with CSVs */ |
1078 | 12.3k | u_int i; |
1079 | 192k | for(i=0; data[i] != '\0'; i++) if(data[i] == ',') data[i] = ';'; |
1080 | 12.3k | } |
1081 | | |
1082 | | /* ****************************************************** */ |
1083 | | |
1084 | 610k | u_int8_t plen2slot(u_int16_t plen) { |
1085 | | /* |
1086 | | Slots [32 bytes lenght] |
1087 | | 0..31, 32..63 ... |
1088 | | */ |
1089 | | |
1090 | 610k | if(plen > PLEN_MAX) |
1091 | 3.66k | return(PLEN_NUM_BINS-1); |
1092 | 606k | else |
1093 | 606k | return(plen/PLEN_BIN_LEN); |
1094 | 610k | } |
1095 | | |
1096 | | /* ****************************************************** */ |
1097 | | |
1098 | | static void dump_flow_fingerprint(struct ndpi_workflow * workflow, |
1099 | 0 | struct ndpi_flow_info *flow) { |
1100 | 0 | ndpi_serializer serializer; |
1101 | 0 | bool rc; |
1102 | |
|
1103 | 0 | if(ndpi_init_serializer(&serializer, ndpi_serialization_format_json) == -1) |
1104 | 0 | return; |
1105 | | |
1106 | 0 | ndpi_serialize_start_of_block(&serializer, "fingerprint"); |
1107 | 0 | rc = ndpi_serialize_flow_fingerprint(workflow->ndpi_struct, flow->ndpi_flow, &serializer); |
1108 | 0 | ndpi_serialize_end_of_block(&serializer); |
1109 | |
|
1110 | 0 | if(rc) { |
1111 | 0 | char buf[64], *buffer; |
1112 | 0 | u_int32_t buffer_len; |
1113 | |
|
1114 | 0 | ndpi_serialize_string_uint32(&serializer, "proto", flow->protocol); |
1115 | 0 | ndpi_serialize_string_string(&serializer, "cli_ip", flow->src_name ? flow->src_name : ""); |
1116 | 0 | ndpi_serialize_string_uint32(&serializer, "cli_port", ntohs(flow->src_port)); |
1117 | 0 | ndpi_serialize_string_string(&serializer, "srv_ip", flow->dst_name ? flow->dst_name : ""); |
1118 | 0 | ndpi_serialize_string_uint32(&serializer, "srv_port", ntohs(flow->dst_port)); |
1119 | 0 | ndpi_serialize_string_string(&serializer, "proto", |
1120 | 0 | ndpi_protocol2name(workflow->ndpi_struct, |
1121 | 0 | flow->detected_protocol.proto, |
1122 | 0 | buf, sizeof(buf))); |
1123 | |
|
1124 | 0 | if(flow->server_hostname) |
1125 | 0 | ndpi_serialize_string_string(&serializer, "server_hostname", flow->server_hostname); |
1126 | |
|
1127 | 0 | buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len); |
1128 | 0 | fprintf(fingerprint_fp, "%s\n", buffer); |
1129 | 0 | } |
1130 | |
|
1131 | 0 | ndpi_term_serializer(&serializer); |
1132 | 0 | } |
1133 | | |
1134 | | |
1135 | | static void add_to_address_port_list(ndpi_address_port_list *list, ndpi_address_port *ap) |
1136 | 228k | { |
1137 | 228k | int new_num; |
1138 | 228k | void *new_buf; |
1139 | 228k | unsigned int i; |
1140 | | |
1141 | 228k | if(ap->port == 0) |
1142 | 216k | return; |
1143 | | |
1144 | | /* Avoid saving duplicates */ |
1145 | 17.5k | for(i = 0; i < list->num_aps; i++) |
1146 | 13.0k | if(memcmp(&list->aps[i], ap, sizeof(*ap)) == 0) |
1147 | 7.02k | return; |
1148 | | |
1149 | 4.41k | if(list->num_aps == list->num_aps_allocated) { |
1150 | 4.00k | new_num = 1 + list->num_aps_allocated * 2; |
1151 | 4.00k | new_buf = ndpi_realloc(list->aps, list->num_aps_allocated * sizeof(ndpi_address_port), |
1152 | 4.00k | new_num * sizeof(ndpi_address_port)); |
1153 | 4.00k | if(!new_buf) |
1154 | 0 | return; |
1155 | 4.00k | list->aps = new_buf; |
1156 | 4.00k | list->num_aps_allocated = new_num; |
1157 | 4.00k | } |
1158 | 4.41k | memcpy(&list->aps[list->num_aps++], ap, sizeof(ndpi_address_port)); |
1159 | 4.41k | } |
1160 | | |
1161 | | /* ****************************************************** */ |
1162 | | |
1163 | 581k | static void process_ndpi_monitoring_info(struct ndpi_flow_info *flow) { |
1164 | 581k | if(!flow->ndpi_flow || !flow->ndpi_flow->monit) |
1165 | 534k | return; |
1166 | | |
1167 | 46.4k | if(flow->monitoring_state == 0 && |
1168 | 26.1k | flow->ndpi_flow->state == NDPI_STATE_MONITORING) { |
1169 | | /* We just moved to monitoring state */ |
1170 | 261 | flow->monitoring_state = 1; |
1171 | 261 | flow->num_packets_before_monitoring = flow->ndpi_flow->packet_direction_complete_counter[0] + flow->ndpi_flow->packet_direction_complete_counter[1]; |
1172 | 261 | } |
1173 | | |
1174 | | /* In theory, we should check only for STUN. |
1175 | | However since we sometimes might not have STUN in protocol classification |
1176 | | (because we have only two protocols in flow->ndpi_flow->detected_protocol_stack[]) |
1177 | | we need to check also for the other "master" protocols set by STUN dissector |
1178 | | See at the beginning of the STUN c file for further details |
1179 | | */ |
1180 | 46.4k | if(flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_STUN || |
1181 | 43.6k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_STUN || |
1182 | 20.8k | flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_DTLS || |
1183 | 20.7k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_DTLS || |
1184 | 15.6k | flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_SRTP || |
1185 | 45.6k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_SRTP) { |
1186 | | |
1187 | 45.6k | add_to_address_port_list(&flow->stun.mapped_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.mapped_address); |
1188 | 45.6k | add_to_address_port_list(&flow->stun.other_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.other_address); |
1189 | 45.6k | add_to_address_port_list(&flow->stun.peer_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.peer_address); |
1190 | 45.6k | add_to_address_port_list(&flow->stun.relayed_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.relayed_address); |
1191 | 45.6k | add_to_address_port_list(&flow->stun.response_origin, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.response_origin); |
1192 | 45.6k | flow->multimedia_flow_types |= flow->ndpi_flow->flow_multimedia_types; |
1193 | | |
1194 | 45.6k | flow->stun.rtp_counters[0] = flow->ndpi_flow->stun.rtp_counters[0]; |
1195 | 45.6k | flow->stun.rtp_counters[1] = flow->ndpi_flow->stun.rtp_counters[1]; |
1196 | 45.6k | } |
1197 | 46.4k | } |
1198 | | |
1199 | | /* ****************************************************** */ |
1200 | | |
1201 | | static void serialize_monitoring_metadata(struct ndpi_flow_info *flow) |
1202 | 307 | { |
1203 | 307 | unsigned int i; |
1204 | 307 | char buf[64]; |
1205 | | |
1206 | 307 | if(!flow->ndpi_flow->monit) |
1207 | 46 | return; |
1208 | | |
1209 | 261 | ndpi_serialize_start_of_block(&flow->ndpi_flow_serializer, "monitoring"); |
1210 | | |
1211 | 261 | switch(flow->detected_protocol.proto.master_protocol ? flow->detected_protocol.proto.master_protocol : flow->detected_protocol.proto.app_protocol) { |
1212 | 88 | case NDPI_PROTOCOL_STUN: |
1213 | 148 | case NDPI_PROTOCOL_DTLS: |
1214 | 255 | case NDPI_PROTOCOL_SRTP: |
1215 | 255 | ndpi_serialize_start_of_block(&flow->ndpi_flow_serializer, "stun"); |
1216 | | |
1217 | 255 | if(flow->stun.mapped_address.num_aps > 0) { |
1218 | 214 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "mapped_address"); |
1219 | 653 | for(i = 0; i < flow->stun.mapped_address.num_aps; i++) { |
1220 | 439 | if(flow->stun.mapped_address.aps[i].port > 0) { |
1221 | 439 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "mapped_address", |
1222 | 439 | print_ndpi_address_port(&flow->stun.mapped_address.aps[i], buf, sizeof(buf))); |
1223 | 439 | } |
1224 | 439 | } |
1225 | 214 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1226 | 214 | } |
1227 | | |
1228 | 255 | if(flow->stun.other_address.num_aps > 0) { |
1229 | 18 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "other_address"); |
1230 | 39 | for(i = 0; i < flow->stun.other_address.num_aps; i++) { |
1231 | 21 | if(flow->stun.other_address.aps[i].port > 0) { |
1232 | 21 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "other_address", |
1233 | 21 | print_ndpi_address_port(&flow->stun.other_address.aps[i], buf, sizeof(buf))); |
1234 | 21 | } |
1235 | 21 | } |
1236 | 18 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1237 | 18 | } |
1238 | | |
1239 | 255 | if(flow->stun.peer_address.num_aps > 0) { |
1240 | 92 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "peer_address"); |
1241 | 405 | for(i = 0; i < flow->stun.peer_address.num_aps; i++) { |
1242 | 313 | if(flow->stun.peer_address.aps[i].port > 0) { |
1243 | 313 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "peer_address", |
1244 | 313 | print_ndpi_address_port(&flow->stun.peer_address.aps[i], buf, sizeof(buf))); |
1245 | 313 | } |
1246 | 313 | } |
1247 | 92 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1248 | 92 | } |
1249 | | |
1250 | 255 | if(flow->stun.relayed_address.num_aps > 0) { |
1251 | 123 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "relayed_address"); |
1252 | 274 | for(i = 0; i < flow->stun.relayed_address.num_aps; i++) { |
1253 | 151 | if(flow->stun.relayed_address.aps[i].port > 0) { |
1254 | 151 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "relayed_address", |
1255 | 151 | print_ndpi_address_port(&flow->stun.relayed_address.aps[i], buf, sizeof(buf))); |
1256 | 151 | } |
1257 | 151 | } |
1258 | 123 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1259 | 123 | } |
1260 | | |
1261 | 255 | if(flow->stun.response_origin.num_aps > 0) { |
1262 | 22 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "response_origin"); |
1263 | 50 | for(i = 0; i < flow->stun.response_origin.num_aps; i++) { |
1264 | 28 | if(flow->stun.response_origin.aps[i].port > 0) { |
1265 | 28 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "response_origin", |
1266 | 28 | print_ndpi_address_port(&flow->stun.response_origin.aps[i], buf, sizeof(buf))); |
1267 | 28 | } |
1268 | 28 | } |
1269 | 22 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1270 | 22 | } |
1271 | | |
1272 | 255 | ndpi_serialize_end_of_block(&flow->ndpi_flow_serializer); /* stun */ |
1273 | | |
1274 | 255 | break; |
1275 | 261 | } |
1276 | | |
1277 | 261 | ndpi_serialize_end_of_block(&flow->ndpi_flow_serializer); |
1278 | 261 | } |
1279 | | |
1280 | | /* ****************************************************** */ |
1281 | | |
1282 | 267k | void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_flow_info *flow) { |
1283 | 267k | u_int i; |
1284 | 267k | char out[128], *s; |
1285 | | |
1286 | 267k | if(!flow->ndpi_flow) return; |
1287 | | |
1288 | 219k | flow->info_type = INFO_INVALID; |
1289 | | |
1290 | 219k | s = ndpi_get_flow_risk_info(flow->ndpi_flow, out, sizeof(out), 0 /* text */); |
1291 | | |
1292 | 219k | if(s != NULL) |
1293 | 185k | flow->risk_str = ndpi_strdup(s); |
1294 | | |
1295 | 219k | flow->confidence = flow->ndpi_flow->confidence; |
1296 | | |
1297 | 219k | flow->num_dissector_calls = flow->ndpi_flow->num_dissector_calls; |
1298 | | |
1299 | 219k | ndpi_snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s", |
1300 | 219k | flow->ndpi_flow->host_server_name); |
1301 | | |
1302 | 219k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MINING)) { |
1303 | 87 | ndpi_snprintf(flow->mining.currency, sizeof(flow->mining.currency), "%s", |
1304 | 87 | flow->ndpi_flow->protos.mining.currency); |
1305 | 87 | } |
1306 | | |
1307 | 219k | flow->risk = flow->ndpi_flow->risk; |
1308 | | |
1309 | 219k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DHCP)) { |
1310 | 624 | if(flow->ndpi_flow->protos.dhcp.fingerprint[0] != '\0') |
1311 | 234 | flow->dhcp_fingerprint = ndpi_strdup(flow->ndpi_flow->protos.dhcp.fingerprint); |
1312 | | |
1313 | 624 | if(flow->ndpi_flow->protos.dhcp.class_ident[0] != '\0') |
1314 | 143 | flow->dhcp_class_ident = ndpi_strdup(flow->ndpi_flow->protos.dhcp.class_ident); |
1315 | 218k | } else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_BITTORRENT) && |
1316 | 10.8k | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DNS) && |
1317 | 10.8k | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TLS)) { |
1318 | 10.7k | u_int j; |
1319 | | |
1320 | 10.7k | if(flow->ndpi_flow->protos.bittorrent.hash[0] != '\0') { |
1321 | 98 | u_int avail = sizeof(flow->ndpi_flow->protos.bittorrent.hash) * 2 + 1; |
1322 | 98 | flow->bittorent_hash = ndpi_malloc(avail); |
1323 | | |
1324 | 98 | if(flow->bittorent_hash) { |
1325 | 2.05k | for(i=0, j = 0; i < sizeof(flow->ndpi_flow->protos.bittorrent.hash); i++) { |
1326 | 1.96k | snprintf(&flow->bittorent_hash[j], avail-j, "%02x", |
1327 | 1.96k | flow->ndpi_flow->protos.bittorrent.hash[i]); |
1328 | | |
1329 | 1.96k | j += 2; |
1330 | 1.96k | } |
1331 | | |
1332 | 98 | flow->bittorent_hash[j] = '\0'; |
1333 | 98 | } |
1334 | 98 | } |
1335 | 10.7k | } |
1336 | | /* TIVOCONNECT */ |
1337 | 207k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TIVOCONNECT)) { |
1338 | 181 | flow->info_type = INFO_TIVOCONNECT; |
1339 | 181 | ndpi_snprintf(flow->tivoconnect.identity_uuid, sizeof(flow->tivoconnect.identity_uuid), |
1340 | 181 | "%s", flow->ndpi_flow->protos.tivoconnect.identity_uuid); |
1341 | 181 | ndpi_snprintf(flow->tivoconnect.machine, sizeof(flow->tivoconnect.machine), |
1342 | 181 | "%s", flow->ndpi_flow->protos.tivoconnect.machine); |
1343 | 181 | ndpi_snprintf(flow->tivoconnect.platform, sizeof(flow->tivoconnect.platform), |
1344 | 181 | "%s", flow->ndpi_flow->protos.tivoconnect.platform); |
1345 | 181 | ndpi_snprintf(flow->tivoconnect.services, sizeof(flow->tivoconnect.services), |
1346 | 181 | "%s", flow->ndpi_flow->protos.tivoconnect.services); |
1347 | 181 | } |
1348 | | /* SOFTETHER */ |
1349 | 207k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SOFTETHER) && |
1350 | 254 | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_HTTP)) { |
1351 | 230 | flow->info_type = INFO_SOFTETHER; |
1352 | 230 | ndpi_snprintf(flow->softether.ip, sizeof(flow->softether.ip), "%s", |
1353 | 230 | flow->ndpi_flow->protos.softether.ip); |
1354 | 230 | ndpi_snprintf(flow->softether.port, sizeof(flow->softether.port), "%s", |
1355 | 230 | flow->ndpi_flow->protos.softether.port); |
1356 | 230 | ndpi_snprintf(flow->softether.hostname, sizeof(flow->softether.hostname), "%s", |
1357 | 230 | flow->ndpi_flow->protos.softether.hostname); |
1358 | 230 | ndpi_snprintf(flow->softether.fqdn, sizeof(flow->softether.fqdn), "%s", |
1359 | 230 | flow->ndpi_flow->protos.softether.fqdn); |
1360 | 230 | } |
1361 | | /* SERVICE_LOCATION */ |
1362 | 207k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SERVICE_LOCATION)) { |
1363 | 3.96k | size_t i; |
1364 | | |
1365 | 3.96k | flow->info_type = INFO_GENERIC; |
1366 | 3.96k | flow->info[0] = 0; |
1367 | 3.96k | if (flow->ndpi_flow->protos.slp.url_count > 0) |
1368 | 758 | strncat(flow->info, "URL(s): ", sizeof(flow->info)-1); |
1369 | | |
1370 | 4.83k | for (i = 0; i < flow->ndpi_flow->protos.slp.url_count; ++i) { |
1371 | 868 | size_t length = strlen(flow->info); |
1372 | | |
1373 | 868 | strncat(flow->info + length, flow->ndpi_flow->protos.slp.url[i], |
1374 | 868 | sizeof(flow->info) - length); |
1375 | 868 | length = strlen(flow->info); |
1376 | | |
1377 | 868 | if (i < (size_t)flow->ndpi_flow->protos.slp.url_count - 1) |
1378 | 110 | strncat(flow->info + length, ", ", sizeof(flow->info) - length); |
1379 | 868 | } |
1380 | 3.96k | } |
1381 | | /* NATPMP */ |
1382 | 203k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_NATPMP)) { |
1383 | 339 | flow->info_type = INFO_NATPMP; |
1384 | 339 | flow->natpmp.result_code = flow->ndpi_flow->protos.natpmp.result_code; |
1385 | 339 | flow->natpmp.internal_port = flow->ndpi_flow->protos.natpmp.internal_port; |
1386 | 339 | flow->natpmp.external_port = flow->ndpi_flow->protos.natpmp.external_port; |
1387 | 339 | inet_ntop(AF_INET, &flow->ndpi_flow->protos.natpmp.external_address.ipv4, &flow->natpmp.ip[0], sizeof(flow->natpmp.ip)); |
1388 | 339 | } |
1389 | | /* DISCORD */ |
1390 | 203k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DISCORD) && |
1391 | 902 | !ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack) && |
1392 | 871 | flow->ndpi_flow->protos.discord.client_ip[0] != '\0') { |
1393 | 80 | flow->info_type = INFO_GENERIC; |
1394 | 80 | ndpi_snprintf(flow->info, sizeof(flow->info), "Client IP: %s", |
1395 | 80 | flow->ndpi_flow->protos.discord.client_ip); |
1396 | 80 | } |
1397 | | /* DNS */ |
1398 | 203k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DNS)) { |
1399 | 7.10k | if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[0] == 0) |
1400 | 6.99k | { |
1401 | 6.99k | flow->info_type = INFO_GENERIC; |
1402 | 6.99k | inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[0].ipv4, flow->info, sizeof(flow->info)); |
1403 | 6.99k | } else { |
1404 | 110 | flow->info_type = INFO_GENERIC; |
1405 | 110 | inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[0].ipv6, flow->info, sizeof(flow->info)); |
1406 | | |
1407 | | /* For consistency across platforms replace :0: with :: */ |
1408 | 110 | ndpi_patchIPv6Address(flow->info); |
1409 | 110 | } |
1410 | | |
1411 | 7.10k | if(flow->ndpi_flow->protos.dns.geolocation_iata_code[0] != '\0') |
1412 | 23 | strcpy(flow->dns.geolocation_iata_code, flow->ndpi_flow->protos.dns.geolocation_iata_code); |
1413 | | |
1414 | 7.10k | if(flow->ndpi_flow->protos.dns.ptr_domain_name[0] != '\0') |
1415 | 327 | strcpy(flow->dns.ptr_domain_name, flow->ndpi_flow->protos.dns.ptr_domain_name); |
1416 | | |
1417 | 7.10k | flow->dns.transaction_id = flow->ndpi_flow->protos.dns.transaction_id; |
1418 | | |
1419 | | #if 0 |
1420 | | if(0) { |
1421 | | u_int8_t i; |
1422 | | |
1423 | | for(i=0; i<flow->ndpi_flow->protos.dns.num_rsp_addr; i++) { |
1424 | | char buf[64]; |
1425 | | |
1426 | | if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[i] == 0) { |
1427 | | inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv4, buf, sizeof(buf)); |
1428 | | } else { |
1429 | | inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf)); |
1430 | | } |
1431 | | |
1432 | | printf("(%s) %s [ttl: %u]\n", flow->host_server_name, buf, flow->ndpi_flow->protos.dns.rsp_addr_ttl[i]); |
1433 | | } |
1434 | | } |
1435 | | #endif |
1436 | 7.10k | } |
1437 | | /* MDNS */ |
1438 | 195k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MDNS)) { |
1439 | 975 | flow->info_type = INFO_GENERIC; |
1440 | 975 | ndpi_snprintf(flow->info, sizeof(flow->info), "%s", flow->ndpi_flow->host_server_name); |
1441 | 975 | } |
1442 | | /* UBNTAC2 */ |
1443 | 194k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_UBNTAC2)) { |
1444 | 105 | flow->info_type = INFO_GENERIC; |
1445 | 105 | ndpi_snprintf(flow->info, sizeof(flow->info), "%s", flow->ndpi_flow->protos.ubntac2.version); |
1446 | 105 | } |
1447 | | /* FTP, IMAP, SMTP, POP3 */ |
1448 | 194k | else if(!ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack) && |
1449 | 174k | (ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_FTP_CONTROL) || |
1450 | 173k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_IMAP) || |
1451 | 173k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_POP) || |
1452 | 173k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_SMTP))) { |
1453 | 2.78k | flow->info_type = INFO_FTP_IMAP_POP_SMTP; |
1454 | 2.78k | ndpi_snprintf(flow->ftp_imap_pop_smtp.username, |
1455 | 2.78k | sizeof(flow->ftp_imap_pop_smtp.username), |
1456 | 2.78k | "%s", flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.username); |
1457 | 2.78k | ndpi_snprintf(flow->ftp_imap_pop_smtp.password, |
1458 | 2.78k | sizeof(flow->ftp_imap_pop_smtp.password), |
1459 | 2.78k | "%s", flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.password); |
1460 | 2.78k | flow->ftp_imap_pop_smtp.auth_failed = |
1461 | 2.78k | flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.auth_failed; |
1462 | 2.78k | } |
1463 | | /* TFTP */ |
1464 | 192k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TFTP)) { |
1465 | 571 | flow->info_type = INFO_GENERIC; |
1466 | 571 | if(flow->ndpi_flow->protos.tftp.filename[0] != '\0') |
1467 | 29 | ndpi_snprintf(flow->info, sizeof(flow->info), "Filename: %s", |
1468 | 29 | flow->ndpi_flow->protos.tftp.filename); |
1469 | 571 | } |
1470 | | /* KERBEROS */ |
1471 | 191k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_KERBEROS)) { |
1472 | 1.88k | flow->info_type = INFO_KERBEROS; |
1473 | 1.88k | ndpi_snprintf(flow->kerberos.domain, |
1474 | 1.88k | sizeof(flow->kerberos.domain), |
1475 | 1.88k | "%s", flow->ndpi_flow->protos.kerberos.domain); |
1476 | 1.88k | ndpi_snprintf(flow->kerberos.hostname, |
1477 | 1.88k | sizeof(flow->kerberos.hostname), |
1478 | 1.88k | "%s", flow->ndpi_flow->protos.kerberos.hostname); |
1479 | 1.88k | ndpi_snprintf(flow->kerberos.username, |
1480 | 1.88k | sizeof(flow->kerberos.username), |
1481 | 1.88k | "%s", flow->ndpi_flow->protos.kerberos.username); |
1482 | | /* COLLECTD */ |
1483 | 189k | } else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_COLLECTD)) { |
1484 | 40 | flow->info_type = INFO_GENERIC; |
1485 | 40 | if(flow->ndpi_flow->protos.collectd.client_username[0] != '\0') |
1486 | 1 | ndpi_snprintf(flow->info, sizeof(flow->info), "Username: %s", |
1487 | 1 | flow->ndpi_flow->protos.collectd.client_username); |
1488 | 40 | } |
1489 | | /* SIP */ |
1490 | 189k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SIP)) { |
1491 | 488 | flow->info_type = INFO_SIP; |
1492 | 488 | if(flow->ndpi_flow->protos.sip.from) |
1493 | 280 | ndpi_snprintf(flow->sip.from, sizeof(flow->sip.from), "%s", flow->ndpi_flow->protos.sip.from); |
1494 | 488 | if(flow->ndpi_flow->protos.sip.from_imsi[0] != '\0') |
1495 | 0 | ndpi_snprintf(flow->sip.from_imsi, sizeof(flow->sip.from_imsi), "%s", flow->ndpi_flow->protos.sip.from_imsi); |
1496 | 488 | if(flow->ndpi_flow->protos.sip.to) |
1497 | 280 | ndpi_snprintf(flow->sip.to, sizeof(flow->sip.to), "%s", flow->ndpi_flow->protos.sip.to); |
1498 | 488 | if(flow->ndpi_flow->protos.sip.to_imsi[0] != '\0') |
1499 | 5 | ndpi_snprintf(flow->sip.to_imsi, sizeof(flow->sip.to_imsi), "%s", flow->ndpi_flow->protos.sip.to_imsi); |
1500 | 488 | } |
1501 | | /* BFCP */ |
1502 | 189k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_BFCP)) { |
1503 | 76 | flow->info_type = INFO_BFCP; |
1504 | 76 | flow->bfcp.conference_id = flow->ndpi_flow->protos.bfcp.conference_id; |
1505 | 76 | flow->bfcp.user_id = flow->ndpi_flow->protos.bfcp.user_id; |
1506 | 76 | } |
1507 | | /* TELNET */ |
1508 | 189k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TELNET)) { |
1509 | 598 | if(flow->ndpi_flow->protos.telnet.username[0] != '\0') |
1510 | 66 | flow->telnet.username = ndpi_strdup(flow->ndpi_flow->protos.telnet.username); |
1511 | 598 | if(flow->ndpi_flow->protos.telnet.password[0] != '\0') |
1512 | 30 | flow->telnet.password = ndpi_strdup(flow->ndpi_flow->protos.telnet.password); |
1513 | 188k | } else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SSH)) { |
1514 | 837 | ndpi_snprintf(flow->host_server_name, |
1515 | 837 | sizeof(flow->host_server_name), "%s", |
1516 | 837 | flow->ndpi_flow->protos.ssh.client_signature); |
1517 | 837 | ndpi_snprintf(flow->ssh_tls.server_info, sizeof(flow->ssh_tls.server_info), "%s", |
1518 | 837 | flow->ndpi_flow->protos.ssh.server_signature); |
1519 | 837 | ndpi_snprintf(flow->ssh_tls.client_hassh, sizeof(flow->ssh_tls.client_hassh), "%s", |
1520 | 837 | flow->ndpi_flow->protos.ssh.hassh_client); |
1521 | 837 | ndpi_snprintf(flow->ssh_tls.server_hassh, sizeof(flow->ssh_tls.server_hassh), "%s", |
1522 | 837 | flow->ndpi_flow->protos.ssh.hassh_server); |
1523 | 837 | } |
1524 | | /* TLS/QUIC/DTLS/MAIL_S/FTPS */ |
1525 | 187k | else if(ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack)) { |
1526 | 20.4k | flow->ssh_tls.ssl_version = flow->ndpi_flow->protos.tls_quic.ssl_version; |
1527 | 20.4k | flow->ssh_tls.quic_version = flow->ndpi_flow->protos.tls_quic.quic_version; |
1528 | | |
1529 | 20.4k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_QUIC)) |
1530 | 6.96k | flow->idle_timeout_sec = flow->ndpi_flow->protos.tls_quic.quic_idle_timeout_sec; |
1531 | | |
1532 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.server_names_len > 0 && flow->ndpi_flow->protos.tls_quic.server_names) |
1533 | 1.28k | flow->ssh_tls.server_names = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.server_names); |
1534 | | |
1535 | 20.4k | flow->ssh_tls.notBefore = flow->ndpi_flow->protos.tls_quic.notBefore; |
1536 | 20.4k | flow->ssh_tls.notAfter = flow->ndpi_flow->protos.tls_quic.notAfter; |
1537 | 20.4k | ndpi_snprintf(flow->ssh_tls.ja4_client, sizeof(flow->ssh_tls.ja4_client), "%s", |
1538 | 20.4k | flow->ndpi_flow->protos.tls_quic.ja4_client); |
1539 | | |
1540 | 20.4k | if(flow->ndpi_flow->ndpi.fingerprint) |
1541 | 8.40k | flow->ndpi_fingerprint = ndpi_strdup(flow->ndpi_flow->ndpi.fingerprint); |
1542 | | |
1543 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw) |
1544 | 8.18k | flow->ssh_tls.ja4_client_raw = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw); |
1545 | | |
1546 | 20.4k | ndpi_snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s", |
1547 | 20.4k | flow->ndpi_flow->protos.tls_quic.ja3_server); |
1548 | 20.4k | flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.tls_quic.server_unsafe_cipher; |
1549 | 20.4k | flow->ssh_tls.server_cipher = flow->ndpi_flow->protos.tls_quic.server_cipher; |
1550 | | |
1551 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.fingerprint_set) { |
1552 | 1.83k | memcpy(flow->ssh_tls.sha1_cert_fingerprint, |
1553 | 1.83k | flow->ndpi_flow->protos.tls_quic.sha1_certificate_fingerprint, 20); |
1554 | 1.83k | flow->ssh_tls.sha1_cert_fingerprint_set = 1; |
1555 | 1.83k | } |
1556 | | |
1557 | 20.4k | flow->ssh_tls.browser_heuristics = flow->ndpi_flow->protos.tls_quic.browser_heuristics; |
1558 | | |
1559 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.issuerDN) |
1560 | 1.50k | flow->ssh_tls.tls_issuerDN = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.issuerDN); |
1561 | | |
1562 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.subjectDN) |
1563 | 1.60k | flow->ssh_tls.tls_subjectDN = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.subjectDN); |
1564 | | |
1565 | 20.4k | flow->ssh_tls.encrypted_ch.version = flow->ndpi_flow->protos.tls_quic.encrypted_ch.version; |
1566 | | |
1567 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.tls_supported_versions) { |
1568 | 5.37k | if((flow->ssh_tls.tls_supported_versions = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.tls_supported_versions)) != NULL) |
1569 | 5.37k | correct_csv_data_field(flow->ssh_tls.tls_supported_versions); |
1570 | 5.37k | } |
1571 | | |
1572 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.advertised_alpns) { |
1573 | 6.14k | if((flow->ssh_tls.advertised_alpns = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.advertised_alpns)) != NULL) |
1574 | 6.14k | correct_csv_data_field(flow->ssh_tls.advertised_alpns); |
1575 | 6.14k | } |
1576 | | |
1577 | 20.4k | if(flow->ndpi_flow->protos.tls_quic.negotiated_alpn) { |
1578 | 864 | if((flow->ssh_tls.negotiated_alpn = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.negotiated_alpn)) != NULL) |
1579 | 864 | correct_csv_data_field(flow->ssh_tls.negotiated_alpn); |
1580 | 864 | } |
1581 | | |
1582 | 20.4k | if(flow->protocol == IPPROTO_TCP) { |
1583 | 12.5k | if(enable_doh_dot_detection) { |
1584 | | /* For TLS we use TLS block lenght instead of payload lenght */ |
1585 | 0 | ndpi_reset_bin(&flow->payload_len_bin); |
1586 | | |
1587 | 0 | for(i=0; i<flow->ndpi_flow->l4.tcp.tls.num_tls_blocks; i++) { |
1588 | 0 | u_int16_t len = abs(flow->ndpi_flow->l4.tcp.tls.tls_blocks[i].len); |
1589 | | |
1590 | | /* printf("[TLS_LEN] %u\n", len); */ |
1591 | 0 | ndpi_inc_bin(&flow->payload_len_bin, plen2slot(len), 1); |
1592 | 0 | } |
1593 | 0 | } |
1594 | | |
1595 | 12.5k | flow->ssh_tls.num_blocks = flow->ndpi_flow->l4.tcp.tls.num_tls_blocks; |
1596 | 12.5k | memcpy(flow->ssh_tls.blocks, flow->ndpi_flow->l4.tcp.tls.tls_blocks, sizeof(flow->ndpi_flow->l4.tcp.tls.tls_blocks)); |
1597 | 12.5k | } |
1598 | 20.4k | } |
1599 | | /* FASTCGI */ |
1600 | 167k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_FASTCGI)) { |
1601 | 189 | flow->info_type = INFO_FASTCGI; |
1602 | 189 | flow->fast_cgi.method = flow->ndpi_flow->protos.fast_cgi.method; |
1603 | 189 | ndpi_snprintf(flow->fast_cgi.user_agent, sizeof(flow->fast_cgi.user_agent), "%s", flow->ndpi_flow->protos.fast_cgi.user_agent); |
1604 | 189 | ndpi_snprintf(flow->fast_cgi.url, sizeof(flow->fast_cgi.url), "%s", flow->ndpi_flow->protos.fast_cgi.url); |
1605 | 189 | } |
1606 | | |
1607 | 219k | if(!monitoring_enabled) { |
1608 | 0 | add_to_address_port_list(&flow->stun.mapped_address, &flow->ndpi_flow->stun.mapped_address); |
1609 | 0 | add_to_address_port_list(&flow->stun.peer_address, &flow->ndpi_flow->stun.peer_address); |
1610 | 0 | add_to_address_port_list(&flow->stun.relayed_address, &flow->ndpi_flow->stun.relayed_address); |
1611 | 0 | add_to_address_port_list(&flow->stun.response_origin, &flow->ndpi_flow->stun.response_origin); |
1612 | 0 | add_to_address_port_list(&flow->stun.other_address, &flow->ndpi_flow->stun.other_address); |
1613 | 0 | } |
1614 | | |
1615 | 219k | flow->multimedia_flow_types |= flow->ndpi_flow->flow_multimedia_types; |
1616 | | |
1617 | 219k | if(flow->ndpi_flow->tcp.fingerprint) { |
1618 | 54.1k | char buf[128]; |
1619 | | |
1620 | 54.1k | snprintf(buf, sizeof(buf), "%s/%s", flow->ndpi_flow->tcp.fingerprint, |
1621 | 54.1k | ndpi_print_os_hint(flow->ndpi_flow->tcp.os_hint)); |
1622 | 54.1k | flow->tcp_fingerprint = ndpi_strdup(buf); |
1623 | 54.1k | } |
1624 | | |
1625 | | /* HTTP metadata are "global" not in `flow->ndpi_flow->protos` union; for example, we can have |
1626 | | HTTP/BitTorrent and in that case we want to export also HTTP attributes */ |
1627 | 219k | if(ndpi_stack_is_http_like(&flow->detected_protocol.protocol_stack)) { /* HTTP, HTTP_PROXY, HTTP_CONNECT */ |
1628 | 37.3k | if(flow->ndpi_flow->http.url != NULL) { |
1629 | 23.9k | ndpi_snprintf(flow->http.url, sizeof(flow->http.url), "%s", flow->ndpi_flow->http.url); |
1630 | 23.9k | } |
1631 | | |
1632 | 37.3k | flow->http.response_status_code = flow->ndpi_flow->http.response_status_code; |
1633 | 37.3k | ndpi_snprintf(flow->http.content_type, sizeof(flow->http.content_type), "%s", flow->ndpi_flow->http.content_type ? flow->ndpi_flow->http.content_type : ""); |
1634 | 37.3k | ndpi_snprintf(flow->http.server, sizeof(flow->http.server), "%s", flow->ndpi_flow->http.server ? flow->ndpi_flow->http.server : ""); |
1635 | 37.3k | ndpi_snprintf(flow->http.request_content_type, sizeof(flow->http.request_content_type), "%s", flow->ndpi_flow->http.request_content_type ? flow->ndpi_flow->http.request_content_type : ""); |
1636 | 37.3k | ndpi_snprintf(flow->http.nat_ip, sizeof(flow->http.nat_ip), "%s", flow->ndpi_flow->http.nat_ip ? flow->ndpi_flow->http.nat_ip : ""); |
1637 | 37.3k | ndpi_snprintf(flow->http.filename, sizeof(flow->http.filename), "%s", flow->ndpi_flow->http.filename ? flow->ndpi_flow->http.filename : ""); |
1638 | 37.3k | ndpi_snprintf(flow->http.username, sizeof(flow->http.username), "%s", flow->ndpi_flow->http.username ? flow->ndpi_flow->http.username : ""); |
1639 | 37.3k | ndpi_snprintf(flow->http.password, sizeof(flow->http.password), "%s", flow->ndpi_flow->http.password ? flow->ndpi_flow->http.password : ""); |
1640 | 37.3k | } |
1641 | | |
1642 | 219k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_RTP)) |
1643 | 423 | memcpy(&flow->rtp, &flow->ndpi_flow->rtp, sizeof(flow->rtp)); |
1644 | | |
1645 | 219k | ndpi_snprintf(flow->http.user_agent, |
1646 | 219k | sizeof(flow->http.user_agent), |
1647 | 219k | "%s", (flow->ndpi_flow->http.user_agent ? flow->ndpi_flow->http.user_agent : "")); |
1648 | | |
1649 | 219k | { |
1650 | 219k | ndpi_ip_addr_t ip_addr; |
1651 | 219k | struct ndpi_address_cache_item *c; |
1652 | | |
1653 | 219k | memset(&ip_addr, 0, sizeof(ip_addr)); |
1654 | | |
1655 | 219k | if(flow->ip_version == 4) |
1656 | 200k | ip_addr.ipv4 = flow->dst_ip; |
1657 | 18.4k | else |
1658 | 18.4k | memcpy(&ip_addr.ipv6, &flow->dst_ip6, sizeof(struct ndpi_in6_addr)); |
1659 | | |
1660 | 219k | c = ndpi_cache_address_find(workflow->ndpi_struct, ip_addr); |
1661 | | |
1662 | 219k | if(c) { |
1663 | 5.83k | flow->server_hostname = ndpi_strdup(c->hostname); |
1664 | 5.83k | } |
1665 | 219k | } |
1666 | | |
1667 | 219k | if (workflow->ndpi_serialization_format != ndpi_serialization_format_unknown) { |
1668 | 219k | if (ndpi_flow2json(workflow->ndpi_struct, flow->ndpi_flow, |
1669 | 219k | flow->ip_version, flow->protocol, |
1670 | 219k | flow->vlan_id, |
1671 | 219k | flow->src_ip, flow->dst_ip, |
1672 | 219k | &flow->src_ip6, &flow->dst_ip6, |
1673 | 219k | flow->src_port, flow->dst_port, |
1674 | 219k | flow->detected_protocol, |
1675 | 219k | &flow->ndpi_flow_serializer) != 0) { |
1676 | 0 | LOG(NDPI_LOG_ERROR, "flow2json failed\n"); |
1677 | 0 | return; |
1678 | 0 | } |
1679 | | |
1680 | 219k | ndpi_serialize_string_uint32(&flow->ndpi_flow_serializer, "detection_completed", flow->detection_completed); |
1681 | 219k | ndpi_serialize_string_uint32(&flow->ndpi_flow_serializer, "check_extra_packets", flow->check_extra_packets); |
1682 | | |
1683 | 219k | if(flow->ndpi_flow->state == NDPI_STATE_MONITORING) { |
1684 | 307 | serialize_monitoring_metadata(flow); |
1685 | 307 | } |
1686 | | |
1687 | 219k | if(flow->server_hostname) |
1688 | 5.83k | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "server_hostname", flow->server_hostname); |
1689 | 219k | } |
1690 | | |
1691 | 219k | if(flow->detection_completed && (!flow->check_extra_packets)) { |
1692 | 47.9k | flow->flow_payload = flow->ndpi_flow->flow_payload, flow->flow_payload_len = flow->ndpi_flow->flow_payload_len; |
1693 | 47.9k | flow->ndpi_flow->flow_payload = NULL; /* We'll free the memory */ |
1694 | | |
1695 | 47.9k | if(workflow->flow_callback != NULL) |
1696 | 47.9k | workflow->flow_callback(workflow, flow, workflow->flow_callback_userdata); |
1697 | | |
1698 | 47.9k | if(fingerprint_fp) |
1699 | 0 | dump_flow_fingerprint(workflow, flow); |
1700 | | |
1701 | 47.9k | ndpi_free_flow_info_half(flow); |
1702 | 47.9k | } |
1703 | 219k | } |
1704 | | |
1705 | | /* ****************************************************** */ |
1706 | | |
1707 | | /** |
1708 | | * @brief Clear entropy stats if it meets prereq. |
1709 | | */ |
1710 | | static void |
1711 | 786k | ndpi_clear_entropy_stats(struct ndpi_flow_info *flow) { |
1712 | 786k | if(enable_flow_stats) { |
1713 | 786k | if(flow->entropy->src2dst_pkt_count + flow->entropy->dst2src_pkt_count == max_num_packets_per_flow) { |
1714 | 35.7k | memcpy(flow->last_entropy, flow->entropy, sizeof(struct ndpi_entropy)); |
1715 | 35.7k | memset(flow->entropy, 0x00, sizeof(struct ndpi_entropy)); |
1716 | 35.7k | } |
1717 | 786k | } |
1718 | 786k | } |
1719 | | |
1720 | 453k | void update_tcp_flags_count(struct ndpi_flow_info* flow, struct ndpi_tcphdr* tcp, u_int8_t src_to_dst_direction){ |
1721 | 453k | if(tcp->cwr){ |
1722 | 19.9k | flow->cwr_count++; |
1723 | 19.9k | src_to_dst_direction ? flow->src2dst_cwr_count++ : flow->dst2src_cwr_count++; |
1724 | 19.9k | } |
1725 | 453k | if(tcp->ece){ |
1726 | 39.7k | flow->ece_count++; |
1727 | 39.7k | src_to_dst_direction ? flow->src2dst_ece_count++ : flow->dst2src_ece_count++; |
1728 | 39.7k | } |
1729 | 453k | if(tcp->rst){ |
1730 | 53.1k | flow->rst_count++; |
1731 | 53.1k | src_to_dst_direction ? flow->src2dst_rst_count++ : flow->dst2src_rst_count++; |
1732 | 53.1k | } |
1733 | 453k | if(tcp->ack){ |
1734 | 339k | flow->ack_count++; |
1735 | 339k | src_to_dst_direction ? flow->src2dst_ack_count++ : flow->dst2src_ack_count++; |
1736 | 339k | } |
1737 | 453k | if(tcp->fin){ |
1738 | 51.4k | flow->fin_count++; |
1739 | 51.4k | src_to_dst_direction ? flow->src2dst_fin_count++ : flow->dst2src_fin_count++; |
1740 | 51.4k | } |
1741 | 453k | if(tcp->syn){ |
1742 | 128k | flow->syn_count++; |
1743 | 128k | src_to_dst_direction ? flow->src2dst_syn_count++ : flow->dst2src_syn_count++; |
1744 | 128k | } |
1745 | 453k | if(tcp->psh){ |
1746 | 189k | flow->psh_count++; |
1747 | 189k | src_to_dst_direction ? flow->src2dst_psh_count++ : flow->dst2src_psh_count++; |
1748 | 189k | } |
1749 | 453k | if(tcp->urg){ |
1750 | 49.7k | flow->urg_count++; |
1751 | 49.7k | src_to_dst_direction ? flow->src2dst_urg_count++ : flow->dst2src_urg_count++; |
1752 | 49.7k | } |
1753 | 453k | } |
1754 | | |
1755 | | /* ****************************************************** */ |
1756 | | |
1757 | | /** |
1758 | | Function to process the packet: |
1759 | | determine the flow of a packet and try to decode it |
1760 | | @return: 0 if success; else != 0 |
1761 | | |
1762 | | @Note: ipsize = header->len - ip_offset ; rawsize = header->len |
1763 | | */ |
1764 | | static struct ndpi_proto packet_processing(struct ndpi_workflow * workflow, |
1765 | | const u_int64_t time_ms, |
1766 | | u_int16_t vlan_id, |
1767 | | ndpi_packet_tunnel tunnel_type, |
1768 | | const struct ndpi_iphdr *iph, |
1769 | | struct ndpi_ipv6hdr *iph6, |
1770 | | u_int16_t ipsize, u_int16_t rawsize, |
1771 | | const struct pcap_pkthdr *header, |
1772 | | const u_char *packet, |
1773 | | pkt_timeval when, |
1774 | | ndpi_risk *flow_risk, |
1775 | 793k | struct ndpi_flow_info **flow_ext) { |
1776 | 793k | struct ndpi_flow_info *flow = NULL; |
1777 | 793k | struct ndpi_flow_struct *ndpi_flow = NULL; |
1778 | 793k | u_int8_t proto; |
1779 | 793k | struct ndpi_tcphdr *tcph = NULL; |
1780 | 793k | struct ndpi_udphdr *udph = NULL; |
1781 | 793k | u_int16_t sport, dport, payload_len = 0; |
1782 | 793k | u_int8_t *payload; |
1783 | 793k | u_int8_t src_to_dst_direction = 1; |
1784 | 793k | u_int8_t begin_or_end_tcp = 0; |
1785 | 793k | struct ndpi_proto nproto; |
1786 | | |
1787 | 793k | memset(&nproto, '\0', sizeof(nproto)); |
1788 | | |
1789 | 793k | if(workflow->prefs.ignore_vlanid) |
1790 | 0 | vlan_id = 0; |
1791 | | |
1792 | 793k | if(iph) |
1793 | 723k | flow = get_ndpi_flow_info(workflow, IPVERSION, vlan_id, |
1794 | 723k | tunnel_type, iph, NULL, |
1795 | 723k | ipsize, |
1796 | 723k | ntohs(iph->tot_len) ? (ntohs(iph->tot_len) - (iph->ihl * 4)) : ipsize - (iph->ihl * 4) /* TSO */, |
1797 | 723k | iph->ihl * 4, |
1798 | 723k | &tcph, &udph, &sport, &dport, |
1799 | 723k | &proto, |
1800 | 723k | &payload, &payload_len, &src_to_dst_direction, when); |
1801 | 70.5k | else |
1802 | 70.5k | flow = get_ndpi_flow_info6(workflow, vlan_id, |
1803 | 70.5k | tunnel_type, iph6, ipsize, |
1804 | 70.5k | &tcph, &udph, &sport, &dport, |
1805 | 70.5k | &proto, |
1806 | 70.5k | &payload, &payload_len, &src_to_dst_direction, when); |
1807 | | |
1808 | 793k | if(flow != NULL) { |
1809 | 786k | pkt_timeval tdiff; |
1810 | | |
1811 | 786k | workflow->stats.ip_packet_count++; |
1812 | 786k | workflow->stats.total_wire_bytes += rawsize + 24 /* CRC etc */, |
1813 | 786k | workflow->stats.total_ip_bytes += rawsize; |
1814 | 786k | ndpi_flow = flow->ndpi_flow; |
1815 | | |
1816 | 786k | if(tcph != NULL){ |
1817 | 453k | update_tcp_flags_count(flow, tcph, src_to_dst_direction); |
1818 | 453k | if(tcph->syn && !flow->src2dst_bytes){ |
1819 | 63.8k | flow->c_to_s_init_win = rawsize; |
1820 | 389k | }else if(tcph->syn && tcph->ack && flow->src2dst_bytes == flow->c_to_s_init_win){ |
1821 | 12.6k | flow->s_to_c_init_win = rawsize; |
1822 | 12.6k | } |
1823 | 453k | } |
1824 | | |
1825 | 786k | if((tcph != NULL) && (tcph->fin || tcph->rst || tcph->syn)) |
1826 | 170k | begin_or_end_tcp = 1; |
1827 | | |
1828 | 786k | if(flow->flow_last_pkt_time.tv_sec) { |
1829 | 521k | ndpi_timer_sub(&when, &flow->flow_last_pkt_time, &tdiff); |
1830 | | |
1831 | 521k | if(flow->iat_flow |
1832 | 521k | && (tdiff.tv_sec >= 0) /* Discard backward time */ |
1833 | 521k | ) { |
1834 | 505k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1835 | | |
1836 | 505k | if(ms > 0) |
1837 | 212k | ndpi_data_add_value(flow->iat_flow, ms); |
1838 | 505k | } |
1839 | 521k | } |
1840 | | |
1841 | 786k | memcpy(&flow->flow_last_pkt_time, &when, sizeof(when)); |
1842 | | |
1843 | 786k | if(src_to_dst_direction) { |
1844 | 614k | if(flow->src2dst_last_pkt_time.tv_sec) { |
1845 | 351k | ndpi_timer_sub(&when, &flow->src2dst_last_pkt_time, &tdiff); |
1846 | | |
1847 | 351k | if(flow->iat_c_to_s |
1848 | 351k | && (tdiff.tv_sec >= 0) /* Discard backward time */ |
1849 | 351k | ) { |
1850 | 338k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1851 | | |
1852 | 338k | ndpi_data_add_value(flow->iat_c_to_s, ms); |
1853 | 338k | } |
1854 | 351k | } |
1855 | | |
1856 | 614k | ndpi_data_add_value(flow->pktlen_c_to_s, rawsize); |
1857 | 614k | flow->src2dst_packets++, flow->src2dst_bytes += rawsize, flow->src2dst_goodput_bytes += payload_len; |
1858 | 614k | memcpy(&flow->src2dst_last_pkt_time, &when, sizeof(when)); |
1859 | | |
1860 | | #ifdef DIRECTION_BINS |
1861 | | if(payload_len && (flow->src2dst_packets < MAX_NUM_BIN_PKTS)) |
1862 | | ndpi_inc_bin(&flow->payload_len_bin_src2dst, plen2slot(payload_len)); |
1863 | | #endif |
1864 | 614k | } else { |
1865 | 171k | if(flow->dst2src_last_pkt_time.tv_sec && (!begin_or_end_tcp)) { |
1866 | 112k | ndpi_timer_sub(&when, &flow->dst2src_last_pkt_time, &tdiff); |
1867 | | |
1868 | 112k | if(flow->iat_s_to_c) { |
1869 | 112k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1870 | | |
1871 | 112k | ndpi_data_add_value(flow->iat_s_to_c, ms); |
1872 | 112k | } |
1873 | 112k | } |
1874 | 171k | ndpi_data_add_value(flow->pktlen_s_to_c, rawsize); |
1875 | 171k | flow->dst2src_packets++, flow->dst2src_bytes += rawsize, flow->dst2src_goodput_bytes += payload_len; |
1876 | 171k | flow->risk &= ~(1ULL << NDPI_UNIDIRECTIONAL_TRAFFIC); /* Clear bit */ |
1877 | 171k | memcpy(&flow->dst2src_last_pkt_time, &when, sizeof(when)); |
1878 | | |
1879 | | #ifdef DIRECTION_BINS |
1880 | | if(payload_len && (flow->dst2src_packets < MAX_NUM_BIN_PKTS)) |
1881 | | ndpi_inc_bin(&flow->payload_len_bin_dst2src, plen2slot(payload_len)); |
1882 | | #endif |
1883 | 171k | } |
1884 | | |
1885 | 786k | #ifndef DIRECTION_BINS |
1886 | 786k | if(payload_len && ((flow->src2dst_packets+flow->dst2src_packets) < MAX_NUM_BIN_PKTS)) { |
1887 | | #if 0 |
1888 | | /* Discard packets until the protocol is detected */ |
1889 | | if(flow->detected_protocol.proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) |
1890 | | #endif |
1891 | 610k | ndpi_inc_bin(&flow->payload_len_bin, plen2slot(payload_len), 1); |
1892 | 610k | } |
1893 | 786k | #endif |
1894 | | |
1895 | 786k | if(enable_payload_analyzer && (payload_len > 0)) |
1896 | 0 | ndpi_payload_analyzer(flow, |
1897 | 0 | payload, payload_len, |
1898 | 0 | workflow->stats.ip_packet_count); |
1899 | | |
1900 | 786k | if(enable_flow_stats) { |
1901 | | /* Update BD, distribution and mean. */ |
1902 | 786k | ndpi_flow_update_byte_count(flow, payload, payload_len, src_to_dst_direction); |
1903 | 786k | ndpi_flow_update_byte_dist_mean_var(flow, payload, payload_len, src_to_dst_direction); |
1904 | | /* Update SPLT scores for first 32 packets. */ |
1905 | 786k | if((flow->entropy->src2dst_pkt_count+flow->entropy->dst2src_pkt_count) <= max_num_packets_per_flow) { |
1906 | 786k | if(flow->bidirectional) |
1907 | 335k | flow->entropy->score = ndpi_classify(flow->entropy->src2dst_pkt_len, flow->entropy->src2dst_pkt_time, |
1908 | 335k | flow->entropy->dst2src_pkt_len, flow->entropy->dst2src_pkt_time, |
1909 | 335k | flow->entropy->src2dst_start, flow->entropy->dst2src_start, |
1910 | 335k | max_num_packets_per_flow, ntohs(flow->src_port), ntohs(flow->dst_port), |
1911 | 335k | flow->src2dst_packets, flow->dst2src_packets, |
1912 | 335k | flow->entropy->src2dst_opackets, flow->entropy->dst2src_opackets, |
1913 | 335k | flow->entropy->src2dst_l4_bytes, flow->entropy->dst2src_l4_bytes, 1, |
1914 | 335k | flow->entropy->src2dst_byte_count, flow->entropy->dst2src_byte_count); |
1915 | 451k | else |
1916 | 451k | flow->entropy->score = ndpi_classify(flow->entropy->src2dst_pkt_len, flow->entropy->src2dst_pkt_time, |
1917 | 451k | NULL, NULL, flow->entropy->src2dst_start, flow->entropy->src2dst_start, |
1918 | 451k | max_num_packets_per_flow, ntohs(flow->src_port), ntohs(flow->dst_port), |
1919 | 451k | flow->src2dst_packets, 0, |
1920 | 451k | flow->entropy->src2dst_opackets, 0, |
1921 | 451k | flow->entropy->src2dst_l4_bytes, 0, 1, |
1922 | 451k | flow->entropy->src2dst_byte_count, NULL); |
1923 | 786k | } |
1924 | 786k | } |
1925 | | |
1926 | 786k | if(flow->first_seen_ms == 0) |
1927 | 219k | flow->first_seen_ms = time_ms; |
1928 | | |
1929 | 786k | flow->last_seen_ms = time_ms; |
1930 | | |
1931 | | /* Copy packets entropy if num packets count == 10 */ |
1932 | 786k | ndpi_clear_entropy_stats(flow); |
1933 | | /* Reset IAT reeference times (see https://github.com/ntop/nDPI/pull/1316) */ |
1934 | 786k | if(((flow->src2dst_packets + flow->dst2src_packets) % max_num_packets_per_flow) == 0) { |
1935 | 35.7k | memset(&flow->src2dst_last_pkt_time, '\0', sizeof(flow->src2dst_last_pkt_time)); |
1936 | 35.7k | memset(&flow->dst2src_last_pkt_time, '\0', sizeof(flow->dst2src_last_pkt_time)); |
1937 | 35.7k | memset(&flow->flow_last_pkt_time, '\0', sizeof(flow->flow_last_pkt_time)); |
1938 | 35.7k | } |
1939 | | |
1940 | 786k | if((human_readeable_string_len != 0) && (!flow->has_human_readeable_strings)) { |
1941 | 544k | u_int8_t skip = 0; |
1942 | | |
1943 | 544k | if(proto == IPPROTO_TCP && |
1944 | 314k | (is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) || |
1945 | 250k | is_ndpi_proto(flow, NDPI_PROTOCOL_SSH))) { |
1946 | 66.6k | if((flow->src2dst_packets+flow->dst2src_packets) < 10 /* MIN_NUM_ENCRYPT_SKIP_PACKETS */) |
1947 | 17.4k | skip = 1; /* Skip initial negotiation packets */ |
1948 | 66.6k | } |
1949 | | |
1950 | 544k | if((!skip) && ((flow->src2dst_packets+flow->dst2src_packets) < 100)) { |
1951 | 502k | if(ndpi_has_human_readable_string((char*)packet, header->caplen, |
1952 | 502k | human_readeable_string_len, |
1953 | 502k | flow->human_readeable_string_buffer, |
1954 | 502k | sizeof(flow->human_readeable_string_buffer)) == 1) |
1955 | 106k | flow->has_human_readeable_strings = 1; |
1956 | 502k | } |
1957 | 544k | } else { |
1958 | 241k | if(proto == IPPROTO_TCP && |
1959 | 139k | (is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) || |
1960 | 133k | is_ndpi_proto(flow, NDPI_PROTOCOL_SSH))) |
1961 | 6.38k | flow->has_human_readeable_strings = 0; |
1962 | 241k | } |
1963 | 786k | } else { // flow is NULL |
1964 | 7.70k | workflow->stats.total_discarded_bytes += header->len; |
1965 | 7.70k | return(nproto); |
1966 | 7.70k | } |
1967 | | |
1968 | 786k | if(!flow->detection_completed) { |
1969 | 581k | struct ndpi_flow_input_info input_info; |
1970 | | |
1971 | 581k | u_int enough_packets = |
1972 | 581k | ((proto == IPPROTO_UDP && (max_num_udp_dissected_pkts > 0 && flow->src2dst_packets + flow->dst2src_packets >= max_num_udp_dissected_pkts)) || |
1973 | 581k | (proto == IPPROTO_TCP && (max_num_tcp_dissected_pkts > 0 && flow->src2dst_packets + flow->dst2src_packets >= max_num_tcp_dissected_pkts))) ? 1 : 0; |
1974 | | |
1975 | | #if 0 |
1976 | | printf("%s()\n", __FUNCTION__); |
1977 | | #endif |
1978 | | |
1979 | 581k | if(proto == IPPROTO_TCP) |
1980 | 353k | workflow->stats.dpi_packet_count[0]++; |
1981 | 227k | else if(proto == IPPROTO_UDP) |
1982 | 217k | workflow->stats.dpi_packet_count[1]++; |
1983 | 10.6k | else |
1984 | 10.6k | workflow->stats.dpi_packet_count[2]++; |
1985 | 581k | flow->dpi_packets++; |
1986 | | |
1987 | 581k | memset(&input_info, '\0', sizeof(input_info)); /* To be sure to set to "unknown" any fields */ |
1988 | | /* Set here any information (easily) available; in this trivial example we don't have any */ |
1989 | 581k | input_info.in_pkt_dir = NDPI_IN_PKT_DIR_UNKNOWN; |
1990 | 581k | input_info.seen_flow_beginning = NDPI_FLOW_BEGINNING_UNKNOWN; |
1991 | 581k | malloc_size_stats = 1; |
1992 | 581k | flow->detected_protocol = ndpi_detection_process_packet(workflow->ndpi_struct, ndpi_flow, |
1993 | 581k | iph ? (uint8_t *)iph : (uint8_t *)iph6, |
1994 | 581k | ipsize, time_ms, &input_info); |
1995 | 581k | if(monitoring_enabled) |
1996 | 581k | process_ndpi_monitoring_info(flow); |
1997 | 581k | if(flow->detected_protocol.state == NDPI_STATE_CLASSIFIED || |
1998 | 533k | enough_packets) { |
1999 | | |
2000 | 47.9k | flow->detection_completed = 1; |
2001 | | |
2002 | 47.9k | if(flow->detected_protocol.state != NDPI_STATE_CLASSIFIED) { |
2003 | 0 | flow->detected_protocol = ndpi_detection_giveup(workflow->ndpi_struct, flow->ndpi_flow); |
2004 | 0 | } |
2005 | | |
2006 | 47.9k | if(flow->ndpi_flow->protocol_was_guessed) workflow->stats.guessed_flow_protocols++; |
2007 | 47.9k | process_ndpi_collected_info(workflow, flow); |
2008 | 47.9k | } |
2009 | | |
2010 | | /* Let's try to save client-server direction */ |
2011 | 581k | flow->current_pkt_from_client_to_server = input_info.in_pkt_dir; |
2012 | | |
2013 | 581k | malloc_size_stats = 0; |
2014 | 581k | } else { |
2015 | 205k | flow->current_pkt_from_client_to_server = NDPI_IN_PKT_DIR_UNKNOWN; /* Unknown */ |
2016 | 205k | } |
2017 | | |
2018 | | #if 0 |
2019 | | if(flow->risk != 0) { |
2020 | | FILE *r = fopen("/tmp/e", "a"); |
2021 | | |
2022 | | if(r) { |
2023 | | fprintf(r, "->>> %u [%08X]\n", flow->risk, flow->risk); |
2024 | | fclose(r); |
2025 | | } |
2026 | | } |
2027 | | #endif |
2028 | | |
2029 | 786k | *flow_risk = flow->risk; |
2030 | 786k | *flow_ext = flow; |
2031 | | |
2032 | 786k | return(flow->detected_protocol); |
2033 | 793k | } |
2034 | | |
2035 | | /* ****************************************************** */ |
2036 | | |
2037 | 22.6k | int ndpi_is_datalink_supported(int datalink_type) { |
2038 | | /* Keep in sync with the similar switch in ndpi_workflow_process_packet */ |
2039 | 22.6k | switch(datalink_type) { |
2040 | 7.53k | case DLT_NULL: |
2041 | 7.55k | case DLT_PPP_SERIAL: |
2042 | 7.58k | case DLT_C_HDLC: |
2043 | 7.71k | case DLT_PPP: |
2044 | 7.71k | #ifdef DLT_IPV4 |
2045 | 9.16k | case DLT_IPV4: |
2046 | 9.16k | #endif |
2047 | 9.16k | #ifdef DLT_IPV6 |
2048 | 9.87k | case DLT_IPV6: |
2049 | 9.87k | #endif |
2050 | 21.1k | case DLT_EN10MB: |
2051 | 21.8k | case DLT_LINUX_SLL: |
2052 | 21.9k | case DLT_IEEE802_11_RADIO: |
2053 | 22.5k | case DLT_RAW: |
2054 | 22.5k | case DLT_PPI: |
2055 | 22.6k | case LINKTYPE_LINUX_SLL2: |
2056 | 22.6k | return 1; |
2057 | 36 | default: |
2058 | 36 | return 0; |
2059 | 22.6k | } |
2060 | 22.6k | } |
2061 | | |
2062 | 236k | static bool ndpi_is_valid_vxlan(const struct pcap_pkthdr *header, const u_char *packet, u_int16_t ip_offset, u_int16_t ip_len){ |
2063 | 236k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr) + sizeof(struct ndpi_vxlanhdr)) { |
2064 | 6.33k | return false; |
2065 | 6.33k | } |
2066 | 230k | u_int32_t vxlan_dst_port = ntohs(4789); |
2067 | 230k | struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[ip_offset+ip_len]; |
2068 | 230k | u_int offset = ip_offset + ip_len + sizeof(struct ndpi_udphdr); |
2069 | | /** |
2070 | | * rfc-7348 |
2071 | | * VXLAN Header: This is an 8-byte field that has: |
2072 | | |
2073 | | - Flags (8 bits): where the I flag MUST be set to 1 for a valid |
2074 | | VXLAN Network ID (VNI). The other 7 bits (designated "R") are |
2075 | | reserved fields and MUST be set to zero on transmission and |
2076 | | ignored on receipt. |
2077 | | |
2078 | | - VXLAN Segment ID/VXLAN Network Identifier (VNI): this is a |
2079 | | 24-bit value used to designate the individual VXLAN overlay |
2080 | | network on which the communicating VMs are situated. VMs in |
2081 | | different VXLAN overlay networks cannot communicate with each |
2082 | | other. |
2083 | | |
2084 | | - Reserved fields (24 bits and 8 bits): MUST be set to zero on |
2085 | | transmission and ignored on receipt. |
2086 | | VXLAN Header: |
2087 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2088 | | |R|R|R|R|I|R|R|R| Reserved | |
2089 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2090 | | | VXLAN Network Identifier (VNI) | Reserved | |
2091 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2092 | | */ |
2093 | 230k | if((udp->dest == vxlan_dst_port || udp->source == vxlan_dst_port) && |
2094 | 7.67k | (packet[offset] == 0x8) && |
2095 | 5.81k | (packet[offset + 1] == 0x0) && |
2096 | 5.59k | (packet[offset + 2] == 0x0) && |
2097 | 5.51k | (packet[offset + 3] == 0x0) && |
2098 | 5.38k | (packet[offset + 7] == 0x0)) { |
2099 | 5.24k | return true; |
2100 | 5.24k | } |
2101 | 224k | return false; |
2102 | 230k | } |
2103 | | |
2104 | 5.24k | static inline u_int ndpi_skip_vxlan(u_int16_t ip_offset, u_int16_t ip_len){ |
2105 | 5.24k | return ip_offset + ip_len + sizeof(struct ndpi_udphdr) + sizeof(struct ndpi_vxlanhdr); |
2106 | 5.24k | } |
2107 | | |
2108 | | static uint32_t ndpi_is_valid_gre_tunnel(const struct pcap_pkthdr *header, |
2109 | | const u_char *packet, const u_int16_t ip_offset, |
2110 | 3.80k | const u_int16_t ip_len) { |
2111 | 3.80k | uint32_t offset = ip_offset + ip_len; |
2112 | 3.80k | struct ndpi_gre_basehdr *grehdr = (struct ndpi_gre_basehdr*)&packet[offset]; |
2113 | 3.80k | offset += sizeof(struct ndpi_gre_basehdr); |
2114 | | /* |
2115 | | The GRE flags are encoded in the first two octets. Bit 0 is the |
2116 | | most significant bit, bit 15 is the least significant bit. Bits |
2117 | | 13 through 15 are reserved for the Version field. Bits 9 through |
2118 | | 12 are reserved for future use and MUST be transmitted as zero. |
2119 | | */ |
2120 | 3.80k | if(NDPI_GRE_IS_FLAGS(grehdr->flags)) |
2121 | 274 | return 0; |
2122 | 3.53k | if(NDPI_GRE_IS_REC(grehdr->flags)) |
2123 | 248 | return 0; |
2124 | | /*GRE rfc 2890 that update 1701*/ |
2125 | 3.28k | if(NDPI_GRE_IS_VERSION_0(grehdr->flags)) { |
2126 | 1.24k | if(NDPI_GRE_IS_CSUM(grehdr->flags)) { |
2127 | 279 | if(header->caplen < offset + 4) |
2128 | 18 | return 0; |
2129 | | /*checksum field and offset field*/ |
2130 | 261 | offset += 4; |
2131 | 261 | } |
2132 | 1.23k | if(NDPI_GRE_IS_KEY(grehdr->flags)) { |
2133 | 279 | if(header->caplen < offset + 4) |
2134 | 18 | return 0; |
2135 | 261 | offset += 4; |
2136 | 261 | } |
2137 | 1.21k | if(NDPI_GRE_IS_SEQ(grehdr->flags)) { |
2138 | 305 | if(header->caplen < offset + 4) |
2139 | 18 | return 0; |
2140 | 287 | offset += 4; |
2141 | 287 | } |
2142 | 2.03k | } else if(NDPI_GRE_IS_VERSION_1(grehdr->flags)) { /*rfc-2637 section 4.1 enhanced gre*/ |
2143 | 1.98k | if(NDPI_GRE_IS_CSUM(grehdr->flags)) |
2144 | 13 | return 0; |
2145 | 1.96k | if(NDPI_GRE_IS_ROUTING(grehdr->flags)) |
2146 | 50 | return 0; |
2147 | 1.91k | if(!NDPI_GRE_IS_KEY(grehdr->flags)) |
2148 | 362 | return 0; |
2149 | 1.55k | if(NDPI_GRE_IS_STRICT(grehdr->flags)) |
2150 | 34 | return 0; |
2151 | 1.52k | if(grehdr->protocol != NDPI_GRE_PROTO_PPP) |
2152 | 92 | return 0; |
2153 | | /*key field*/ |
2154 | 1.43k | if(header->caplen < offset + 4) |
2155 | 34 | return 0; |
2156 | 1.39k | offset += 4; |
2157 | 1.39k | if(NDPI_GRE_IS_SEQ(grehdr->flags)) { |
2158 | 39 | if(header->caplen < offset + 4) |
2159 | 18 | return 0; |
2160 | 21 | offset += 4; |
2161 | 21 | } |
2162 | 1.37k | if(NDPI_GRE_IS_ACK(grehdr->flags)) { |
2163 | 26 | if(header->caplen < offset + 4) |
2164 | 12 | return 0; |
2165 | 14 | offset += 4; |
2166 | 14 | } |
2167 | 1.37k | } else { /*support only ver 0, 1*/ |
2168 | 54 | return 0; |
2169 | 54 | } |
2170 | 2.56k | return offset; |
2171 | 3.28k | } |
2172 | | |
2173 | | /* ****************************************************** */ |
2174 | | |
2175 | | struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, |
2176 | | const struct pcap_pkthdr *header, |
2177 | | const u_char *packet, |
2178 | | ndpi_risk *flow_risk, |
2179 | 954k | struct ndpi_flow_info **flow) { |
2180 | | /* |
2181 | | * Declare pointers to packet headers |
2182 | | */ |
2183 | | /* --- Ethernet header --- */ |
2184 | 954k | const struct ndpi_ethhdr *ethernet; |
2185 | | /* --- LLC header --- */ |
2186 | 954k | const struct ndpi_llc_header_snap *llc; |
2187 | | |
2188 | | /* --- Cisco HDLC header --- */ |
2189 | 954k | const struct ndpi_chdlc *chdlc; |
2190 | | |
2191 | | /* --- Radio Tap header --- */ |
2192 | 954k | const struct ndpi_radiotap_header *radiotap; |
2193 | | /* --- Wifi header --- */ |
2194 | 954k | const struct ndpi_wifi_header *wifi; |
2195 | | |
2196 | | /* --- MPLS header --- */ |
2197 | 954k | union mpls { |
2198 | 954k | uint32_t u32; |
2199 | 954k | struct ndpi_mpls_header mpls; |
2200 | 954k | } mpls; |
2201 | | |
2202 | | /** --- IP header --- **/ |
2203 | 954k | struct ndpi_iphdr *iph; |
2204 | | /** --- IPv6 header --- **/ |
2205 | 954k | struct ndpi_ipv6hdr *iph6; |
2206 | | |
2207 | 954k | struct ndpi_proto nproto; |
2208 | 954k | ndpi_packet_tunnel tunnel_type = ndpi_no_tunnel; |
2209 | | |
2210 | | /* lengths and offsets */ |
2211 | 954k | u_int32_t eth_offset = 0, dlt; |
2212 | 954k | u_int16_t radio_len, header_length; |
2213 | 954k | u_int16_t fc; |
2214 | 954k | u_int16_t type = 0; |
2215 | 954k | int wifi_len = 0; |
2216 | 954k | int pyld_eth_len = 0; |
2217 | 954k | int check; |
2218 | 954k | u_int64_t time_ms; |
2219 | 954k | u_int16_t ip_offset = 0, ip_len; |
2220 | 954k | u_int16_t frag_off = 0, vlan_id = 0; |
2221 | 954k | u_int8_t proto = 0, recheck_type; |
2222 | 954k | u_int8_t ip_ver, ppp_type; |
2223 | | /*u_int32_t label;*/ |
2224 | | |
2225 | | /* counters */ |
2226 | 954k | u_int8_t vlan_packet = 0; |
2227 | | |
2228 | 954k | *flow_risk = 0 /* NDPI_NO_RISK */; |
2229 | 954k | *flow = NULL; |
2230 | | |
2231 | 954k | memset(&nproto, '\0', sizeof(nproto)); |
2232 | | |
2233 | 954k | if((addr_dump_path != NULL) && (workflow->stats.raw_packet_count == 0)) { |
2234 | | /* At the first packet flush expired cached addresses */ |
2235 | 0 | ndpi_cache_address_flush_expired(workflow->ndpi_struct, header->ts.tv_sec); |
2236 | 0 | } |
2237 | | |
2238 | | /* Increment raw packet counter */ |
2239 | 954k | workflow->stats.raw_packet_count++; |
2240 | | |
2241 | | /* setting time */ |
2242 | 954k | time_ms = ((uint64_t) header->ts.tv_sec) * TICK_RESOLUTION + header->ts.tv_usec / (1000000 / TICK_RESOLUTION); |
2243 | | |
2244 | | /* safety check */ |
2245 | 954k | if(workflow->last_time > time_ms) { |
2246 | | /* printf("\nWARNING: timestamp bug in the pcap file (ts delta: %llu, repairing)\n", ndpi_thread_info[thread_id].last_time - time); */ |
2247 | 954k | time_ms = workflow->last_time; |
2248 | 954k | } |
2249 | | /* update last time value */ |
2250 | 954k | workflow->last_time = time_ms; |
2251 | | |
2252 | | /*** check Data Link type ***/ |
2253 | 954k | int datalink_type; |
2254 | | |
2255 | | #ifdef USE_DPDK |
2256 | | datalink_type = DLT_EN10MB; |
2257 | | #else |
2258 | 954k | datalink_type = (int)pcap_datalink(workflow->pcap_handle); |
2259 | 954k | #endif |
2260 | | |
2261 | 960k | datalink_check: |
2262 | | // 20 for min iph and 8 for min UDP |
2263 | 960k | if(header->caplen < eth_offset + 28) |
2264 | 90.0k | return(nproto); /* Too short */ |
2265 | | |
2266 | | /* Keep in sync with ndpi_is_datalink_supported() */ |
2267 | 870k | switch(datalink_type) { |
2268 | 156k | case DLT_NULL: |
2269 | 156k | if(ntohl(*((u_int32_t*)&packet[eth_offset])) == 2) |
2270 | 30.9k | type = ETH_P_IP; |
2271 | 125k | else |
2272 | 125k | type = ETH_P_IPV6; |
2273 | | |
2274 | 156k | ip_offset = 4 + eth_offset; |
2275 | 156k | break; |
2276 | | |
2277 | | /* Cisco PPP in HDLC-like framing - 50 */ |
2278 | 199 | case DLT_PPP_SERIAL: |
2279 | 199 | chdlc = (struct ndpi_chdlc *) &packet[eth_offset]; |
2280 | 199 | ip_offset = eth_offset + sizeof(struct ndpi_chdlc); /* CHDLC_OFF = 4 */ |
2281 | 199 | type = ntohs(chdlc->proto_code); |
2282 | 199 | break; |
2283 | | |
2284 | | /* Cisco PPP - 9 or 104 */ |
2285 | 232 | case DLT_C_HDLC: |
2286 | 1.17k | case DLT_PPP: |
2287 | 1.17k | if(packet[0] == 0x0f || packet[0] == 0x8f) { |
2288 | 439 | chdlc = (struct ndpi_chdlc *) &packet[eth_offset]; |
2289 | 439 | ip_offset = eth_offset + sizeof(struct ndpi_chdlc); /* CHDLC_OFF = 4 */ |
2290 | 439 | type = ntohs(chdlc->proto_code); |
2291 | 739 | } else { |
2292 | 739 | ip_offset = eth_offset + 2; |
2293 | 739 | ppp_type = ntohs(*((u_int16_t*)&packet[eth_offset])); |
2294 | 739 | if(ppp_type == 0x0021) |
2295 | 275 | type = ETH_P_IP; |
2296 | 464 | else if(ppp_type == 0x0057) |
2297 | 194 | type = ETH_P_IPV6; |
2298 | 270 | else |
2299 | 270 | return(nproto); |
2300 | 739 | } |
2301 | 908 | break; |
2302 | | |
2303 | 908 | #ifdef DLT_IPV4 |
2304 | 49.1k | case DLT_IPV4: |
2305 | 49.1k | type = ETH_P_IP; |
2306 | 49.1k | ip_offset = eth_offset; |
2307 | 49.1k | break; |
2308 | 0 | #endif |
2309 | | |
2310 | 0 | #ifdef DLT_IPV6 |
2311 | 10.6k | case DLT_IPV6: |
2312 | 10.6k | type = ETH_P_IPV6; |
2313 | 10.6k | ip_offset = eth_offset; |
2314 | 10.6k | break; |
2315 | 0 | #endif |
2316 | | |
2317 | | /* IEEE 802.3 Ethernet - 1 */ |
2318 | 629k | case DLT_EN10MB: |
2319 | 629k | ethernet = (struct ndpi_ethhdr *) &packet[eth_offset]; |
2320 | 629k | ip_offset = sizeof(struct ndpi_ethhdr) + eth_offset; |
2321 | 629k | check = ntohs(ethernet->h_proto); |
2322 | | |
2323 | 629k | if(check <= 1500) |
2324 | 17.4k | pyld_eth_len = check; |
2325 | 611k | else if(check >= 1536) |
2326 | 611k | type = check; |
2327 | | |
2328 | 629k | if(pyld_eth_len != 0) { |
2329 | 16.8k | llc = (struct ndpi_llc_header_snap *)(&packet[ip_offset]); |
2330 | | /* check for LLC layer with SNAP extension */ |
2331 | 16.8k | if(llc->dsap == SNAP || llc->ssap == SNAP) { |
2332 | 244 | type = llc->snap.proto_ID; |
2333 | 244 | ip_offset += + 8; |
2334 | 244 | } |
2335 | | /* No SNAP extension - Spanning Tree pkt must be discarted */ |
2336 | 16.6k | else if(llc->dsap == BSTP || llc->ssap == BSTP) { |
2337 | 686 | goto v4_warning; |
2338 | 686 | } |
2339 | 16.8k | } |
2340 | 628k | break; |
2341 | | |
2342 | | /* Linux Cooked Capture - 113 */ |
2343 | 628k | case DLT_LINUX_SLL: |
2344 | 10.8k | type = (packet[eth_offset+14] << 8) + packet[eth_offset+15]; |
2345 | 10.8k | ip_offset = 16 + eth_offset; |
2346 | 10.8k | break; |
2347 | | |
2348 | | /* Linux Cooked Capture v2 - 276 */ |
2349 | 194 | case LINKTYPE_LINUX_SLL2: |
2350 | 194 | type = (packet[eth_offset+10] << 8) + packet[eth_offset+11]; |
2351 | 194 | ip_offset = 20 + eth_offset; |
2352 | 194 | break; |
2353 | | |
2354 | | /* Radiotap link-layer - 127 */ |
2355 | 2.51k | case DLT_IEEE802_11_RADIO: |
2356 | 2.51k | radiotap = (struct ndpi_radiotap_header *) &packet[eth_offset]; |
2357 | 2.51k | radio_len = radiotap->len; |
2358 | | |
2359 | | /* Check Bad FCS presence */ |
2360 | 2.51k | if((radiotap->flags & BAD_FCS) == BAD_FCS) { |
2361 | 208 | workflow->stats.total_discarded_bytes += header->len; |
2362 | 208 | return(nproto); |
2363 | 208 | } |
2364 | | |
2365 | 2.30k | if(header->caplen < (eth_offset + radio_len + sizeof(struct ndpi_wifi_header))) |
2366 | 446 | return(nproto); |
2367 | | |
2368 | | /* Calculate 802.11 header length (variable) */ |
2369 | 1.85k | wifi = (struct ndpi_wifi_header*)( packet + eth_offset + radio_len); |
2370 | 1.85k | fc = wifi->fc; |
2371 | | |
2372 | | /* check wifi data presence */ |
2373 | 1.85k | if(FCF_TYPE(fc) == WIFI_DATA) { |
2374 | 1.61k | if((FCF_TO_DS(fc) && FCF_FROM_DS(fc) == 0x0) || |
2375 | 997 | (FCF_TO_DS(fc) == 0x0 && FCF_FROM_DS(fc))) |
2376 | 1.02k | wifi_len = 26; /* + 4 byte fcs */ |
2377 | 1.61k | } else /* no data frames */ |
2378 | 246 | return(nproto); |
2379 | | |
2380 | | /* Check ether_type from LLC */ |
2381 | 1.61k | if(header->caplen < (eth_offset + wifi_len + radio_len + sizeof(struct ndpi_llc_header_snap))) |
2382 | 1.01k | return(nproto); |
2383 | 600 | llc = (struct ndpi_llc_header_snap*)(packet + eth_offset + wifi_len + radio_len); |
2384 | 600 | if(llc->dsap == SNAP) |
2385 | 19 | type = ntohs(llc->snap.proto_ID); |
2386 | | |
2387 | | /* Set IP header offset */ |
2388 | 600 | ip_offset = wifi_len + radio_len + sizeof(struct ndpi_llc_header_snap) + eth_offset; |
2389 | 600 | break; |
2390 | | |
2391 | 9.72k | case DLT_RAW: |
2392 | 9.72k | ip_offset = eth_offset; |
2393 | | /* Heuristic: no explicit field with next protocol */ |
2394 | 9.72k | ip_ver = (packet[ip_offset] & 0xF0) >> 4; |
2395 | 9.72k | if(ip_ver == 4) |
2396 | 7.09k | type = ETH_P_IP; |
2397 | 2.62k | else if(ip_ver == 6) |
2398 | 2.20k | type = ETH_P_IPV6; |
2399 | 424 | else |
2400 | 424 | return(nproto); |
2401 | | |
2402 | 9.29k | break; |
2403 | | |
2404 | 9.29k | case DLT_PPI: |
2405 | 277 | header_length = le16toh(*(u_int16_t *)&packet[eth_offset + 2]); |
2406 | 277 | dlt = le32toh(*(u_int32_t *)&packet[eth_offset + 4]); |
2407 | 277 | if(dlt != DLT_EN10MB) /* Handle only standard ethernet, for the time being */ |
2408 | 206 | return(nproto); |
2409 | 71 | datalink_type = DLT_EN10MB; |
2410 | 71 | eth_offset += header_length; |
2411 | 71 | goto datalink_check; |
2412 | | |
2413 | 0 | default: |
2414 | | /* |
2415 | | * We shoudn't be here, because we already checked that this datalink is supported. |
2416 | | * Should ndpi_is_datalink_supported() be updated? |
2417 | | */ |
2418 | 0 | printf("Unknown datalink %d\n", datalink_type); |
2419 | 0 | return(nproto); |
2420 | 870k | } |
2421 | | |
2422 | 874k | ether_type_check: |
2423 | 874k | recheck_type = 0; |
2424 | | |
2425 | | /* check ether type */ |
2426 | 874k | switch(type) { |
2427 | 6.70k | case ETH_P_VLAN: |
2428 | 6.70k | if(ip_offset+4 >= (int)header->caplen) |
2429 | 20 | return(nproto); |
2430 | 6.68k | vlan_id = ((packet[ip_offset] << 8) + packet[ip_offset+1]) & 0xFFF; |
2431 | 6.68k | type = (packet[ip_offset+2] << 8) + packet[ip_offset+3]; |
2432 | 6.68k | ip_offset += 4; |
2433 | 6.68k | vlan_packet = 1; |
2434 | | |
2435 | | // double tagging for 802.1Q |
2436 | 8.57k | while((type == 0x8100) && (((bpf_u_int32)ip_offset+4) < header->caplen)) { |
2437 | 1.88k | vlan_id = ((packet[ip_offset] << 8) + packet[ip_offset+1]) & 0xFFF; |
2438 | 1.88k | type = (packet[ip_offset+2] << 8) + packet[ip_offset+3]; |
2439 | 1.88k | ip_offset += 4; |
2440 | 1.88k | } |
2441 | 6.68k | recheck_type = 1; |
2442 | 6.68k | break; |
2443 | | |
2444 | 96 | case ETH_P_MPLS_UNI: |
2445 | 279 | case ETH_P_MPLS_MULTI: |
2446 | 279 | if(ip_offset+4 >= (int)header->caplen) |
2447 | 35 | return(nproto); |
2448 | 244 | mpls.u32 = *((uint32_t *) &packet[ip_offset]); |
2449 | 244 | mpls.u32 = ntohl(mpls.u32); |
2450 | 244 | workflow->stats.mpls_count++; |
2451 | 244 | type = ETH_P_IP, ip_offset += 4; |
2452 | | |
2453 | 1.73k | while(!mpls.mpls.s && (((bpf_u_int32)ip_offset) + 4 < header->caplen)) { |
2454 | 1.48k | mpls.u32 = *((uint32_t *) &packet[ip_offset]); |
2455 | 1.48k | mpls.u32 = ntohl(mpls.u32); |
2456 | 1.48k | ip_offset += 4; |
2457 | 1.48k | } |
2458 | 244 | recheck_type = 1; |
2459 | 244 | break; |
2460 | | |
2461 | 955 | case ETH_P_PPPoE: |
2462 | 955 | workflow->stats.pppoe_count++; |
2463 | 955 | type = ETH_P_IP; |
2464 | 955 | ip_offset += 8; |
2465 | 955 | recheck_type = 1; |
2466 | 955 | break; |
2467 | | |
2468 | 667k | case ETH_P_IP: |
2469 | 835k | case ETH_P_IPV6: |
2470 | | /* Good let's keep decoding */ |
2471 | 835k | break; |
2472 | | |
2473 | 31.6k | default: |
2474 | 31.6k | return(nproto); |
2475 | 874k | } |
2476 | | |
2477 | 843k | if(recheck_type) |
2478 | 7.88k | goto ether_type_check; |
2479 | | |
2480 | 835k | workflow->stats.vlan_count += vlan_packet; |
2481 | | |
2482 | 838k | iph_check: |
2483 | | /* Check and set IP header size and total packet length */ |
2484 | 838k | if(header->caplen < ip_offset + sizeof(struct ndpi_iphdr)) |
2485 | 2.19k | return(nproto); /* Too short for next IP header*/ |
2486 | | |
2487 | 836k | iph = (struct ndpi_iphdr *) &packet[ip_offset]; |
2488 | | |
2489 | | /* just work on Ethernet packets that contain IP */ |
2490 | 836k | if(type == ETH_P_IP && header->caplen >= ip_offset) { |
2491 | 669k | frag_off = ntohs(iph->frag_off); |
2492 | | |
2493 | 669k | proto = iph->protocol; |
2494 | 669k | if(header->caplen < header->len) { |
2495 | 92.1k | static u_int8_t cap_warning_used = 0; |
2496 | | |
2497 | 92.1k | if(cap_warning_used == 0) { |
2498 | 1 | if(!workflow->prefs.quiet_mode) |
2499 | 1 | LOG(NDPI_LOG_DEBUG, |
2500 | 1 | "\n\nWARNING: packet capture size is smaller than packet size, DETECTION MIGHT NOT WORK CORRECTLY\n\n"); |
2501 | 1 | cap_warning_used = 1; |
2502 | 1 | } |
2503 | 92.1k | } |
2504 | 669k | } |
2505 | | |
2506 | 836k | if(iph->version == IPVERSION) { |
2507 | 750k | ip_len = ((u_int16_t)iph->ihl * 4); |
2508 | 750k | iph6 = NULL; |
2509 | | |
2510 | 750k | if(iph->protocol == IPPROTO_IPV6 |
2511 | 749k | || iph->protocol == NDPI_IPIP_PROTOCOL_TYPE |
2512 | 750k | ) { |
2513 | 945 | ip_offset += ip_len; |
2514 | 945 | if(ip_len > 0) |
2515 | 907 | goto iph_check; |
2516 | 945 | } |
2517 | | |
2518 | 749k | if((frag_off & 0x1FFF) != 0) { |
2519 | 14.4k | static u_int8_t ipv4_frags_warning_used = 0; |
2520 | 14.4k | workflow->stats.fragmented_count++; |
2521 | | |
2522 | 14.4k | if(ipv4_frags_warning_used == 0) { |
2523 | 1 | if(!workflow->prefs.quiet_mode) |
2524 | 1 | LOG(NDPI_LOG_DEBUG, "\n\nWARNING: IPv4 fragments are not handled by this demo (nDPI supports them)\n"); |
2525 | 1 | ipv4_frags_warning_used = 1; |
2526 | 1 | } |
2527 | | |
2528 | 14.4k | workflow->stats.total_discarded_bytes += header->len; |
2529 | 14.4k | return(nproto); |
2530 | 14.4k | } |
2531 | 749k | } else if(iph->version == 6) { |
2532 | 75.1k | if(header->caplen < ip_offset + sizeof(struct ndpi_ipv6hdr)) |
2533 | 529 | return(nproto); /* Too short for IPv6 header*/ |
2534 | | |
2535 | 74.6k | iph6 = (struct ndpi_ipv6hdr *)&packet[ip_offset]; |
2536 | 74.6k | proto = iph6->ip6_hdr.ip6_un1_nxt; |
2537 | 74.6k | ip_len = ntohs(iph6->ip6_hdr.ip6_un1_plen); |
2538 | | |
2539 | 74.6k | if(header->caplen < (ip_offset + sizeof(struct ndpi_ipv6hdr) + ntohs(iph6->ip6_hdr.ip6_un1_plen))) |
2540 | 1.43k | return(nproto); /* Too short for IPv6 payload*/ |
2541 | | |
2542 | 73.2k | const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr)); |
2543 | 73.2k | u_int16_t ipsize = header->caplen - ip_offset; |
2544 | | |
2545 | 73.2k | if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &proto) != 0) { |
2546 | 1.59k | return(nproto); |
2547 | 1.59k | } |
2548 | | |
2549 | 71.6k | if(proto == IPPROTO_IPV6 |
2550 | 71.4k | || proto == NDPI_IPIP_PROTOCOL_TYPE |
2551 | 71.6k | ) { |
2552 | 771 | if(l4ptr > packet) { /* Better safe than sorry */ |
2553 | 771 | ip_offset = (l4ptr - packet); |
2554 | 771 | goto iph_check; |
2555 | 771 | } |
2556 | 771 | } |
2557 | | |
2558 | 70.8k | iph = NULL; |
2559 | 70.8k | } else { |
2560 | 11.0k | static u_int8_t ipv4_warning_used = 0; |
2561 | | |
2562 | 13.5k | v4_warning: |
2563 | 13.5k | if(ipv4_warning_used == 0) { |
2564 | 1 | if(!workflow->prefs.quiet_mode) |
2565 | 1 | LOG(NDPI_LOG_DEBUG, |
2566 | 1 | "\n\nWARNING: only IPv4/IPv6 packets are supported in this demo (nDPI supports both IPv4 and IPv6), all other packets will be discarded\n\n"); |
2567 | 1 | ipv4_warning_used = 1; |
2568 | 1 | } |
2569 | | |
2570 | 13.5k | workflow->stats.total_discarded_bytes += header->len; |
2571 | 13.5k | return(nproto); |
2572 | 11.0k | } |
2573 | | |
2574 | 805k | if(workflow->prefs.decode_tunnels && (proto == IPPROTO_UDP)) { |
2575 | 257k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr)) |
2576 | 216 | return(nproto); /* Too short for UDP header*/ |
2577 | 257k | else { |
2578 | 257k | struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[ip_offset+ip_len]; |
2579 | 257k | u_int16_t sport = ntohs(udp->source), dport = ntohs(udp->dest); |
2580 | | |
2581 | 257k | if(((sport == GTP_U_V1_PORT) || (dport == GTP_U_V1_PORT)) && |
2582 | 19.0k | (ip_offset + ip_len + sizeof(struct ndpi_udphdr) + 8 /* Minimum GTPv1 header len */ < header->caplen)) { |
2583 | | /* Check if it's GTPv1 */ |
2584 | 18.8k | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2585 | 18.8k | u_int8_t flags = packet[offset]; |
2586 | 18.8k | u_int8_t message_type = packet[offset+1]; |
2587 | 18.8k | u_int8_t exts_parsing_error = 0; |
2588 | | |
2589 | 18.8k | if((((flags & 0xE0) >> 5) == 1 /* GTPv1 */) && |
2590 | 10.6k | (message_type == 0xFF /* T-PDU */)) { |
2591 | | |
2592 | 10.3k | offset += 8; /* GTPv1 header len */ |
2593 | 10.3k | if(flags & 0x07) |
2594 | 8.48k | offset += 4; /* sequence_number + pdu_number + next_ext_header fields */ |
2595 | | /* Extensions parsing */ |
2596 | 10.3k | if(flags & 0x04) { |
2597 | 1.20k | unsigned int ext_length = 0; |
2598 | | |
2599 | 2.04k | while(offset < header->caplen) { |
2600 | 1.30k | ext_length = packet[offset] << 2; |
2601 | 1.30k | offset += ext_length; |
2602 | 1.30k | if(offset >= header->caplen || ext_length == 0) { |
2603 | 207 | exts_parsing_error = 1; |
2604 | 207 | break; |
2605 | 207 | } |
2606 | 1.09k | if(packet[offset - 1] == 0) |
2607 | 252 | break; |
2608 | 1.09k | } |
2609 | 1.20k | } |
2610 | | |
2611 | 10.3k | if(offset < header->caplen && !exts_parsing_error) { |
2612 | | /* Ok, valid GTP-U */ |
2613 | 2.81k | tunnel_type = ndpi_gtp_tunnel; |
2614 | 2.81k | ip_offset = offset; |
2615 | 2.81k | iph = (struct ndpi_iphdr *)&packet[ip_offset]; |
2616 | 2.81k | if(iph->version == 6) { |
2617 | 90 | iph6 = (struct ndpi_ipv6hdr *)&packet[ip_offset]; |
2618 | 90 | iph = NULL; |
2619 | 90 | if(header->caplen < ip_offset + sizeof(struct ndpi_ipv6hdr)) |
2620 | 45 | return(nproto); |
2621 | 2.72k | } else if(iph->version != IPVERSION) { |
2622 | | // printf("WARNING: not good (packet_id=%u)!\n", (unsigned int)workflow->stats.raw_packet_count); |
2623 | 1.89k | goto v4_warning; |
2624 | 1.89k | } else { |
2625 | 831 | if(header->caplen < ip_offset + sizeof(struct ndpi_iphdr)) |
2626 | 178 | return(nproto); |
2627 | 831 | } |
2628 | 2.81k | } |
2629 | 10.3k | } |
2630 | 238k | } else if((sport == TZSP_PORT) || (dport == TZSP_PORT)) { |
2631 | | /* https://en.wikipedia.org/wiki/TZSP */ |
2632 | 734 | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr) + 4) |
2633 | 41 | return(nproto); /* Too short for TZSP*/ |
2634 | | |
2635 | 693 | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2636 | 693 | u_int8_t version = packet[offset]; |
2637 | 693 | u_int8_t ts_type = packet[offset+1]; |
2638 | 693 | u_int16_t encapsulates = ntohs(*((u_int16_t*)&packet[offset+2])); |
2639 | | |
2640 | 693 | tunnel_type = ndpi_tzsp_tunnel; |
2641 | | |
2642 | 693 | if((version == 1) && (ts_type == 0) && (encapsulates == 1)) { |
2643 | 179 | u_int8_t stop = 0; |
2644 | | |
2645 | 179 | offset += 4; |
2646 | | |
2647 | 179 | while((!stop) && (offset < header->caplen)) { |
2648 | 155 | u_int8_t tag_type = packet[offset]; |
2649 | 155 | u_int8_t tag_len; |
2650 | | |
2651 | 155 | switch(tag_type) { |
2652 | 60 | case 0: /* PADDING Tag */ |
2653 | 60 | tag_len = 1; |
2654 | 60 | break; |
2655 | 1 | case 1: /* END Tag */ |
2656 | 1 | tag_len = 1, stop = 1; |
2657 | 1 | break; |
2658 | 94 | default: |
2659 | 94 | if(offset + 1 >= header->caplen) |
2660 | 18 | return(nproto); /* Invalid packet */ |
2661 | 76 | tag_len = packet[offset+1]; |
2662 | 76 | break; |
2663 | 155 | } |
2664 | | |
2665 | 137 | offset += tag_len; |
2666 | | |
2667 | 137 | if(offset >= header->caplen) |
2668 | 18 | return(nproto); /* Invalid packet */ |
2669 | 119 | else { |
2670 | 119 | eth_offset = offset; |
2671 | 119 | goto datalink_check; |
2672 | 119 | } |
2673 | 137 | } |
2674 | 179 | } |
2675 | 237k | } else if((sport == NDPI_CAPWAP_DATA_PORT) || (dport == NDPI_CAPWAP_DATA_PORT)) { |
2676 | | /* We dissect ONLY CAPWAP traffic */ |
2677 | 1.28k | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2678 | | |
2679 | 1.28k | if((offset+1) < header->caplen) { |
2680 | 1.19k | uint8_t preamble = packet[offset]; |
2681 | | |
2682 | 1.19k | if((preamble & 0x0F) == 0) { /* CAPWAP header */ |
2683 | 844 | u_int16_t msg_len = (packet[offset+1] & 0xF8) >> 1; |
2684 | | |
2685 | 844 | offset += msg_len; |
2686 | | |
2687 | 844 | if((offset + 32 < header->caplen) && |
2688 | 599 | (packet[offset + 1] == 0x08)) { |
2689 | | /* IEEE 802.11 Data */ |
2690 | 114 | offset += 24; |
2691 | | /* LLC header is 8 bytes */ |
2692 | 114 | type = ntohs((u_int16_t)*((u_int16_t*)&packet[offset+6])); |
2693 | | |
2694 | 114 | ip_offset = offset + 8; |
2695 | | |
2696 | 114 | tunnel_type = ndpi_capwap_tunnel; |
2697 | 114 | goto iph_check; |
2698 | 114 | } |
2699 | 844 | } |
2700 | 1.19k | } |
2701 | 236k | }else if(ndpi_is_valid_vxlan(header, packet, ip_offset, ip_len)){ |
2702 | 5.24k | tunnel_type = ndpi_vxlan_tunnel; |
2703 | 5.24k | eth_offset = ndpi_skip_vxlan(ip_offset, ip_len); |
2704 | 5.24k | goto datalink_check; |
2705 | 5.24k | } |
2706 | 257k | } |
2707 | 548k | } else if(workflow->prefs.decode_tunnels && (proto == IPPROTO_GRE)) { |
2708 | 3.91k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_gre_basehdr)) |
2709 | 113 | return(nproto); /* Too short for GRE header*/ |
2710 | 3.80k | u_int32_t offset = 0; |
2711 | 3.80k | if((offset = ndpi_is_valid_gre_tunnel(header, packet, ip_offset, ip_len))) { |
2712 | 2.56k | tunnel_type = ndpi_gre_tunnel; |
2713 | 2.56k | struct ndpi_gre_basehdr *grehdr = (struct ndpi_gre_basehdr*)&packet[ip_offset + ip_len]; |
2714 | 2.56k | if(grehdr->protocol == ntohs(ETH_P_IP) || grehdr->protocol == ntohs(ETH_P_IPV6)) { |
2715 | 329 | ip_offset = offset; |
2716 | 329 | goto iph_check; |
2717 | 2.23k | } else if(grehdr->protocol == NDPI_GRE_PROTO_PPP) { // ppp protocol |
2718 | 1.36k | ip_offset = offset + NDPI_PPP_HDRLEN; |
2719 | 1.36k | goto iph_check; |
2720 | 1.36k | } else { |
2721 | 865 | eth_offset = offset; |
2722 | 865 | goto datalink_check; |
2723 | 865 | } |
2724 | 2.56k | } else { |
2725 | 1.24k | return(nproto); |
2726 | 1.24k | } |
2727 | 3.80k | } |
2728 | | |
2729 | | /* process the packet */ |
2730 | 793k | return(packet_processing(workflow, time_ms, vlan_id, tunnel_type, iph, iph6, |
2731 | 793k | header->caplen - ip_offset, |
2732 | 793k | header->caplen, header, packet, header->ts, |
2733 | 793k | flow_risk, flow)); |
2734 | 805k | } |
2735 | | |
2736 | | /* *********************************************** */ |
2737 | | |
2738 | | #ifdef USE_DPDK |
2739 | | |
2740 | | #include <rte_version.h> |
2741 | | #include <rte_ether.h> |
2742 | | |
2743 | | static const struct rte_eth_conf port_conf_default = { |
2744 | | #if(RTE_VERSION < RTE_VERSION_NUM(19, 8, 0, 0)) |
2745 | | .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } |
2746 | | #else |
2747 | | .rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN } |
2748 | | #endif |
2749 | | }; |
2750 | | |
2751 | | /* ************************************ */ |
2752 | | |
2753 | | int dpdk_port_init(int port, struct rte_mempool *mbuf_pool) { |
2754 | | struct rte_eth_conf port_conf = port_conf_default; |
2755 | | const u_int16_t rx_rings = 1, tx_rings = 1; |
2756 | | int retval; |
2757 | | u_int16_t q; |
2758 | | |
2759 | | /* 1 RX queue */ |
2760 | | retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); |
2761 | | |
2762 | | if(retval != 0) |
2763 | | return retval; |
2764 | | |
2765 | | for(q = 0; q < rx_rings; q++) { |
2766 | | retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, rte_eth_dev_socket_id(port), NULL, mbuf_pool); |
2767 | | if(retval < 0) |
2768 | | return retval; |
2769 | | } |
2770 | | |
2771 | | for(q = 0; q < tx_rings; q++) { |
2772 | | retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, rte_eth_dev_socket_id(port), NULL); |
2773 | | if(retval < 0) |
2774 | | return retval; |
2775 | | } |
2776 | | |
2777 | | retval = rte_eth_dev_start(port); |
2778 | | |
2779 | | if(retval < 0) |
2780 | | return retval; |
2781 | | |
2782 | | rte_eth_promiscuous_enable(port); |
2783 | | |
2784 | | return 0; |
2785 | | } |
2786 | | |
2787 | | int dpdk_port_deinit(int port) { |
2788 | | rte_eth_dev_stop(port); |
2789 | | rte_eth_dev_close(port); |
2790 | | return 0; |
2791 | | } |
2792 | | |
2793 | | #endif |