/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.12M | #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 | 524k | #define GTP_U_V1_PORT 2152 |
67 | 486k | #define NDPI_CAPWAP_DATA_PORT 5247 |
68 | 488k | #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 | 274k | void ndpi_free_flow_info_half(struct ndpi_flow_info *flow) { |
334 | 274k | if(flow->ndpi_flow) { ndpi_flow_free(flow->ndpi_flow); flow->ndpi_flow = NULL; } |
335 | 274k | } |
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 | 225k | void ndpi_flow_info_freer(void *node) { |
455 | 225k | struct ndpi_flow_info *flow = (struct ndpi_flow_info*)node; |
456 | | |
457 | 225k | ndpi_flow_info_free_data(flow); |
458 | 225k | ndpi_free(flow); |
459 | 225k | } |
460 | | |
461 | | /* ***************************************************** */ |
462 | | |
463 | 225k | static void ndpi_free_flow_tls_data(struct ndpi_flow_info *flow) { |
464 | 225k | if(flow->dhcp_fingerprint) { |
465 | 237 | ndpi_free(flow->dhcp_fingerprint); |
466 | 237 | flow->dhcp_fingerprint = NULL; |
467 | 237 | } |
468 | | |
469 | 225k | if(flow->dhcp_class_ident) { |
470 | 145 | ndpi_free(flow->dhcp_class_ident); |
471 | 145 | flow->dhcp_class_ident = NULL; |
472 | 145 | } |
473 | | |
474 | 225k | if(flow->server_hostname) { |
475 | 5.94k | ndpi_free(flow->server_hostname); |
476 | 5.94k | flow->server_hostname = NULL; |
477 | 5.94k | } |
478 | | |
479 | 225k | if(flow->bittorent_hash) { |
480 | 114 | ndpi_free(flow->bittorent_hash); |
481 | 114 | flow->bittorent_hash = NULL; |
482 | 114 | } |
483 | | |
484 | 225k | if(flow->telnet.username) { |
485 | 67 | ndpi_free(flow->telnet.username); |
486 | 67 | flow->telnet.username = NULL; |
487 | 67 | } |
488 | | |
489 | 225k | if(flow->telnet.password) { |
490 | 30 | ndpi_free(flow->telnet.password); |
491 | 30 | flow->telnet.password = NULL; |
492 | 30 | } |
493 | | |
494 | 225k | 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 | 225k | 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 | 225k | if(flow->ssh_tls.negotiated_alpn) { |
505 | 867 | ndpi_free(flow->ssh_tls.negotiated_alpn); |
506 | 867 | flow->ssh_tls.negotiated_alpn = NULL; |
507 | 867 | } |
508 | | |
509 | 225k | if(flow->ssh_tls.tls_supported_versions) { |
510 | 5.38k | ndpi_free(flow->ssh_tls.tls_supported_versions); |
511 | 5.38k | flow->ssh_tls.tls_supported_versions = NULL; |
512 | 5.38k | } |
513 | | |
514 | 225k | 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 | 225k | 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 | 225k | if(flow->ssh_tls.ja4_client_raw) { |
525 | 8.21k | ndpi_free(flow->ssh_tls.ja4_client_raw); |
526 | 8.21k | flow->ssh_tls.ja4_client_raw = NULL; |
527 | 8.21k | } |
528 | | |
529 | 225k | if(flow->ndpi_fingerprint) { |
530 | 8.44k | ndpi_free(flow->ndpi_fingerprint); |
531 | 8.44k | flow->ndpi_fingerprint = NULL; |
532 | 8.44k | } |
533 | | |
534 | 225k | if(flow->stun.mapped_address.aps) { |
535 | 1.70k | ndpi_free(flow->stun.mapped_address.aps); |
536 | 1.70k | flow->stun.mapped_address.aps = NULL; |
537 | 1.70k | } |
538 | 225k | 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 | 225k | if(flow->stun.peer_address.aps) { |
543 | 579 | ndpi_free(flow->stun.peer_address.aps); |
544 | 579 | flow->stun.peer_address.aps = NULL; |
545 | 579 | } |
546 | 225k | if(flow->stun.relayed_address.aps) { |
547 | 717 | ndpi_free(flow->stun.relayed_address.aps); |
548 | 717 | flow->stun.relayed_address.aps = NULL; |
549 | 717 | } |
550 | 225k | 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 | 225k | } |
555 | | |
556 | | /* ***************************************************** */ |
557 | | |
558 | 225k | static void ndpi_free_flow_data_analysis(struct ndpi_flow_info *flow) { |
559 | 225k | if(flow->iat_c_to_s) ndpi_free_data_analysis(flow->iat_c_to_s, 1); |
560 | 225k | if(flow->iat_s_to_c) ndpi_free_data_analysis(flow->iat_s_to_c, 1); |
561 | | |
562 | 225k | if(flow->pktlen_c_to_s) ndpi_free_data_analysis(flow->pktlen_c_to_s, 1); |
563 | 225k | if(flow->pktlen_s_to_c) ndpi_free_data_analysis(flow->pktlen_s_to_c, 1); |
564 | | |
565 | 225k | if(flow->iat_flow) ndpi_free_data_analysis(flow->iat_flow, 1); |
566 | | |
567 | 225k | if(flow->entropy) ndpi_free(flow->entropy); |
568 | 225k | if(flow->last_entropy) ndpi_free(flow->last_entropy); |
569 | 225k | } |
570 | | |
571 | | /* ***************************************************** */ |
572 | | |
573 | 225k | void ndpi_flow_info_free_data(struct ndpi_flow_info *flow) { |
574 | | |
575 | 225k | ndpi_free_flow_info_half(flow); |
576 | 225k | ndpi_term_serializer(&flow->ndpi_flow_serializer); |
577 | 225k | ndpi_free_flow_data_analysis(flow); |
578 | 225k | 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 | 225k | ndpi_free_bin(&flow->payload_len_bin); |
585 | 225k | #endif |
586 | | |
587 | 225k | if(flow->src_name) ndpi_free(flow->src_name); |
588 | 225k | if(flow->dst_name) ndpi_free(flow->dst_name); |
589 | 225k | if(flow->tcp_fingerprint) ndpi_free(flow->tcp_fingerprint); |
590 | 225k | if(flow->risk_str) ndpi_free(flow->risk_str); |
591 | 225k | if(flow->flow_payload) ndpi_free(flow->flow_payload); |
592 | 225k | } |
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.41M | static inline int cmp_n32(uint32_t a,uint32_t b) { |
614 | 1.41M | return a == b ? 0 : ntohl(a) < ntohl(b) ? -1:1; |
615 | 1.41M | } |
616 | 1.19M | static inline int cmp_n16(uint16_t a,uint16_t b) { |
617 | 1.19M | return a == b ? 0 : ntohs(a) < ntohs(b) ? -1:1; |
618 | 1.19M | } |
619 | | |
620 | | /* ***************************************************** */ |
621 | | |
622 | 5.61M | int ndpi_workflow_node_cmp(const void *a, const void *b) { |
623 | 5.61M | const struct ndpi_flow_info *fa = (const struct ndpi_flow_info*)a; |
624 | 5.61M | const struct ndpi_flow_info *fb = (const struct ndpi_flow_info*)b; |
625 | | |
626 | 5.61M | if(fa->hashval < fb->hashval) return(-1); else if(fa->hashval > fb->hashval) return(1); |
627 | | |
628 | | /* Flows have the same hash */ |
629 | | |
630 | 841k | if(fa->vlan_id < fb->vlan_id ) return(-1); else { if(fa->vlan_id > fb->vlan_id ) return(1); } |
631 | 839k | if(fa->protocol < fb->protocol ) return(-1); else { if(fa->protocol > fb->protocol ) return(1); } |
632 | | |
633 | 836k | int r; |
634 | 836k | r = cmp_n32(fa->src_ip, fb->src_ip); if(r) return r; |
635 | 617k | r = cmp_n16(fa->src_port, fb->src_port) ; if(r) return r; |
636 | 577k | r = cmp_n32(fa->dst_ip, fb->dst_ip); if(r) return r; |
637 | 575k | r = cmp_n16(fa->dst_port, fb->dst_port); |
638 | | |
639 | 575k | return(r); |
640 | 577k | } |
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 | 801k | 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 | 801k | 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 | 801k | u_int32_t current_count; |
664 | | |
665 | 801k | if(src_to_dst_direction) { |
666 | 627k | current_count = flow->entropy->src2dst_l4_bytes - len; |
667 | 627k | } else { |
668 | 173k | current_count = flow->entropy->dst2src_l4_bytes - len; |
669 | 173k | } |
670 | | |
671 | 801k | if(current_count < ETTA_MIN_OCTETS) { |
672 | 754k | u_int32_t i; |
673 | 754k | const unsigned char *data = x; |
674 | | |
675 | 135M | for(i=0; i<len; i++) { |
676 | 134M | if(src_to_dst_direction) { |
677 | 87.7M | flow->entropy->src2dst_byte_count[data[i]]++; |
678 | 87.7M | } else { |
679 | 47.0M | flow->entropy->dst2src_byte_count[data[i]]++; |
680 | 47.0M | } |
681 | 134M | current_count++; |
682 | 134M | if(current_count >= ETTA_MIN_OCTETS) { |
683 | 8.96k | break; |
684 | 8.96k | } |
685 | 134M | } |
686 | 754k | } |
687 | 801k | } |
688 | 801k | } |
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 | 801k | unsigned int len, u_int8_t src_to_dst_direction) { |
702 | 801k | const unsigned char *data = x; |
703 | | |
704 | 801k | if((flow->entropy->src2dst_pkt_count+flow->entropy->dst2src_pkt_count) <= max_num_packets_per_flow) { |
705 | 801k | unsigned int i; |
706 | | |
707 | 166M | for(i=0; i<len; i++) { |
708 | 165M | double delta; |
709 | | |
710 | 165M | if(src_to_dst_direction) { |
711 | 103M | flow->entropy->src2dst_num_bytes += 1; |
712 | 103M | delta = ((double)data[i] - flow->entropy->src2dst_bd_mean); |
713 | 103M | flow->entropy->src2dst_bd_mean += delta/((double)flow->entropy->src2dst_num_bytes); |
714 | 103M | flow->entropy->src2dst_bd_variance += delta*((double)data[i] - flow->entropy->src2dst_bd_mean); |
715 | 103M | } else { |
716 | 62.4M | flow->entropy->dst2src_num_bytes += 1; |
717 | 62.4M | delta = ((double)data[i] - flow->entropy->dst2src_bd_mean); |
718 | 62.4M | flow->entropy->dst2src_bd_mean += delta/((double)flow->entropy->dst2src_num_bytes); |
719 | 62.4M | flow->entropy->dst2src_bd_variance += delta*((double)data[i] - flow->entropy->dst2src_bd_mean); |
720 | 62.4M | } |
721 | 165M | } |
722 | 801k | } |
723 | 801k | } |
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 | 809k | pkt_timeval when) { |
744 | 809k | u_int32_t idx, hashval; |
745 | 809k | struct ndpi_flow_info flow; |
746 | 809k | void *ret; |
747 | 809k | const u_int8_t *l3, *l4; |
748 | 809k | 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 | 809k | if(version == IPVERSION) { |
755 | 735k | if(ipsize < 20) |
756 | 10 | return NULL; |
757 | | |
758 | 735k | if((iph->ihl * 4) > ipsize || ipsize < ntohs(iph->tot_len) |
759 | 735k | /* || (iph->frag_off & htons(0x1FFF)) != 0 */) |
760 | 6.79k | return NULL; |
761 | | |
762 | 729k | l3 = (const u_int8_t*)iph; |
763 | 729k | } else { |
764 | 73.1k | if(l4_offset > ipsize) |
765 | 0 | return NULL; |
766 | | |
767 | 73.1k | l3 = (const u_int8_t*)iph6; |
768 | 73.1k | } |
769 | 802k | if(ipsize < l4_offset + l4_packet_len) |
770 | 901 | return NULL; |
771 | | |
772 | 801k | *proto = iph->protocol; |
773 | | |
774 | 801k | if(l4_packet_len < 64) |
775 | 470k | workflow->stats.packet_len[0]++; |
776 | 331k | else if(l4_packet_len >= 64 && l4_packet_len < 128) |
777 | 91.8k | workflow->stats.packet_len[1]++; |
778 | 239k | else if(l4_packet_len >= 128 && l4_packet_len < 256) |
779 | 90.6k | workflow->stats.packet_len[2]++; |
780 | 148k | else if(l4_packet_len >= 256 && l4_packet_len < 1024) |
781 | 82.7k | workflow->stats.packet_len[3]++; |
782 | 65.9k | else if(l4_packet_len >= 1024 && l4_packet_len < 1500) |
783 | 61.9k | workflow->stats.packet_len[4]++; |
784 | 4.02k | else if(l4_packet_len >= 1500) |
785 | 4.02k | workflow->stats.packet_len[5]++; |
786 | | |
787 | 801k | if(l4_packet_len > workflow->stats.max_packet_len) |
788 | 237 | workflow->stats.max_packet_len = l4_packet_len; |
789 | | |
790 | 801k | l4 =& ((const u_int8_t *) l3)[l4_offset]; |
791 | | |
792 | 801k | if(*proto == IPPROTO_TCP && l4_packet_len >= sizeof(struct ndpi_tcphdr)) { |
793 | 462k | u_int tcp_len; |
794 | | |
795 | | // TCP |
796 | 462k | workflow->stats.tcp_count++; |
797 | 462k | *tcph = (struct ndpi_tcphdr *)l4; |
798 | 462k | *sport = ntohs((*tcph)->source), *dport = ntohs((*tcph)->dest); |
799 | 462k | tcp_len = ndpi_min(4*(*tcph)->doff, l4_packet_len); |
800 | 462k | *payload = (u_int8_t*)&l4[tcp_len]; |
801 | 462k | *payload_len = ndpi_max(0, l4_packet_len-4*(*tcph)->doff); |
802 | 462k | l4_data_len = l4_packet_len - sizeof(struct ndpi_tcphdr); |
803 | 462k | } else if(*proto == IPPROTO_UDP && l4_packet_len >= sizeof(struct ndpi_udphdr)) { |
804 | | // UDP |
805 | 305k | workflow->stats.udp_count++; |
806 | 305k | *udph = (struct ndpi_udphdr *)l4; |
807 | 305k | *sport = ntohs((*udph)->source), *dport = ntohs((*udph)->dest); |
808 | 305k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_udphdr)]; |
809 | 305k | *payload_len = (l4_packet_len > sizeof(struct ndpi_udphdr)) ? l4_packet_len-sizeof(struct ndpi_udphdr) : 0; |
810 | 305k | l4_data_len = l4_packet_len - sizeof(struct ndpi_udphdr); |
811 | 305k | } else if(*proto == IPPROTO_ICMP) { |
812 | 8.24k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_icmphdr )]; |
813 | 8.24k | *payload_len = (l4_packet_len > sizeof(struct ndpi_icmphdr)) ? l4_packet_len-sizeof(struct ndpi_icmphdr) : 0; |
814 | 8.24k | l4_data_len = l4_packet_len - sizeof(struct ndpi_icmphdr); |
815 | 8.24k | *sport = *dport = 0; |
816 | 25.2k | } else if(*proto == IPPROTO_ICMPV6) { |
817 | 5.39k | *payload = (u_int8_t*)&l4[sizeof(struct ndpi_icmp6hdr)]; |
818 | 5.39k | *payload_len = (l4_packet_len > sizeof(struct ndpi_icmp6hdr)) ? l4_packet_len-sizeof(struct ndpi_icmp6hdr) : 0; |
819 | 5.39k | l4_data_len = l4_packet_len - sizeof(struct ndpi_icmp6hdr); |
820 | 5.39k | *sport = *dport = 0; |
821 | 19.8k | } else { |
822 | | // non tcp/udp protocols |
823 | 19.8k | *sport = *dport = 0; |
824 | 19.8k | l4_data_len = 0; |
825 | 19.8k | } |
826 | | |
827 | 801k | flow.protocol = iph->protocol, flow.vlan_id = vlan_id; |
828 | 801k | flow.src_ip = iph->saddr, flow.dst_ip = iph->daddr; |
829 | 801k | flow.src_port = htons(*sport), flow.dst_port = htons(*dport); |
830 | 801k | flow.hashval = hashval = flow.protocol + ntohl(flow.src_ip) + ntohl(flow.dst_ip) |
831 | 801k | + 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 | 801k | idx = hashval % workflow->prefs.num_roots; |
844 | 801k | 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 | 801k | int is_changed = 0; |
848 | 801k | if(ret == NULL) { |
849 | 399k | u_int32_t orig_src_ip = flow.src_ip; |
850 | 399k | u_int16_t orig_src_port = flow.src_port; |
851 | 399k | u_int32_t orig_dst_ip = flow.dst_ip; |
852 | 399k | u_int16_t orig_dst_port = flow.dst_port; |
853 | | |
854 | 399k | flow.src_ip = orig_dst_ip; |
855 | 399k | flow.src_port = orig_dst_port; |
856 | 399k | flow.dst_ip = orig_src_ip; |
857 | 399k | flow.dst_port = orig_src_port; |
858 | | |
859 | 399k | is_changed = 1; |
860 | | |
861 | 399k | ret = ndpi_tfind(&flow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp); |
862 | 399k | } |
863 | | |
864 | 801k | if(ret == NULL) { |
865 | 225k | 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 | 225k | } else { |
871 | 225k | struct ndpi_flow_info *newflow = (struct ndpi_flow_info*)ndpi_malloc(sizeof(struct ndpi_flow_info)); |
872 | | |
873 | 225k | 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 | 225k | workflow->num_allocated_flows++; |
878 | | |
879 | 225k | memset(newflow, 0, sizeof(struct ndpi_flow_info)); |
880 | 225k | newflow->flow_id = flow_id++; |
881 | 225k | newflow->hashval = hashval; |
882 | 225k | newflow->tunnel_type = tunnel_type; |
883 | 225k | newflow->protocol = iph->protocol, newflow->vlan_id = vlan_id; |
884 | 225k | newflow->src_ip = iph->saddr, newflow->dst_ip = iph->daddr; |
885 | 225k | newflow->src_port = htons(*sport), newflow->dst_port = htons(*dport); |
886 | 225k | newflow->ip_version = version; |
887 | 225k | newflow->iat_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
888 | 225k | newflow->iat_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW); |
889 | 225k | newflow->pktlen_c_to_s = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
890 | 225k | newflow->pktlen_s_to_c = ndpi_alloc_data_analysis(DATA_ANALUYSIS_SLIDING_WINDOW), |
891 | 225k | 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 | 225k | ndpi_init_bin(&newflow->payload_len_bin, ndpi_bin_family8, PLEN_NUM_BINS); |
898 | 225k | #endif |
899 | | |
900 | 225k | if (version == 4 || version == 6) { |
901 | 225k | uint16_t inet_addrlen = (version == 4) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; |
902 | 225k | newflow->src_name = ndpi_malloc(inet_addrlen); |
903 | 225k | newflow->dst_name = ndpi_malloc(inet_addrlen); |
904 | | |
905 | 225k | if(version == 4) { |
906 | 206k | if (newflow->src_name) |
907 | 206k | inet_ntop(AF_INET, &newflow->src_ip, newflow->src_name, inet_addrlen); |
908 | 206k | if (newflow->dst_name) |
909 | 206k | inet_ntop(AF_INET, &newflow->dst_ip, newflow->dst_name, inet_addrlen); |
910 | 206k | } else if (version == 6) { |
911 | 19.0k | newflow->src_ip6 = *(struct ndpi_in6_addr *)&iph6->ip6_src; |
912 | 19.0k | newflow->dst_ip6 = *(struct ndpi_in6_addr *)&iph6->ip6_dst; |
913 | | |
914 | 19.0k | if (newflow->src_name) |
915 | 19.0k | inet_ntop(AF_INET6, &newflow->src_ip6, newflow->src_name, inet_addrlen); |
916 | 19.0k | if (newflow->dst_name) |
917 | 19.0k | inet_ntop(AF_INET6, &newflow->dst_ip6, newflow->dst_name, inet_addrlen); |
918 | | |
919 | | /* For consistency across platforms replace :0: with :: */ |
920 | 19.0k | if (newflow->src_name) ndpi_patchIPv6Address(newflow->src_name); |
921 | 19.0k | if (newflow->dst_name) ndpi_patchIPv6Address(newflow->dst_name); |
922 | 19.0k | } |
923 | 225k | } |
924 | | |
925 | 225k | 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 | 225k | memset(newflow->ndpi_flow, 0, SIZEOF_FLOW_STRUCT); |
932 | | |
933 | 225k | if (workflow->ndpi_serialization_format != ndpi_serialization_format_unknown) |
934 | 225k | { |
935 | 225k | if (ndpi_init_serializer(&newflow->ndpi_flow_serializer, |
936 | 225k | 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 | 225k | } |
944 | | |
945 | 225k | 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 | 225k | workflow->stats.ndpi_flow_count++; |
951 | 225k | if(*proto == IPPROTO_TCP) |
952 | 133k | workflow->stats.flow_count[0]++; |
953 | 91.8k | else if(*proto == IPPROTO_UDP) |
954 | 84.1k | workflow->stats.flow_count[1]++; |
955 | 7.76k | else |
956 | 7.76k | workflow->stats.flow_count[2]++; |
957 | | |
958 | 225k | if(enable_flow_stats) { |
959 | 225k | newflow->entropy = ndpi_calloc(1, sizeof(struct ndpi_entropy)); |
960 | 225k | newflow->last_entropy = ndpi_calloc(1, sizeof(struct ndpi_entropy)); |
961 | 225k | 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 | 225k | newflow->entropy->src2dst_pkt_len[newflow->entropy->src2dst_pkt_count] = l4_data_len; |
968 | 225k | newflow->entropy->src2dst_pkt_time[newflow->entropy->src2dst_pkt_count] = when; |
969 | 225k | if(newflow->entropy->src2dst_pkt_count == 0) { |
970 | 225k | newflow->entropy->src2dst_start = when; |
971 | 225k | } |
972 | 225k | newflow->entropy->src2dst_pkt_count++; |
973 | | // Non zero app data. |
974 | 225k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
975 | 217k | newflow->entropy->src2dst_opackets++; |
976 | 217k | newflow->entropy->src2dst_l4_bytes += l4_data_len; |
977 | 217k | } |
978 | 225k | } |
979 | 225k | return newflow; |
980 | 225k | } |
981 | 575k | } else { |
982 | 575k | struct ndpi_flow_info *rflow = *(struct ndpi_flow_info**)ret; |
983 | | |
984 | 575k | if(is_changed) { |
985 | 173k | *src_to_dst_direction = 0, rflow->bidirectional |= 1; |
986 | 173k | } |
987 | 401k | else { |
988 | 401k | *src_to_dst_direction = 1; |
989 | 401k | } |
990 | 575k | if(enable_flow_stats) { |
991 | 575k | if(*src_to_dst_direction) { |
992 | 401k | if(rflow->entropy->src2dst_pkt_count < max_num_packets_per_flow) { |
993 | 401k | rflow->entropy->src2dst_pkt_len[rflow->entropy->src2dst_pkt_count] = l4_data_len; |
994 | 401k | rflow->entropy->src2dst_pkt_time[rflow->entropy->src2dst_pkt_count] = when; |
995 | 401k | rflow->entropy->src2dst_l4_bytes += l4_data_len; |
996 | 401k | rflow->entropy->src2dst_pkt_count++; |
997 | 401k | } |
998 | | // Non zero app data. |
999 | 401k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
1000 | 360k | rflow->entropy->src2dst_opackets++; |
1001 | 360k | } |
1002 | 401k | } else { |
1003 | 173k | if(rflow->entropy->dst2src_pkt_count < max_num_packets_per_flow) { |
1004 | 173k | rflow->entropy->dst2src_pkt_len[rflow->entropy->dst2src_pkt_count] = l4_data_len; |
1005 | 173k | rflow->entropy->dst2src_pkt_time[rflow->entropy->dst2src_pkt_count] = when; |
1006 | 173k | if(rflow->entropy->dst2src_pkt_count == 0) { |
1007 | 51.7k | rflow->entropy->dst2src_start = when; |
1008 | 51.7k | } |
1009 | 173k | rflow->entropy->dst2src_l4_bytes += l4_data_len; |
1010 | 173k | rflow->entropy->dst2src_pkt_count++; |
1011 | 173k | } |
1012 | | // Non zero app data. |
1013 | 173k | if(l4_data_len != 0XFEEDFACE && l4_data_len != 0) { |
1014 | 153k | rflow->entropy->dst2src_opackets++; |
1015 | 153k | } |
1016 | 173k | } |
1017 | 575k | } |
1018 | | |
1019 | 575k | return(rflow); |
1020 | 575k | } |
1021 | 801k | } |
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 | 73.2k | pkt_timeval when) { |
1038 | 73.2k | struct ndpi_iphdr iph; |
1039 | | |
1040 | 73.2k | if(ipsize < 40) |
1041 | 10 | return(NULL); |
1042 | 73.2k | memset(&iph, 0, sizeof(iph)); |
1043 | 73.2k | iph.version = IPVERSION; |
1044 | 73.2k | iph.saddr = iph6->ip6_src.u6_addr.u6_addr32[2] + iph6->ip6_src.u6_addr.u6_addr32[3]; |
1045 | 73.2k | iph.daddr = iph6->ip6_dst.u6_addr.u6_addr32[2] + iph6->ip6_dst.u6_addr.u6_addr32[3]; |
1046 | 73.2k | u_int8_t l4proto = iph6->ip6_hdr.ip6_un1_nxt; |
1047 | 73.2k | u_int16_t ip_len = ntohs(iph6->ip6_hdr.ip6_un1_plen); |
1048 | 73.2k | const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr)); |
1049 | 73.2k | if(ipsize < sizeof(struct ndpi_ipv6hdr) + ip_len) |
1050 | 12 | return(NULL); |
1051 | 73.2k | if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &l4proto) != 0) { |
1052 | 26 | return(NULL); |
1053 | 26 | } |
1054 | 73.1k | iph.protocol = l4proto; |
1055 | | |
1056 | 73.1k | return(get_ndpi_flow_info(workflow, 6, vlan_id, tunnel_type, |
1057 | 73.1k | &iph, iph6, ipsize, |
1058 | 73.1k | ip_len, l4ptr - (const u_int8_t *)iph6, |
1059 | 73.1k | tcph, udph, sport, dport, |
1060 | 73.1k | proto, payload, |
1061 | 73.1k | payload_len, src_to_dst_direction, when)); |
1062 | 73.2k | } |
1063 | | |
1064 | | /* ****************************************************** */ |
1065 | | |
1066 | 855k | u_int8_t is_ndpi_proto(struct ndpi_flow_info *flow, u_int16_t id) { |
1067 | 855k | if((flow->detected_protocol.proto.master_protocol == id) |
1068 | 803k | || (flow->detected_protocol.proto.app_protocol == id)) |
1069 | 73.0k | return(1); |
1070 | 782k | else |
1071 | 782k | return(0); |
1072 | 855k | } |
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 | 624k | u_int8_t plen2slot(u_int16_t plen) { |
1085 | | /* |
1086 | | Slots [32 bytes lenght] |
1087 | | 0..31, 32..63 ... |
1088 | | */ |
1089 | | |
1090 | 624k | if(plen > PLEN_MAX) |
1091 | 3.72k | return(PLEN_NUM_BINS-1); |
1092 | 620k | else |
1093 | 620k | return(plen/PLEN_BIN_LEN); |
1094 | 624k | } |
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, |
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 | 233k | { |
1137 | 233k | int new_num; |
1138 | 233k | void *new_buf; |
1139 | 233k | unsigned int i; |
1140 | | |
1141 | 233k | if(ap->port == 0) |
1142 | 221k | return; |
1143 | | |
1144 | | /* Avoid saving duplicates */ |
1145 | 18.3k | for(i = 0; i < list->num_aps; i++) |
1146 | 13.7k | if(memcmp(&list->aps[i], ap, sizeof(*ap)) == 0) |
1147 | 7.23k | return; |
1148 | | |
1149 | 4.54k | if(list->num_aps == list->num_aps_allocated) { |
1150 | 4.11k | new_num = 1 + list->num_aps_allocated * 2; |
1151 | 4.11k | new_buf = ndpi_realloc(list->aps, list->num_aps_allocated * sizeof(ndpi_address_port), |
1152 | 4.11k | new_num * sizeof(ndpi_address_port)); |
1153 | 4.11k | if(!new_buf) |
1154 | 0 | return; |
1155 | 4.11k | list->aps = new_buf; |
1156 | 4.11k | list->num_aps_allocated = new_num; |
1157 | 4.11k | } |
1158 | 4.54k | memcpy(&list->aps[list->num_aps++], ap, sizeof(ndpi_address_port)); |
1159 | 4.54k | } |
1160 | | |
1161 | | /* ****************************************************** */ |
1162 | | |
1163 | 595k | static void process_ndpi_monitoring_info(struct ndpi_flow_info *flow) { |
1164 | 595k | if(!flow->ndpi_flow || !flow->ndpi_flow->monit) |
1165 | 547k | return; |
1166 | | |
1167 | 47.4k | if(flow->monitoring_state == 0 && |
1168 | 26.7k | flow->ndpi_flow->monitoring) { |
1169 | | /* We just moved to monitoring state */ |
1170 | 273 | flow->monitoring_state = 1; |
1171 | 273 | flow->num_packets_before_monitoring = flow->ndpi_flow->packet_direction_complete_counter[0] + flow->ndpi_flow->packet_direction_complete_counter[1]; |
1172 | 273 | } |
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 | 47.4k | if(flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_STUN || |
1181 | 44.6k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_STUN || |
1182 | 21.2k | flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_DTLS || |
1183 | 21.1k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_DTLS || |
1184 | 16.0k | flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_SRTP || |
1185 | 46.6k | flow->detected_protocol.proto.master_protocol == NDPI_PROTOCOL_SRTP) { |
1186 | | |
1187 | 46.6k | add_to_address_port_list(&flow->stun.mapped_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.mapped_address); |
1188 | 46.6k | add_to_address_port_list(&flow->stun.other_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.other_address); |
1189 | 46.6k | add_to_address_port_list(&flow->stun.peer_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.peer_address); |
1190 | 46.6k | add_to_address_port_list(&flow->stun.relayed_address, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.relayed_address); |
1191 | 46.6k | add_to_address_port_list(&flow->stun.response_origin, &flow->ndpi_flow->monit->protos.dtls_stun_rtp.response_origin); |
1192 | 46.6k | flow->multimedia_flow_types |= flow->ndpi_flow->flow_multimedia_types; |
1193 | | |
1194 | 46.6k | flow->stun.rtp_counters[0] = flow->ndpi_flow->stun.rtp_counters[0]; |
1195 | 46.6k | flow->stun.rtp_counters[1] = flow->ndpi_flow->stun.rtp_counters[1]; |
1196 | 46.6k | } |
1197 | 47.4k | } |
1198 | | |
1199 | | /* ****************************************************** */ |
1200 | | |
1201 | | static void serialize_monitoring_metadata(struct ndpi_flow_info *flow) |
1202 | 325 | { |
1203 | 325 | unsigned int i; |
1204 | 325 | char buf[64]; |
1205 | | |
1206 | 325 | if(!flow->ndpi_flow->monit) |
1207 | 52 | return; |
1208 | | |
1209 | 273 | ndpi_serialize_start_of_block(&flow->ndpi_flow_serializer, "monitoring"); |
1210 | | |
1211 | 273 | switch(flow->detected_protocol.proto.master_protocol ? flow->detected_protocol.proto.master_protocol : flow->detected_protocol.proto.app_protocol) { |
1212 | 93 | case NDPI_PROTOCOL_STUN: |
1213 | 153 | case NDPI_PROTOCOL_DTLS: |
1214 | 266 | case NDPI_PROTOCOL_SRTP: |
1215 | 266 | ndpi_serialize_start_of_block(&flow->ndpi_flow_serializer, "stun"); |
1216 | | |
1217 | 266 | if(flow->stun.mapped_address.num_aps > 0) { |
1218 | 221 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "mapped_address"); |
1219 | 689 | for(i = 0; i < flow->stun.mapped_address.num_aps; i++) { |
1220 | 468 | if(flow->stun.mapped_address.aps[i].port > 0) { |
1221 | 468 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "mapped_address", |
1222 | 468 | print_ndpi_address_port(&flow->stun.mapped_address.aps[i], buf, sizeof(buf))); |
1223 | 468 | } |
1224 | 468 | } |
1225 | 221 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1226 | 221 | } |
1227 | | |
1228 | 266 | 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 | 266 | if(flow->stun.peer_address.num_aps > 0) { |
1240 | 97 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "peer_address"); |
1241 | 441 | for(i = 0; i < flow->stun.peer_address.num_aps; i++) { |
1242 | 344 | if(flow->stun.peer_address.aps[i].port > 0) { |
1243 | 344 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "peer_address", |
1244 | 344 | print_ndpi_address_port(&flow->stun.peer_address.aps[i], buf, sizeof(buf))); |
1245 | 344 | } |
1246 | 344 | } |
1247 | 97 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1248 | 97 | } |
1249 | | |
1250 | 266 | if(flow->stun.relayed_address.num_aps > 0) { |
1251 | 132 | ndpi_serialize_start_of_list(&flow->ndpi_flow_serializer, "relayed_address"); |
1252 | 297 | for(i = 0; i < flow->stun.relayed_address.num_aps; i++) { |
1253 | 165 | if(flow->stun.relayed_address.aps[i].port > 0) { |
1254 | 165 | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "relayed_address", |
1255 | 165 | print_ndpi_address_port(&flow->stun.relayed_address.aps[i], buf, sizeof(buf))); |
1256 | 165 | } |
1257 | 165 | } |
1258 | 132 | ndpi_serialize_end_of_list(&flow->ndpi_flow_serializer); |
1259 | 132 | } |
1260 | | |
1261 | 266 | 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 | 266 | ndpi_serialize_end_of_block(&flow->ndpi_flow_serializer); /* stun */ |
1273 | | |
1274 | 266 | break; |
1275 | 273 | } |
1276 | | |
1277 | 273 | ndpi_serialize_end_of_block(&flow->ndpi_flow_serializer); |
1278 | 273 | } |
1279 | | |
1280 | | /* ****************************************************** */ |
1281 | | |
1282 | 274k | void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_flow_info *flow) { |
1283 | 274k | u_int i; |
1284 | 274k | char out[128], *s; |
1285 | | |
1286 | 274k | if(!flow->ndpi_flow) return; |
1287 | | |
1288 | 225k | flow->info_type = INFO_INVALID; |
1289 | | |
1290 | 225k | s = ndpi_get_flow_risk_info(flow->ndpi_flow, out, sizeof(out), 0 /* text */); |
1291 | | |
1292 | 225k | if(s != NULL) |
1293 | 191k | flow->risk_str = ndpi_strdup(s); |
1294 | | |
1295 | 225k | flow->confidence = flow->ndpi_flow->confidence; |
1296 | | |
1297 | 225k | flow->num_dissector_calls = flow->ndpi_flow->num_dissector_calls; |
1298 | | |
1299 | 225k | ndpi_snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s", |
1300 | 225k | flow->ndpi_flow->host_server_name); |
1301 | | |
1302 | 225k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MINING)) { |
1303 | 88 | ndpi_snprintf(flow->mining.currency, sizeof(flow->mining.currency), "%s", |
1304 | 88 | flow->ndpi_flow->protos.mining.currency); |
1305 | 88 | } |
1306 | | |
1307 | 225k | flow->risk = flow->ndpi_flow->risk; |
1308 | | |
1309 | 225k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DHCP)) { |
1310 | 635 | if(flow->ndpi_flow->protos.dhcp.fingerprint[0] != '\0') |
1311 | 237 | flow->dhcp_fingerprint = ndpi_strdup(flow->ndpi_flow->protos.dhcp.fingerprint); |
1312 | | |
1313 | 635 | if(flow->ndpi_flow->protos.dhcp.class_ident[0] != '\0') |
1314 | 145 | flow->dhcp_class_ident = ndpi_strdup(flow->ndpi_flow->protos.dhcp.class_ident); |
1315 | 225k | } else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_BITTORRENT) && |
1316 | 10.9k | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DNS) && |
1317 | 10.9k | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TLS)) { |
1318 | 10.9k | u_int j; |
1319 | | |
1320 | 10.9k | if(flow->ndpi_flow->protos.bittorrent.hash[0] != '\0') { |
1321 | 114 | u_int avail = sizeof(flow->ndpi_flow->protos.bittorrent.hash) * 2 + 1; |
1322 | 114 | flow->bittorent_hash = ndpi_malloc(avail); |
1323 | | |
1324 | 114 | if(flow->bittorent_hash) { |
1325 | 2.39k | for(i=0, j = 0; i < sizeof(flow->ndpi_flow->protos.bittorrent.hash); i++) { |
1326 | 2.28k | snprintf(&flow->bittorent_hash[j], avail-j, "%02x", |
1327 | 2.28k | flow->ndpi_flow->protos.bittorrent.hash[i]); |
1328 | | |
1329 | 2.28k | j += 2; |
1330 | 2.28k | } |
1331 | | |
1332 | 114 | flow->bittorent_hash[j] = '\0'; |
1333 | 114 | } |
1334 | 114 | } |
1335 | 10.9k | } |
1336 | | /* TIVOCONNECT */ |
1337 | 214k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TIVOCONNECT)) { |
1338 | 186 | flow->info_type = INFO_TIVOCONNECT; |
1339 | 186 | ndpi_snprintf(flow->tivoconnect.identity_uuid, sizeof(flow->tivoconnect.identity_uuid), |
1340 | 186 | "%s", flow->ndpi_flow->protos.tivoconnect.identity_uuid); |
1341 | 186 | ndpi_snprintf(flow->tivoconnect.machine, sizeof(flow->tivoconnect.machine), |
1342 | 186 | "%s", flow->ndpi_flow->protos.tivoconnect.machine); |
1343 | 186 | ndpi_snprintf(flow->tivoconnect.platform, sizeof(flow->tivoconnect.platform), |
1344 | 186 | "%s", flow->ndpi_flow->protos.tivoconnect.platform); |
1345 | 186 | ndpi_snprintf(flow->tivoconnect.services, sizeof(flow->tivoconnect.services), |
1346 | 186 | "%s", flow->ndpi_flow->protos.tivoconnect.services); |
1347 | 186 | } |
1348 | | /* SOFTETHER */ |
1349 | 213k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SOFTETHER) && |
1350 | 260 | !ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_HTTP)) { |
1351 | 236 | flow->info_type = INFO_SOFTETHER; |
1352 | 236 | ndpi_snprintf(flow->softether.ip, sizeof(flow->softether.ip), "%s", |
1353 | 236 | flow->ndpi_flow->protos.softether.ip); |
1354 | 236 | ndpi_snprintf(flow->softether.port, sizeof(flow->softether.port), "%s", |
1355 | 236 | flow->ndpi_flow->protos.softether.port); |
1356 | 236 | ndpi_snprintf(flow->softether.hostname, sizeof(flow->softether.hostname), "%s", |
1357 | 236 | flow->ndpi_flow->protos.softether.hostname); |
1358 | 236 | ndpi_snprintf(flow->softether.fqdn, sizeof(flow->softether.fqdn), "%s", |
1359 | 236 | flow->ndpi_flow->protos.softether.fqdn); |
1360 | 236 | } |
1361 | | /* SERVICE_LOCATION */ |
1362 | 213k | 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 | 209k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_NATPMP)) { |
1383 | 342 | flow->info_type = INFO_NATPMP; |
1384 | 342 | flow->natpmp.result_code = flow->ndpi_flow->protos.natpmp.result_code; |
1385 | 342 | flow->natpmp.internal_port = flow->ndpi_flow->protos.natpmp.internal_port; |
1386 | 342 | flow->natpmp.external_port = flow->ndpi_flow->protos.natpmp.external_port; |
1387 | 342 | inet_ntop(AF_INET, &flow->ndpi_flow->protos.natpmp.external_address.ipv4, &flow->natpmp.ip[0], sizeof(flow->natpmp.ip)); |
1388 | 342 | } |
1389 | | /* DISCORD */ |
1390 | 209k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DISCORD) && |
1391 | 903 | !ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack) && |
1392 | 872 | 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 | 209k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_DNS)) { |
1399 | 7.24k | if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[0] == 0) |
1400 | 7.12k | { |
1401 | 7.12k | flow->info_type = INFO_GENERIC; |
1402 | 7.12k | inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[0].ipv4, flow->info, sizeof(flow->info)); |
1403 | 7.12k | } else { |
1404 | 118 | flow->info_type = INFO_GENERIC; |
1405 | 118 | 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 | 118 | ndpi_patchIPv6Address(flow->info); |
1409 | 118 | } |
1410 | | |
1411 | 7.24k | if(flow->ndpi_flow->protos.dns.geolocation_iata_code[0] != '\0') |
1412 | 18 | strcpy(flow->dns.geolocation_iata_code, flow->ndpi_flow->protos.dns.geolocation_iata_code); |
1413 | | |
1414 | 7.24k | 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.24k | 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.24k | } |
1437 | | /* MDNS */ |
1438 | 202k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MDNS)) { |
1439 | 998 | flow->info_type = INFO_GENERIC; |
1440 | 998 | ndpi_snprintf(flow->info, sizeof(flow->info), "%s", flow->ndpi_flow->host_server_name); |
1441 | 998 | } |
1442 | | /* UBNTAC2 */ |
1443 | 201k | 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 | 201k | else if(!ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack) && |
1449 | 180k | (ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_FTP_CONTROL) || |
1450 | 179k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_IMAP) || |
1451 | 179k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_POP) || |
1452 | 179k | ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_MAIL_SMTP))) { |
1453 | 2.88k | flow->info_type = INFO_FTP_IMAP_POP_SMTP; |
1454 | 2.88k | ndpi_snprintf(flow->ftp_imap_pop_smtp.username, |
1455 | 2.88k | sizeof(flow->ftp_imap_pop_smtp.username), |
1456 | 2.88k | "%s", flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.username); |
1457 | 2.88k | ndpi_snprintf(flow->ftp_imap_pop_smtp.password, |
1458 | 2.88k | sizeof(flow->ftp_imap_pop_smtp.password), |
1459 | 2.88k | "%s", flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.password); |
1460 | 2.88k | flow->ftp_imap_pop_smtp.auth_failed = |
1461 | 2.88k | flow->ndpi_flow->l4.tcp.ftp_imap_pop_smtp.auth_failed; |
1462 | 2.88k | } |
1463 | | /* TFTP */ |
1464 | 198k | 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 | 197k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_KERBEROS)) { |
1472 | 1.90k | flow->info_type = INFO_KERBEROS; |
1473 | 1.90k | ndpi_snprintf(flow->kerberos.domain, |
1474 | 1.90k | sizeof(flow->kerberos.domain), |
1475 | 1.90k | "%s", flow->ndpi_flow->protos.kerberos.domain); |
1476 | 1.90k | ndpi_snprintf(flow->kerberos.hostname, |
1477 | 1.90k | sizeof(flow->kerberos.hostname), |
1478 | 1.90k | "%s", flow->ndpi_flow->protos.kerberos.hostname); |
1479 | 1.90k | ndpi_snprintf(flow->kerberos.username, |
1480 | 1.90k | sizeof(flow->kerberos.username), |
1481 | 1.90k | "%s", flow->ndpi_flow->protos.kerberos.username); |
1482 | | /* COLLECTD */ |
1483 | 195k | } 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 | 195k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SIP)) { |
1491 | 494 | flow->info_type = INFO_SIP; |
1492 | 494 | if(flow->ndpi_flow->protos.sip.from) |
1493 | 281 | ndpi_snprintf(flow->sip.from, sizeof(flow->sip.from), "%s", flow->ndpi_flow->protos.sip.from); |
1494 | 494 | 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 | 494 | 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 | 494 | 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 | 494 | } |
1501 | | /* BFCP */ |
1502 | 195k | 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 | 195k | else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_TELNET)) { |
1509 | 606 | if(flow->ndpi_flow->protos.telnet.username[0] != '\0') |
1510 | 67 | flow->telnet.username = ndpi_strdup(flow->ndpi_flow->protos.telnet.username); |
1511 | 606 | if(flow->ndpi_flow->protos.telnet.password[0] != '\0') |
1512 | 30 | flow->telnet.password = ndpi_strdup(flow->ndpi_flow->protos.telnet.password); |
1513 | 194k | } else if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_SSH)) { |
1514 | 842 | ndpi_snprintf(flow->host_server_name, |
1515 | 842 | sizeof(flow->host_server_name), "%s", |
1516 | 842 | flow->ndpi_flow->protos.ssh.client_signature); |
1517 | 842 | ndpi_snprintf(flow->ssh_tls.server_info, sizeof(flow->ssh_tls.server_info), "%s", |
1518 | 842 | flow->ndpi_flow->protos.ssh.server_signature); |
1519 | 842 | ndpi_snprintf(flow->ssh_tls.client_hassh, sizeof(flow->ssh_tls.client_hassh), "%s", |
1520 | 842 | flow->ndpi_flow->protos.ssh.hassh_client); |
1521 | 842 | ndpi_snprintf(flow->ssh_tls.server_hassh, sizeof(flow->ssh_tls.server_hassh), "%s", |
1522 | 842 | flow->ndpi_flow->protos.ssh.hassh_server); |
1523 | 842 | } |
1524 | | /* TLS/QUIC/DTLS/MAIL_S/FTPS */ |
1525 | 193k | else if(ndpi_stack_is_tls_like(&flow->detected_protocol.protocol_stack)) { |
1526 | 20.6k | flow->ssh_tls.ssl_version = flow->ndpi_flow->protos.tls_quic.ssl_version; |
1527 | 20.6k | flow->ssh_tls.quic_version = flow->ndpi_flow->protos.tls_quic.quic_version; |
1528 | | |
1529 | 20.6k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_QUIC)) |
1530 | 6.97k | flow->idle_timeout_sec = flow->ndpi_flow->protos.tls_quic.quic_idle_timeout_sec; |
1531 | | |
1532 | 20.6k | 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.6k | flow->ssh_tls.notBefore = flow->ndpi_flow->protos.tls_quic.notBefore; |
1536 | 20.6k | flow->ssh_tls.notAfter = flow->ndpi_flow->protos.tls_quic.notAfter; |
1537 | 20.6k | ndpi_snprintf(flow->ssh_tls.ja4_client, sizeof(flow->ssh_tls.ja4_client), "%s", |
1538 | 20.6k | flow->ndpi_flow->protos.tls_quic.ja4_client); |
1539 | | |
1540 | 20.6k | if(flow->ndpi_flow->ndpi.fingerprint) |
1541 | 8.44k | flow->ndpi_fingerprint = ndpi_strdup(flow->ndpi_flow->ndpi.fingerprint); |
1542 | | |
1543 | 20.6k | if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw) |
1544 | 8.21k | flow->ssh_tls.ja4_client_raw = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw); |
1545 | | |
1546 | 20.6k | ndpi_snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s", |
1547 | 20.6k | flow->ndpi_flow->protos.tls_quic.ja3_server); |
1548 | 20.6k | flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.tls_quic.server_unsafe_cipher; |
1549 | 20.6k | flow->ssh_tls.server_cipher = flow->ndpi_flow->protos.tls_quic.server_cipher; |
1550 | | |
1551 | 20.6k | if(flow->ndpi_flow->protos.tls_quic.fingerprint_set) { |
1552 | 1.84k | memcpy(flow->ssh_tls.sha1_cert_fingerprint, |
1553 | 1.84k | flow->ndpi_flow->protos.tls_quic.sha1_certificate_fingerprint, 20); |
1554 | 1.84k | flow->ssh_tls.sha1_cert_fingerprint_set = 1; |
1555 | 1.84k | } |
1556 | | |
1557 | 20.6k | flow->ssh_tls.browser_heuristics = flow->ndpi_flow->protos.tls_quic.browser_heuristics; |
1558 | | |
1559 | 20.6k | 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.6k | 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.6k | flow->ssh_tls.encrypted_ch.version = flow->ndpi_flow->protos.tls_quic.encrypted_ch.version; |
1566 | | |
1567 | 20.6k | if(flow->ndpi_flow->protos.tls_quic.tls_supported_versions) { |
1568 | 5.38k | if((flow->ssh_tls.tls_supported_versions = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.tls_supported_versions)) != NULL) |
1569 | 5.38k | correct_csv_data_field(flow->ssh_tls.tls_supported_versions); |
1570 | 5.38k | } |
1571 | | |
1572 | 20.6k | 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.6k | if(flow->ndpi_flow->protos.tls_quic.negotiated_alpn) { |
1578 | 867 | if((flow->ssh_tls.negotiated_alpn = ndpi_strdup(flow->ndpi_flow->protos.tls_quic.negotiated_alpn)) != NULL) |
1579 | 867 | correct_csv_data_field(flow->ssh_tls.negotiated_alpn); |
1580 | 867 | } |
1581 | | |
1582 | 20.6k | if(flow->protocol == IPPROTO_TCP) { |
1583 | 12.7k | 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.7k | flow->ssh_tls.num_blocks = flow->ndpi_flow->l4.tcp.tls.num_tls_blocks; |
1596 | 12.7k | memcpy(flow->ssh_tls.blocks, flow->ndpi_flow->l4.tcp.tls.tls_blocks, sizeof(flow->ndpi_flow->l4.tcp.tls.tls_blocks)); |
1597 | 12.7k | } |
1598 | 20.6k | } |
1599 | | /* FASTCGI */ |
1600 | 172k | 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 | 225k | 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 | 225k | flow->multimedia_flow_types |= flow->ndpi_flow->flow_multimedia_types; |
1616 | | |
1617 | 225k | if(flow->ndpi_flow->tcp.fingerprint) { |
1618 | 57.1k | char buf[128]; |
1619 | | |
1620 | 57.1k | snprintf(buf, sizeof(buf), "%s/%s", flow->ndpi_flow->tcp.fingerprint, |
1621 | 57.1k | ndpi_print_os_hint(flow->ndpi_flow->tcp.os_hint)); |
1622 | 57.1k | flow->tcp_fingerprint = ndpi_strdup(buf); |
1623 | 57.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 | 225k | if(ndpi_stack_is_http_like(&flow->detected_protocol.protocol_stack)) { /* HTTP, HTTP_PROXY, HTTP_CONNECT */ |
1628 | 38.6k | if(flow->ndpi_flow->http.url != NULL) { |
1629 | 24.7k | ndpi_snprintf(flow->http.url, sizeof(flow->http.url), "%s", flow->ndpi_flow->http.url); |
1630 | 24.7k | } |
1631 | | |
1632 | 38.6k | flow->http.response_status_code = flow->ndpi_flow->http.response_status_code; |
1633 | 38.6k | 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 | 38.6k | ndpi_snprintf(flow->http.server, sizeof(flow->http.server), "%s", flow->ndpi_flow->http.server ? flow->ndpi_flow->http.server : ""); |
1635 | 38.6k | 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 | 38.6k | 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 | 38.6k | ndpi_snprintf(flow->http.filename, sizeof(flow->http.filename), "%s", flow->ndpi_flow->http.filename ? flow->ndpi_flow->http.filename : ""); |
1638 | 38.6k | ndpi_snprintf(flow->http.username, sizeof(flow->http.username), "%s", flow->ndpi_flow->http.username ? flow->ndpi_flow->http.username : ""); |
1639 | 38.6k | ndpi_snprintf(flow->http.password, sizeof(flow->http.password), "%s", flow->ndpi_flow->http.password ? flow->ndpi_flow->http.password : ""); |
1640 | 38.6k | } |
1641 | | |
1642 | 225k | if(ndpi_stack_contains(&flow->detected_protocol.protocol_stack, NDPI_PROTOCOL_RTP)) |
1643 | 433 | memcpy(&flow->rtp, &flow->ndpi_flow->rtp, sizeof(flow->rtp)); |
1644 | | |
1645 | 225k | ndpi_snprintf(flow->http.user_agent, |
1646 | 225k | sizeof(flow->http.user_agent), |
1647 | 225k | "%s", (flow->ndpi_flow->http.user_agent ? flow->ndpi_flow->http.user_agent : "")); |
1648 | | |
1649 | 225k | { |
1650 | 225k | ndpi_ip_addr_t ip_addr; |
1651 | 225k | struct ndpi_address_cache_item *c; |
1652 | | |
1653 | 225k | memset(&ip_addr, 0, sizeof(ip_addr)); |
1654 | | |
1655 | 225k | if(flow->ip_version == 4) |
1656 | 206k | ip_addr.ipv4 = flow->dst_ip; |
1657 | 19.0k | else |
1658 | 19.0k | memcpy(&ip_addr.ipv6, &flow->dst_ip6, sizeof(struct ndpi_in6_addr)); |
1659 | | |
1660 | 225k | c = ndpi_cache_address_find(workflow->ndpi_struct, ip_addr); |
1661 | | |
1662 | 225k | if(c) { |
1663 | 5.94k | flow->server_hostname = ndpi_strdup(c->hostname); |
1664 | 5.94k | } |
1665 | 225k | } |
1666 | | |
1667 | 225k | if (workflow->ndpi_serialization_format != ndpi_serialization_format_unknown) { |
1668 | 225k | if (ndpi_flow2json(workflow->ndpi_struct, flow->ndpi_flow, |
1669 | 225k | flow->ip_version, flow->protocol, |
1670 | 225k | flow->vlan_id, |
1671 | 225k | flow->src_ip, flow->dst_ip, |
1672 | 225k | &flow->src_ip6, &flow->dst_ip6, |
1673 | 225k | flow->src_port, flow->dst_port, |
1674 | 225k | flow->detected_protocol, |
1675 | 225k | &flow->ndpi_flow_serializer) != 0) { |
1676 | 0 | LOG(NDPI_LOG_ERROR, "flow2json failed\n"); |
1677 | 0 | return; |
1678 | 0 | } |
1679 | | |
1680 | 225k | ndpi_serialize_string_uint32(&flow->ndpi_flow_serializer, "detection_completed", flow->detection_completed); |
1681 | 225k | ndpi_serialize_string_uint32(&flow->ndpi_flow_serializer, "check_extra_packets", flow->check_extra_packets); |
1682 | | |
1683 | 225k | if(flow->ndpi_flow->monitoring) { |
1684 | 325 | serialize_monitoring_metadata(flow); |
1685 | 325 | } |
1686 | | |
1687 | 225k | if(flow->server_hostname) |
1688 | 5.94k | ndpi_serialize_string_string(&flow->ndpi_flow_serializer, "server_hostname", flow->server_hostname); |
1689 | 225k | } |
1690 | | |
1691 | 225k | if(flow->detection_completed && (!flow->check_extra_packets)) { |
1692 | 48.7k | flow->flow_payload = flow->ndpi_flow->flow_payload, flow->flow_payload_len = flow->ndpi_flow->flow_payload_len; |
1693 | 48.7k | flow->ndpi_flow->flow_payload = NULL; /* We'll free the memory */ |
1694 | | |
1695 | 48.7k | if(workflow->flow_callback != NULL) |
1696 | 0 | workflow->flow_callback(workflow, flow, workflow->flow_callback_userdata); |
1697 | | |
1698 | 48.7k | if(fingerprint_fp) |
1699 | 0 | dump_flow_fingerprint(workflow, flow); |
1700 | | |
1701 | 48.7k | ndpi_free_flow_info_half(flow); |
1702 | 48.7k | } |
1703 | 225k | } |
1704 | | |
1705 | | /* ****************************************************** */ |
1706 | | |
1707 | | /** |
1708 | | * @brief Clear entropy stats if it meets prereq. |
1709 | | */ |
1710 | | static void |
1711 | 801k | ndpi_clear_entropy_stats(struct ndpi_flow_info *flow) { |
1712 | 801k | if(enable_flow_stats) { |
1713 | 801k | if(flow->entropy->src2dst_pkt_count + flow->entropy->dst2src_pkt_count == max_num_packets_per_flow) { |
1714 | 36.1k | memcpy(flow->last_entropy, flow->entropy, sizeof(struct ndpi_entropy)); |
1715 | 36.1k | memset(flow->entropy, 0x00, sizeof(struct ndpi_entropy)); |
1716 | 36.1k | } |
1717 | 801k | } |
1718 | 801k | } |
1719 | | |
1720 | 462k | void update_tcp_flags_count(struct ndpi_flow_info* flow, struct ndpi_tcphdr* tcp, u_int8_t src_to_dst_direction){ |
1721 | 462k | if(tcp->cwr){ |
1722 | 20.6k | flow->cwr_count++; |
1723 | 20.6k | src_to_dst_direction ? flow->src2dst_cwr_count++ : flow->dst2src_cwr_count++; |
1724 | 20.6k | } |
1725 | 462k | if(tcp->ece){ |
1726 | 40.6k | flow->ece_count++; |
1727 | 40.6k | src_to_dst_direction ? flow->src2dst_ece_count++ : flow->dst2src_ece_count++; |
1728 | 40.6k | } |
1729 | 462k | if(tcp->rst){ |
1730 | 54.8k | flow->rst_count++; |
1731 | 54.8k | src_to_dst_direction ? flow->src2dst_rst_count++ : flow->dst2src_rst_count++; |
1732 | 54.8k | } |
1733 | 462k | if(tcp->ack){ |
1734 | 343k | flow->ack_count++; |
1735 | 343k | src_to_dst_direction ? flow->src2dst_ack_count++ : flow->dst2src_ack_count++; |
1736 | 343k | } |
1737 | 462k | if(tcp->fin){ |
1738 | 52.5k | flow->fin_count++; |
1739 | 52.5k | src_to_dst_direction ? flow->src2dst_fin_count++ : flow->dst2src_fin_count++; |
1740 | 52.5k | } |
1741 | 462k | if(tcp->syn){ |
1742 | 133k | flow->syn_count++; |
1743 | 133k | src_to_dst_direction ? flow->src2dst_syn_count++ : flow->dst2src_syn_count++; |
1744 | 133k | } |
1745 | 462k | if(tcp->psh){ |
1746 | 194k | flow->psh_count++; |
1747 | 194k | src_to_dst_direction ? flow->src2dst_psh_count++ : flow->dst2src_psh_count++; |
1748 | 194k | } |
1749 | 462k | if(tcp->urg){ |
1750 | 51.7k | flow->urg_count++; |
1751 | 51.7k | src_to_dst_direction ? flow->src2dst_urg_count++ : flow->dst2src_urg_count++; |
1752 | 51.7k | } |
1753 | 462k | } |
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 | 809k | struct ndpi_flow_info **flow_ext) { |
1776 | 809k | struct ndpi_flow_info *flow = NULL; |
1777 | 809k | struct ndpi_flow_struct *ndpi_flow = NULL; |
1778 | 809k | u_int8_t proto; |
1779 | 809k | struct ndpi_tcphdr *tcph = NULL; |
1780 | 809k | struct ndpi_udphdr *udph = NULL; |
1781 | 809k | u_int16_t sport, dport, payload_len = 0; |
1782 | 809k | u_int8_t *payload; |
1783 | 809k | u_int8_t src_to_dst_direction = 1; |
1784 | 809k | u_int8_t begin_or_end_tcp = 0; |
1785 | 809k | struct ndpi_proto nproto; |
1786 | | |
1787 | 809k | memset(&nproto, '\0', sizeof(nproto)); |
1788 | | |
1789 | 809k | if(workflow->prefs.ignore_vlanid) |
1790 | 0 | vlan_id = 0; |
1791 | | |
1792 | 809k | if(iph) |
1793 | 735k | flow = get_ndpi_flow_info(workflow, IPVERSION, vlan_id, |
1794 | 735k | tunnel_type, iph, NULL, |
1795 | 735k | ipsize, |
1796 | 735k | ntohs(iph->tot_len) ? (ntohs(iph->tot_len) - (iph->ihl * 4)) : ipsize - (iph->ihl * 4) /* TSO */, |
1797 | 735k | iph->ihl * 4, |
1798 | 735k | &tcph, &udph, &sport, &dport, |
1799 | 735k | &proto, |
1800 | 735k | &payload, &payload_len, &src_to_dst_direction, when); |
1801 | 73.2k | else |
1802 | 73.2k | flow = get_ndpi_flow_info6(workflow, vlan_id, |
1803 | 73.2k | tunnel_type, iph6, ipsize, |
1804 | 73.2k | &tcph, &udph, &sport, &dport, |
1805 | 73.2k | &proto, |
1806 | 73.2k | &payload, &payload_len, &src_to_dst_direction, when); |
1807 | | |
1808 | 809k | if(flow != NULL) { |
1809 | 801k | pkt_timeval tdiff; |
1810 | | |
1811 | 801k | workflow->stats.ip_packet_count++; |
1812 | 801k | workflow->stats.total_wire_bytes += rawsize + 24 /* CRC etc */, |
1813 | 801k | workflow->stats.total_ip_bytes += rawsize; |
1814 | 801k | ndpi_flow = flow->ndpi_flow; |
1815 | | |
1816 | 801k | if(tcph != NULL){ |
1817 | 462k | update_tcp_flags_count(flow, tcph, src_to_dst_direction); |
1818 | 462k | if(tcph->syn && !flow->src2dst_bytes){ |
1819 | 67.2k | flow->c_to_s_init_win = rawsize; |
1820 | 395k | }else if(tcph->syn && tcph->ack && flow->src2dst_bytes == flow->c_to_s_init_win){ |
1821 | 12.8k | flow->s_to_c_init_win = rawsize; |
1822 | 12.8k | } |
1823 | 462k | } |
1824 | | |
1825 | 801k | if((tcph != NULL) && (tcph->fin || tcph->rst || tcph->syn)) |
1826 | 175k | begin_or_end_tcp = 1; |
1827 | | |
1828 | 801k | if(flow->flow_last_pkt_time.tv_sec) { |
1829 | 529k | ndpi_timer_sub(&when, &flow->flow_last_pkt_time, &tdiff); |
1830 | | |
1831 | 529k | if(flow->iat_flow |
1832 | 529k | && (tdiff.tv_sec >= 0) /* Discard backward time */ |
1833 | 529k | ) { |
1834 | 512k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1835 | | |
1836 | 512k | if(ms > 0) |
1837 | 216k | ndpi_data_add_value(flow->iat_flow, ms); |
1838 | 512k | } |
1839 | 529k | } |
1840 | | |
1841 | 801k | memcpy(&flow->flow_last_pkt_time, &when, sizeof(when)); |
1842 | | |
1843 | 801k | if(src_to_dst_direction) { |
1844 | 627k | if(flow->src2dst_last_pkt_time.tv_sec) { |
1845 | 357k | ndpi_timer_sub(&when, &flow->src2dst_last_pkt_time, &tdiff); |
1846 | | |
1847 | 357k | if(flow->iat_c_to_s |
1848 | 357k | && (tdiff.tv_sec >= 0) /* Discard backward time */ |
1849 | 357k | ) { |
1850 | 343k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1851 | | |
1852 | 343k | ndpi_data_add_value(flow->iat_c_to_s, ms); |
1853 | 343k | } |
1854 | 357k | } |
1855 | | |
1856 | 627k | ndpi_data_add_value(flow->pktlen_c_to_s, rawsize); |
1857 | 627k | flow->src2dst_packets++, flow->src2dst_bytes += rawsize, flow->src2dst_goodput_bytes += payload_len; |
1858 | 627k | 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 | 627k | } else { |
1865 | 173k | if(flow->dst2src_last_pkt_time.tv_sec && (!begin_or_end_tcp)) { |
1866 | 113k | ndpi_timer_sub(&when, &flow->dst2src_last_pkt_time, &tdiff); |
1867 | | |
1868 | 113k | if(flow->iat_s_to_c) { |
1869 | 113k | u_int64_t ms = ndpi_timeval_to_milliseconds(tdiff); |
1870 | | |
1871 | 113k | ndpi_data_add_value(flow->iat_s_to_c, ms); |
1872 | 113k | } |
1873 | 113k | } |
1874 | 173k | ndpi_data_add_value(flow->pktlen_s_to_c, rawsize); |
1875 | 173k | flow->dst2src_packets++, flow->dst2src_bytes += rawsize, flow->dst2src_goodput_bytes += payload_len; |
1876 | 173k | flow->risk &= ~(1ULL << NDPI_UNIDIRECTIONAL_TRAFFIC); /* Clear bit */ |
1877 | 173k | 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 | 173k | } |
1884 | | |
1885 | 801k | #ifndef DIRECTION_BINS |
1886 | 801k | 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 | 624k | ndpi_inc_bin(&flow->payload_len_bin, plen2slot(payload_len), 1); |
1892 | 624k | } |
1893 | 801k | #endif |
1894 | | |
1895 | 801k | 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 | 801k | if(enable_flow_stats) { |
1901 | | /* Update BD, distribution and mean. */ |
1902 | 801k | ndpi_flow_update_byte_count(flow, payload, payload_len, src_to_dst_direction); |
1903 | 801k | ndpi_flow_update_byte_dist_mean_var(flow, payload, payload_len, src_to_dst_direction); |
1904 | | /* Update SPLT scores for first 32 packets. */ |
1905 | 801k | if((flow->entropy->src2dst_pkt_count+flow->entropy->dst2src_pkt_count) <= max_num_packets_per_flow) { |
1906 | 801k | if(flow->bidirectional) |
1907 | 339k | flow->entropy->score = ndpi_classify(flow->entropy->src2dst_pkt_len, flow->entropy->src2dst_pkt_time, |
1908 | 339k | flow->entropy->dst2src_pkt_len, flow->entropy->dst2src_pkt_time, |
1909 | 339k | flow->entropy->src2dst_start, flow->entropy->dst2src_start, |
1910 | 339k | max_num_packets_per_flow, ntohs(flow->src_port), ntohs(flow->dst_port), |
1911 | 339k | flow->src2dst_packets, flow->dst2src_packets, |
1912 | 339k | flow->entropy->src2dst_opackets, flow->entropy->dst2src_opackets, |
1913 | 339k | flow->entropy->src2dst_l4_bytes, flow->entropy->dst2src_l4_bytes, 1, |
1914 | 339k | flow->entropy->src2dst_byte_count, flow->entropy->dst2src_byte_count); |
1915 | 462k | else |
1916 | 462k | flow->entropy->score = ndpi_classify(flow->entropy->src2dst_pkt_len, flow->entropy->src2dst_pkt_time, |
1917 | 462k | NULL, NULL, flow->entropy->src2dst_start, flow->entropy->src2dst_start, |
1918 | 462k | max_num_packets_per_flow, ntohs(flow->src_port), ntohs(flow->dst_port), |
1919 | 462k | flow->src2dst_packets, 0, |
1920 | 462k | flow->entropy->src2dst_opackets, 0, |
1921 | 462k | flow->entropy->src2dst_l4_bytes, 0, 1, |
1922 | 462k | flow->entropy->src2dst_byte_count, NULL); |
1923 | 801k | } |
1924 | 801k | } |
1925 | | |
1926 | 801k | if(flow->first_seen_ms == 0) |
1927 | 225k | flow->first_seen_ms = time_ms; |
1928 | | |
1929 | 801k | flow->last_seen_ms = time_ms; |
1930 | | |
1931 | | /* Copy packets entropy if num packets count == 10 */ |
1932 | 801k | ndpi_clear_entropy_stats(flow); |
1933 | | /* Reset IAT reeference times (see https://github.com/ntop/nDPI/pull/1316) */ |
1934 | 801k | if(((flow->src2dst_packets + flow->dst2src_packets) % max_num_packets_per_flow) == 0) { |
1935 | 36.1k | memset(&flow->src2dst_last_pkt_time, '\0', sizeof(flow->src2dst_last_pkt_time)); |
1936 | 36.1k | memset(&flow->dst2src_last_pkt_time, '\0', sizeof(flow->dst2src_last_pkt_time)); |
1937 | 36.1k | memset(&flow->flow_last_pkt_time, '\0', sizeof(flow->flow_last_pkt_time)); |
1938 | 36.1k | } |
1939 | | |
1940 | 801k | if((human_readeable_string_len != 0) && (!flow->has_human_readeable_strings)) { |
1941 | 555k | u_int8_t skip = 0; |
1942 | | |
1943 | 555k | if(proto == IPPROTO_TCP && |
1944 | 321k | (is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) || |
1945 | 257k | is_ndpi_proto(flow, NDPI_PROTOCOL_SSH))) { |
1946 | 66.5k | if((flow->src2dst_packets+flow->dst2src_packets) < 10 /* MIN_NUM_ENCRYPT_SKIP_PACKETS */) |
1947 | 17.5k | skip = 1; /* Skip initial negotiation packets */ |
1948 | 66.5k | } |
1949 | | |
1950 | 555k | if((!skip) && ((flow->src2dst_packets+flow->dst2src_packets) < 100)) { |
1951 | 513k | if(ndpi_has_human_readable_string((char*)packet, header->caplen, |
1952 | 513k | human_readeable_string_len, |
1953 | 513k | flow->human_readeable_string_buffer, |
1954 | 513k | sizeof(flow->human_readeable_string_buffer)) == 1) |
1955 | 109k | flow->has_human_readeable_strings = 1; |
1956 | 513k | } |
1957 | 555k | } else { |
1958 | 245k | if(proto == IPPROTO_TCP && |
1959 | 141k | (is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) || |
1960 | 135k | is_ndpi_proto(flow, NDPI_PROTOCOL_SSH))) |
1961 | 6.42k | flow->has_human_readeable_strings = 0; |
1962 | 245k | } |
1963 | 801k | } else { // flow is NULL |
1964 | 7.75k | workflow->stats.total_discarded_bytes += header->len; |
1965 | 7.75k | return(nproto); |
1966 | 7.75k | } |
1967 | | |
1968 | 801k | if(!flow->detection_completed) { |
1969 | 595k | struct ndpi_flow_input_info input_info; |
1970 | | |
1971 | 595k | u_int enough_packets = |
1972 | 595k | ((proto == IPPROTO_UDP && (max_num_udp_dissected_pkts > 0 && flow->src2dst_packets + flow->dst2src_packets >= max_num_udp_dissected_pkts)) || |
1973 | 595k | (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 | 595k | if(proto == IPPROTO_TCP) |
1980 | 362k | workflow->stats.dpi_packet_count[0]++; |
1981 | 232k | else if(proto == IPPROTO_UDP) |
1982 | 221k | workflow->stats.dpi_packet_count[1]++; |
1983 | 10.7k | else |
1984 | 10.7k | workflow->stats.dpi_packet_count[2]++; |
1985 | 595k | flow->dpi_packets++; |
1986 | | |
1987 | 595k | 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 | 595k | input_info.in_pkt_dir = NDPI_IN_PKT_DIR_UNKNOWN; |
1990 | 595k | input_info.seen_flow_beginning = NDPI_FLOW_BEGINNING_UNKNOWN; |
1991 | 595k | malloc_size_stats = 1; |
1992 | 595k | flow->detected_protocol = ndpi_detection_process_packet(workflow->ndpi_struct, ndpi_flow, |
1993 | 595k | iph ? (uint8_t *)iph : (uint8_t *)iph6, |
1994 | 595k | ipsize, time_ms, &input_info); |
1995 | 595k | if(monitoring_enabled) |
1996 | 595k | process_ndpi_monitoring_info(flow); |
1997 | 595k | enough_packets |= ndpi_flow->fail_with_unknown; |
1998 | 595k | if(enough_packets || (flow->detected_protocol.proto.app_protocol != NDPI_PROTOCOL_UNKNOWN)) { |
1999 | 252k | if((!enough_packets) |
2000 | 249k | && ndpi_extra_dissection_possible(workflow->ndpi_struct, ndpi_flow)) |
2001 | 203k | ; /* Wait for further metadata */ |
2002 | 48.7k | else { |
2003 | | /* New protocol detected or give up */ |
2004 | 48.7k | flow->detection_completed = 1; |
2005 | | |
2006 | 48.7k | if(flow->detected_protocol.proto.app_protocol == NDPI_PROTOCOL_UNKNOWN) { |
2007 | 2.90k | u_int8_t proto_guessed; |
2008 | | |
2009 | 2.90k | flow->detected_protocol = ndpi_detection_giveup(workflow->ndpi_struct, flow->ndpi_flow, |
2010 | 2.90k | &proto_guessed); |
2011 | 2.90k | if(proto_guessed) workflow->stats.guessed_flow_protocols++; |
2012 | 2.90k | } |
2013 | | |
2014 | 48.7k | process_ndpi_collected_info(workflow, flow); |
2015 | 48.7k | } |
2016 | 252k | } |
2017 | | /* Let's try to save client-server direction */ |
2018 | 595k | flow->current_pkt_from_client_to_server = input_info.in_pkt_dir; |
2019 | | |
2020 | 595k | malloc_size_stats = 0; |
2021 | 595k | } else { |
2022 | 206k | flow->current_pkt_from_client_to_server = NDPI_IN_PKT_DIR_UNKNOWN; /* Unknown */ |
2023 | 206k | } |
2024 | | |
2025 | | #if 0 |
2026 | | if(flow->risk != 0) { |
2027 | | FILE *r = fopen("/tmp/e", "a"); |
2028 | | |
2029 | | if(r) { |
2030 | | fprintf(r, "->>> %u [%08X]\n", flow->risk, flow->risk); |
2031 | | fclose(r); |
2032 | | } |
2033 | | } |
2034 | | #endif |
2035 | | |
2036 | 801k | *flow_risk = flow->risk; |
2037 | 801k | *flow_ext = flow; |
2038 | | |
2039 | 801k | return(flow->detected_protocol); |
2040 | 809k | } |
2041 | | |
2042 | | /* ****************************************************** */ |
2043 | | |
2044 | 22.8k | int ndpi_is_datalink_supported(int datalink_type) { |
2045 | | /* Keep in sync with the similar switch in ndpi_workflow_process_packet */ |
2046 | 22.8k | switch(datalink_type) { |
2047 | 7.67k | case DLT_NULL: |
2048 | 7.68k | case DLT_PPP_SERIAL: |
2049 | 7.72k | case DLT_C_HDLC: |
2050 | 7.85k | case DLT_PPP: |
2051 | 7.85k | #ifdef DLT_IPV4 |
2052 | 9.31k | case DLT_IPV4: |
2053 | 9.31k | #endif |
2054 | 9.31k | #ifdef DLT_IPV6 |
2055 | 10.0k | case DLT_IPV6: |
2056 | 10.0k | #endif |
2057 | 21.4k | case DLT_EN10MB: |
2058 | 22.1k | case DLT_LINUX_SLL: |
2059 | 22.2k | case DLT_IEEE802_11_RADIO: |
2060 | 22.8k | case DLT_RAW: |
2061 | 22.8k | case DLT_PPI: |
2062 | 22.8k | case LINKTYPE_LINUX_SLL2: |
2063 | 22.8k | return 1; |
2064 | 36 | default: |
2065 | 36 | return 0; |
2066 | 22.8k | } |
2067 | 22.8k | } |
2068 | | |
2069 | 242k | 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){ |
2070 | 242k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr) + sizeof(struct ndpi_vxlanhdr)) { |
2071 | 6.35k | return false; |
2072 | 6.35k | } |
2073 | 235k | u_int32_t vxlan_dst_port = ntohs(4789); |
2074 | 235k | struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[ip_offset+ip_len]; |
2075 | 235k | u_int offset = ip_offset + ip_len + sizeof(struct ndpi_udphdr); |
2076 | | /** |
2077 | | * rfc-7348 |
2078 | | * VXLAN Header: This is an 8-byte field that has: |
2079 | | |
2080 | | - Flags (8 bits): where the I flag MUST be set to 1 for a valid |
2081 | | VXLAN Network ID (VNI). The other 7 bits (designated "R") are |
2082 | | reserved fields and MUST be set to zero on transmission and |
2083 | | ignored on receipt. |
2084 | | |
2085 | | - VXLAN Segment ID/VXLAN Network Identifier (VNI): this is a |
2086 | | 24-bit value used to designate the individual VXLAN overlay |
2087 | | network on which the communicating VMs are situated. VMs in |
2088 | | different VXLAN overlay networks cannot communicate with each |
2089 | | other. |
2090 | | |
2091 | | - Reserved fields (24 bits and 8 bits): MUST be set to zero on |
2092 | | transmission and ignored on receipt. |
2093 | | VXLAN Header: |
2094 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2095 | | |R|R|R|R|I|R|R|R| Reserved | |
2096 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2097 | | | VXLAN Network Identifier (VNI) | Reserved | |
2098 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
2099 | | */ |
2100 | 235k | if((udp->dest == vxlan_dst_port || udp->source == vxlan_dst_port) && |
2101 | 7.67k | (packet[offset] == 0x8) && |
2102 | 5.81k | (packet[offset + 1] == 0x0) && |
2103 | 5.59k | (packet[offset + 2] == 0x0) && |
2104 | 5.51k | (packet[offset + 3] == 0x0) && |
2105 | 5.38k | (packet[offset + 7] == 0x0)) { |
2106 | 5.24k | return true; |
2107 | 5.24k | } |
2108 | 230k | return false; |
2109 | 235k | } |
2110 | | |
2111 | 5.24k | static inline u_int ndpi_skip_vxlan(u_int16_t ip_offset, u_int16_t ip_len){ |
2112 | 5.24k | return ip_offset + ip_len + sizeof(struct ndpi_udphdr) + sizeof(struct ndpi_vxlanhdr); |
2113 | 5.24k | } |
2114 | | |
2115 | | static uint32_t ndpi_is_valid_gre_tunnel(const struct pcap_pkthdr *header, |
2116 | | const u_char *packet, const u_int16_t ip_offset, |
2117 | 3.80k | const u_int16_t ip_len) { |
2118 | 3.80k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_gre_basehdr)) |
2119 | 0 | return 0; /* Too short for GRE header*/ |
2120 | 3.80k | uint32_t offset = ip_offset + ip_len; |
2121 | 3.80k | struct ndpi_gre_basehdr *grehdr = (struct ndpi_gre_basehdr*)&packet[offset]; |
2122 | 3.80k | offset += sizeof(struct ndpi_gre_basehdr); |
2123 | | /* |
2124 | | The GRE flags are encoded in the first two octets. Bit 0 is the |
2125 | | most significant bit, bit 15 is the least significant bit. Bits |
2126 | | 13 through 15 are reserved for the Version field. Bits 9 through |
2127 | | 12 are reserved for future use and MUST be transmitted as zero. |
2128 | | */ |
2129 | 3.80k | if(NDPI_GRE_IS_FLAGS(grehdr->flags)) |
2130 | 274 | return 0; |
2131 | 3.53k | if(NDPI_GRE_IS_REC(grehdr->flags)) |
2132 | 248 | return 0; |
2133 | | /*GRE rfc 2890 that update 1701*/ |
2134 | 3.28k | if(NDPI_GRE_IS_VERSION_0(grehdr->flags)) { |
2135 | 1.24k | if(NDPI_GRE_IS_CSUM(grehdr->flags)) { |
2136 | 279 | if(header->caplen < offset + 4) |
2137 | 18 | return 0; |
2138 | | /*checksum field and offset field*/ |
2139 | 261 | offset += 4; |
2140 | 261 | } |
2141 | 1.23k | if(NDPI_GRE_IS_KEY(grehdr->flags)) { |
2142 | 279 | if(header->caplen < offset + 4) |
2143 | 18 | return 0; |
2144 | 261 | offset += 4; |
2145 | 261 | } |
2146 | 1.21k | if(NDPI_GRE_IS_SEQ(grehdr->flags)) { |
2147 | 305 | if(header->caplen < offset + 4) |
2148 | 18 | return 0; |
2149 | 287 | offset += 4; |
2150 | 287 | } |
2151 | 2.03k | } else if(NDPI_GRE_IS_VERSION_1(grehdr->flags)) { /*rfc-2637 section 4.1 enhanced gre*/ |
2152 | 1.98k | if(NDPI_GRE_IS_CSUM(grehdr->flags)) |
2153 | 13 | return 0; |
2154 | 1.96k | if(NDPI_GRE_IS_ROUTING(grehdr->flags)) |
2155 | 50 | return 0; |
2156 | 1.91k | if(!NDPI_GRE_IS_KEY(grehdr->flags)) |
2157 | 362 | return 0; |
2158 | 1.55k | if(NDPI_GRE_IS_STRICT(grehdr->flags)) |
2159 | 34 | return 0; |
2160 | 1.52k | if(grehdr->protocol != NDPI_GRE_PROTO_PPP) |
2161 | 92 | return 0; |
2162 | | /*key field*/ |
2163 | 1.43k | if(header->caplen < offset + 4) |
2164 | 34 | return 0; |
2165 | 1.39k | offset += 4; |
2166 | 1.39k | if(NDPI_GRE_IS_SEQ(grehdr->flags)) { |
2167 | 40 | if(header->caplen < offset + 4) |
2168 | 18 | return 0; |
2169 | 22 | offset += 4; |
2170 | 22 | } |
2171 | 1.37k | if(NDPI_GRE_IS_ACK(grehdr->flags)) { |
2172 | 27 | if(header->caplen < offset + 4) |
2173 | 12 | return 0; |
2174 | 15 | offset += 4; |
2175 | 15 | } |
2176 | 1.37k | } else { /*support only ver 0, 1*/ |
2177 | 54 | return 0; |
2178 | 54 | } |
2179 | 2.56k | return offset; |
2180 | 3.28k | } |
2181 | | |
2182 | | /* ****************************************************** */ |
2183 | | |
2184 | | struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow, |
2185 | | const struct pcap_pkthdr *header, |
2186 | | const u_char *packet, |
2187 | | ndpi_risk *flow_risk, |
2188 | 971k | struct ndpi_flow_info **flow) { |
2189 | | /* |
2190 | | * Declare pointers to packet headers |
2191 | | */ |
2192 | | /* --- Ethernet header --- */ |
2193 | 971k | const struct ndpi_ethhdr *ethernet; |
2194 | | /* --- LLC header --- */ |
2195 | 971k | const struct ndpi_llc_header_snap *llc; |
2196 | | |
2197 | | /* --- Cisco HDLC header --- */ |
2198 | 971k | const struct ndpi_chdlc *chdlc; |
2199 | | |
2200 | | /* --- Radio Tap header --- */ |
2201 | 971k | const struct ndpi_radiotap_header *radiotap; |
2202 | | /* --- Wifi header --- */ |
2203 | 971k | const struct ndpi_wifi_header *wifi; |
2204 | | |
2205 | | /* --- MPLS header --- */ |
2206 | 971k | union mpls { |
2207 | 971k | uint32_t u32; |
2208 | 971k | struct ndpi_mpls_header mpls; |
2209 | 971k | } mpls; |
2210 | | |
2211 | | /** --- IP header --- **/ |
2212 | 971k | struct ndpi_iphdr *iph; |
2213 | | /** --- IPv6 header --- **/ |
2214 | 971k | struct ndpi_ipv6hdr *iph6; |
2215 | | |
2216 | 971k | struct ndpi_proto nproto; |
2217 | 971k | ndpi_packet_tunnel tunnel_type = ndpi_no_tunnel; |
2218 | | |
2219 | | /* lengths and offsets */ |
2220 | 971k | u_int32_t eth_offset = 0, dlt; |
2221 | 971k | u_int16_t radio_len, header_length; |
2222 | 971k | u_int16_t fc; |
2223 | 971k | u_int16_t type = 0; |
2224 | 971k | int wifi_len = 0; |
2225 | 971k | int pyld_eth_len = 0; |
2226 | 971k | int check; |
2227 | 971k | u_int64_t time_ms; |
2228 | 971k | u_int16_t ip_offset = 0, ip_len; |
2229 | 971k | u_int16_t frag_off = 0, vlan_id = 0; |
2230 | 971k | u_int8_t proto = 0, recheck_type; |
2231 | 971k | u_int8_t ip_ver, ppp_type; |
2232 | | /*u_int32_t label;*/ |
2233 | | |
2234 | | /* counters */ |
2235 | 971k | u_int8_t vlan_packet = 0; |
2236 | | |
2237 | 971k | *flow_risk = 0 /* NDPI_NO_RISK */; |
2238 | 971k | *flow = NULL; |
2239 | | |
2240 | 971k | memset(&nproto, '\0', sizeof(nproto)); |
2241 | | |
2242 | 971k | if((addr_dump_path != NULL) && (workflow->stats.raw_packet_count == 0)) { |
2243 | | /* At the first packet flush expired cached addresses */ |
2244 | 0 | ndpi_cache_address_flush_expired(workflow->ndpi_struct, header->ts.tv_sec); |
2245 | 0 | } |
2246 | | |
2247 | | /* Increment raw packet counter */ |
2248 | 971k | workflow->stats.raw_packet_count++; |
2249 | | |
2250 | | /* setting time */ |
2251 | 971k | time_ms = ((uint64_t) header->ts.tv_sec) * TICK_RESOLUTION + header->ts.tv_usec / (1000000 / TICK_RESOLUTION); |
2252 | | |
2253 | | /* safety check */ |
2254 | 971k | if(workflow->last_time > time_ms) { |
2255 | | /* printf("\nWARNING: timestamp bug in the pcap file (ts delta: %llu, repairing)\n", ndpi_thread_info[thread_id].last_time - time); */ |
2256 | 971k | time_ms = workflow->last_time; |
2257 | 971k | } |
2258 | | /* update last time value */ |
2259 | 971k | workflow->last_time = time_ms; |
2260 | | |
2261 | | /*** check Data Link type ***/ |
2262 | 971k | int datalink_type; |
2263 | | |
2264 | | #ifdef USE_DPDK |
2265 | | datalink_type = DLT_EN10MB; |
2266 | | #else |
2267 | 971k | datalink_type = (int)pcap_datalink(workflow->pcap_handle); |
2268 | 971k | #endif |
2269 | | |
2270 | 978k | datalink_check: |
2271 | | // 20 for min iph and 8 for min UDP |
2272 | 978k | if(header->caplen < eth_offset + 28) |
2273 | 91.8k | return(nproto); /* Too short */ |
2274 | | |
2275 | | /* Keep in sync with ndpi_is_datalink_supported() */ |
2276 | 886k | switch(datalink_type) { |
2277 | 158k | case DLT_NULL: |
2278 | 158k | if(ntohl(*((u_int32_t*)&packet[eth_offset])) == 2) |
2279 | 30.9k | type = ETH_P_IP; |
2280 | 127k | else |
2281 | 127k | type = ETH_P_IPV6; |
2282 | | |
2283 | 158k | ip_offset = 4 + eth_offset; |
2284 | 158k | break; |
2285 | | |
2286 | | /* Cisco PPP in HDLC-like framing - 50 */ |
2287 | 199 | case DLT_PPP_SERIAL: |
2288 | 199 | chdlc = (struct ndpi_chdlc *) &packet[eth_offset]; |
2289 | 199 | ip_offset = eth_offset + sizeof(struct ndpi_chdlc); /* CHDLC_OFF = 4 */ |
2290 | 199 | type = ntohs(chdlc->proto_code); |
2291 | 199 | break; |
2292 | | |
2293 | | /* Cisco PPP - 9 or 104 */ |
2294 | 233 | case DLT_C_HDLC: |
2295 | 1.18k | case DLT_PPP: |
2296 | 1.18k | if(packet[0] == 0x0f || packet[0] == 0x8f) { |
2297 | 441 | chdlc = (struct ndpi_chdlc *) &packet[eth_offset]; |
2298 | 441 | ip_offset = eth_offset + sizeof(struct ndpi_chdlc); /* CHDLC_OFF = 4 */ |
2299 | 441 | type = ntohs(chdlc->proto_code); |
2300 | 739 | } else { |
2301 | 739 | ip_offset = eth_offset + 2; |
2302 | 739 | ppp_type = ntohs(*((u_int16_t*)&packet[eth_offset])); |
2303 | 739 | if(ppp_type == 0x0021) |
2304 | 276 | type = ETH_P_IP; |
2305 | 463 | else if(ppp_type == 0x0057) |
2306 | 194 | type = ETH_P_IPV6; |
2307 | 269 | else |
2308 | 269 | return(nproto); |
2309 | 739 | } |
2310 | 911 | break; |
2311 | | |
2312 | 911 | #ifdef DLT_IPV4 |
2313 | 51.2k | case DLT_IPV4: |
2314 | 51.2k | type = ETH_P_IP; |
2315 | 51.2k | ip_offset = eth_offset; |
2316 | 51.2k | break; |
2317 | 0 | #endif |
2318 | | |
2319 | 0 | #ifdef DLT_IPV6 |
2320 | 10.6k | case DLT_IPV6: |
2321 | 10.6k | type = ETH_P_IPV6; |
2322 | 10.6k | ip_offset = eth_offset; |
2323 | 10.6k | break; |
2324 | 0 | #endif |
2325 | | |
2326 | | /* IEEE 802.3 Ethernet - 1 */ |
2327 | 642k | case DLT_EN10MB: |
2328 | 642k | ethernet = (struct ndpi_ethhdr *) &packet[eth_offset]; |
2329 | 642k | ip_offset = sizeof(struct ndpi_ethhdr) + eth_offset; |
2330 | 642k | check = ntohs(ethernet->h_proto); |
2331 | | |
2332 | 642k | if(check <= 1500) |
2333 | 17.4k | pyld_eth_len = check; |
2334 | 624k | else if(check >= 1536) |
2335 | 624k | type = check; |
2336 | | |
2337 | 642k | if(pyld_eth_len != 0) { |
2338 | 16.8k | llc = (struct ndpi_llc_header_snap *)(&packet[ip_offset]); |
2339 | | /* check for LLC layer with SNAP extension */ |
2340 | 16.8k | if(llc->dsap == SNAP || llc->ssap == SNAP) { |
2341 | 244 | type = llc->snap.proto_ID; |
2342 | 244 | ip_offset += + 8; |
2343 | 244 | } |
2344 | | /* No SNAP extension - Spanning Tree pkt must be discarted */ |
2345 | 16.6k | else if(llc->dsap == BSTP || llc->ssap == BSTP) { |
2346 | 686 | goto v4_warning; |
2347 | 686 | } |
2348 | 16.8k | } |
2349 | 641k | break; |
2350 | | |
2351 | | /* Linux Cooked Capture - 113 */ |
2352 | 641k | case DLT_LINUX_SLL: |
2353 | 10.8k | type = (packet[eth_offset+14] << 8) + packet[eth_offset+15]; |
2354 | 10.8k | ip_offset = 16 + eth_offset; |
2355 | 10.8k | break; |
2356 | | |
2357 | | /* Linux Cooked Capture v2 - 276 */ |
2358 | 194 | case LINKTYPE_LINUX_SLL2: |
2359 | 194 | type = (packet[eth_offset+10] << 8) + packet[eth_offset+11]; |
2360 | 194 | ip_offset = 20 + eth_offset; |
2361 | 194 | break; |
2362 | | |
2363 | | /* Radiotap link-layer - 127 */ |
2364 | 2.51k | case DLT_IEEE802_11_RADIO: |
2365 | 2.51k | radiotap = (struct ndpi_radiotap_header *) &packet[eth_offset]; |
2366 | 2.51k | radio_len = radiotap->len; |
2367 | | |
2368 | | /* Check Bad FCS presence */ |
2369 | 2.51k | if((radiotap->flags & BAD_FCS) == BAD_FCS) { |
2370 | 208 | workflow->stats.total_discarded_bytes += header->len; |
2371 | 208 | return(nproto); |
2372 | 208 | } |
2373 | | |
2374 | 2.30k | if(header->caplen < (eth_offset + radio_len + sizeof(struct ndpi_wifi_header))) |
2375 | 446 | return(nproto); |
2376 | | |
2377 | | /* Calculate 802.11 header length (variable) */ |
2378 | 1.85k | wifi = (struct ndpi_wifi_header*)( packet + eth_offset + radio_len); |
2379 | 1.85k | fc = wifi->fc; |
2380 | | |
2381 | | /* check wifi data presence */ |
2382 | 1.85k | if(FCF_TYPE(fc) == WIFI_DATA) { |
2383 | 1.61k | if((FCF_TO_DS(fc) && FCF_FROM_DS(fc) == 0x0) || |
2384 | 996 | (FCF_TO_DS(fc) == 0x0 && FCF_FROM_DS(fc))) |
2385 | 1.02k | wifi_len = 26; /* + 4 byte fcs */ |
2386 | 1.61k | } else /* no data frames */ |
2387 | 246 | return(nproto); |
2388 | | |
2389 | | /* Check ether_type from LLC */ |
2390 | 1.61k | if(header->caplen < (eth_offset + wifi_len + radio_len + sizeof(struct ndpi_llc_header_snap))) |
2391 | 1.01k | return(nproto); |
2392 | 600 | llc = (struct ndpi_llc_header_snap*)(packet + eth_offset + wifi_len + radio_len); |
2393 | 600 | if(llc->dsap == SNAP) |
2394 | 19 | type = ntohs(llc->snap.proto_ID); |
2395 | | |
2396 | | /* Set IP header offset */ |
2397 | 600 | ip_offset = wifi_len + radio_len + sizeof(struct ndpi_llc_header_snap) + eth_offset; |
2398 | 600 | break; |
2399 | | |
2400 | 8.77k | case DLT_RAW: |
2401 | 8.77k | ip_offset = eth_offset; |
2402 | | /* Heuristic: no explicit field with next protocol */ |
2403 | 8.77k | ip_ver = (packet[ip_offset] & 0xF0) >> 4; |
2404 | 8.77k | if(ip_ver == 4) |
2405 | 6.14k | type = ETH_P_IP; |
2406 | 2.62k | else if(ip_ver == 6) |
2407 | 2.20k | type = ETH_P_IPV6; |
2408 | 424 | else |
2409 | 424 | return(nproto); |
2410 | | |
2411 | 8.35k | break; |
2412 | | |
2413 | 8.35k | case DLT_PPI: |
2414 | 277 | header_length = le16toh(*(u_int16_t *)&packet[eth_offset + 2]); |
2415 | 277 | dlt = le32toh(*(u_int32_t *)&packet[eth_offset + 4]); |
2416 | 277 | if(dlt != DLT_EN10MB) /* Handle only standard ethernet, for the time being */ |
2417 | 206 | return(nproto); |
2418 | 71 | datalink_type = DLT_EN10MB; |
2419 | 71 | eth_offset += header_length; |
2420 | 71 | goto datalink_check; |
2421 | | |
2422 | 0 | default: |
2423 | | /* |
2424 | | * We shoudn't be here, because we already checked that this datalink is supported. |
2425 | | * Should ndpi_is_datalink_supported() be updated? |
2426 | | */ |
2427 | 0 | printf("Unknown datalink %d\n", datalink_type); |
2428 | 0 | return(nproto); |
2429 | 886k | } |
2430 | | |
2431 | 890k | ether_type_check: |
2432 | 890k | recheck_type = 0; |
2433 | | |
2434 | | /* check ether type */ |
2435 | 890k | switch(type) { |
2436 | 6.76k | case ETH_P_VLAN: |
2437 | 6.76k | if(ip_offset+4 >= (int)header->caplen) |
2438 | 20 | return(nproto); |
2439 | 6.74k | vlan_id = ((packet[ip_offset] << 8) + packet[ip_offset+1]) & 0xFFF; |
2440 | 6.74k | type = (packet[ip_offset+2] << 8) + packet[ip_offset+3]; |
2441 | 6.74k | ip_offset += 4; |
2442 | 6.74k | vlan_packet = 1; |
2443 | | |
2444 | | // double tagging for 802.1Q |
2445 | 8.59k | while((type == 0x8100) && (((bpf_u_int32)ip_offset+4) < header->caplen)) { |
2446 | 1.85k | vlan_id = ((packet[ip_offset] << 8) + packet[ip_offset+1]) & 0xFFF; |
2447 | 1.85k | type = (packet[ip_offset+2] << 8) + packet[ip_offset+3]; |
2448 | 1.85k | ip_offset += 4; |
2449 | 1.85k | } |
2450 | 6.74k | recheck_type = 1; |
2451 | 6.74k | break; |
2452 | | |
2453 | 97 | case ETH_P_MPLS_UNI: |
2454 | 280 | case ETH_P_MPLS_MULTI: |
2455 | 280 | if(ip_offset+4 >= (int)header->caplen) |
2456 | 35 | return(nproto); |
2457 | 245 | mpls.u32 = *((uint32_t *) &packet[ip_offset]); |
2458 | 245 | mpls.u32 = ntohl(mpls.u32); |
2459 | 245 | workflow->stats.mpls_count++; |
2460 | 245 | type = ETH_P_IP, ip_offset += 4; |
2461 | | |
2462 | 1.73k | while(!mpls.mpls.s && (((bpf_u_int32)ip_offset) + 4 < header->caplen)) { |
2463 | 1.48k | mpls.u32 = *((uint32_t *) &packet[ip_offset]); |
2464 | 1.48k | mpls.u32 = ntohl(mpls.u32); |
2465 | 1.48k | ip_offset += 4; |
2466 | 1.48k | } |
2467 | 245 | recheck_type = 1; |
2468 | 245 | break; |
2469 | | |
2470 | 913 | case ETH_P_PPPoE: |
2471 | 913 | workflow->stats.pppoe_count++; |
2472 | 913 | type = ETH_P_IP; |
2473 | 913 | ip_offset += 8; |
2474 | 913 | recheck_type = 1; |
2475 | 913 | break; |
2476 | | |
2477 | 681k | case ETH_P_IP: |
2478 | 850k | case ETH_P_IPV6: |
2479 | | /* Good let's keep decoding */ |
2480 | 850k | break; |
2481 | | |
2482 | 31.8k | default: |
2483 | 31.8k | return(nproto); |
2484 | 890k | } |
2485 | | |
2486 | 858k | if(recheck_type) |
2487 | 7.90k | goto ether_type_check; |
2488 | | |
2489 | 850k | workflow->stats.vlan_count += vlan_packet; |
2490 | | |
2491 | 854k | iph_check: |
2492 | | /* Check and set IP header size and total packet length */ |
2493 | 854k | if(header->caplen < ip_offset + sizeof(struct ndpi_iphdr)) |
2494 | 2.19k | return(nproto); /* Too short for next IP header*/ |
2495 | | |
2496 | 852k | iph = (struct ndpi_iphdr *) &packet[ip_offset]; |
2497 | | |
2498 | | /* just work on Ethernet packets that contain IP */ |
2499 | 852k | if(type == ETH_P_IP && header->caplen >= ip_offset) { |
2500 | 682k | frag_off = ntohs(iph->frag_off); |
2501 | | |
2502 | 682k | proto = iph->protocol; |
2503 | 682k | if(header->caplen < header->len) { |
2504 | 94.3k | static u_int8_t cap_warning_used = 0; |
2505 | | |
2506 | 94.3k | if(cap_warning_used == 0) { |
2507 | 1 | if(!workflow->prefs.quiet_mode) |
2508 | 1 | LOG(NDPI_LOG_DEBUG, |
2509 | 1 | "\n\nWARNING: packet capture size is smaller than packet size, DETECTION MIGHT NOT WORK CORRECTLY\n\n"); |
2510 | 1 | cap_warning_used = 1; |
2511 | 1 | } |
2512 | 94.3k | } |
2513 | 682k | } |
2514 | | |
2515 | 852k | if(iph->version == IPVERSION) { |
2516 | 763k | ip_len = ((u_int16_t)iph->ihl * 4); |
2517 | 763k | iph6 = NULL; |
2518 | | |
2519 | 763k | if(iph->protocol == IPPROTO_IPV6 |
2520 | 762k | || iph->protocol == NDPI_IPIP_PROTOCOL_TYPE |
2521 | 763k | ) { |
2522 | 947 | ip_offset += ip_len; |
2523 | 947 | if(ip_len > 0) |
2524 | 909 | goto iph_check; |
2525 | 947 | } |
2526 | | |
2527 | 762k | if((frag_off & 0x1FFF) != 0) { |
2528 | 14.7k | static u_int8_t ipv4_frags_warning_used = 0; |
2529 | 14.7k | workflow->stats.fragmented_count++; |
2530 | | |
2531 | 14.7k | if(ipv4_frags_warning_used == 0) { |
2532 | 1 | if(!workflow->prefs.quiet_mode) |
2533 | 1 | LOG(NDPI_LOG_DEBUG, "\n\nWARNING: IPv4 fragments are not handled by this demo (nDPI supports them)\n"); |
2534 | 1 | ipv4_frags_warning_used = 1; |
2535 | 1 | } |
2536 | | |
2537 | 14.7k | workflow->stats.total_discarded_bytes += header->len; |
2538 | 14.7k | return(nproto); |
2539 | 14.7k | } |
2540 | 762k | } else if(iph->version == 6) { |
2541 | 77.8k | if(header->caplen < ip_offset + sizeof(struct ndpi_ipv6hdr)) |
2542 | 529 | return(nproto); /* Too short for IPv6 header*/ |
2543 | | |
2544 | 77.3k | iph6 = (struct ndpi_ipv6hdr *)&packet[ip_offset]; |
2545 | 77.3k | proto = iph6->ip6_hdr.ip6_un1_nxt; |
2546 | 77.3k | ip_len = ntohs(iph6->ip6_hdr.ip6_un1_plen); |
2547 | | |
2548 | 77.3k | if(header->caplen < (ip_offset + sizeof(struct ndpi_ipv6hdr) + ntohs(iph6->ip6_hdr.ip6_un1_plen))) |
2549 | 1.46k | return(nproto); /* Too short for IPv6 payload*/ |
2550 | | |
2551 | 75.8k | const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr)); |
2552 | 75.8k | u_int16_t ipsize = header->caplen - ip_offset; |
2553 | | |
2554 | 75.8k | if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &proto) != 0) { |
2555 | 1.60k | return(nproto); |
2556 | 1.60k | } |
2557 | | |
2558 | 74.2k | if(proto == IPPROTO_IPV6 |
2559 | 74.0k | || proto == NDPI_IPIP_PROTOCOL_TYPE |
2560 | 74.2k | ) { |
2561 | 798 | if(l4ptr > packet) { /* Better safe than sorry */ |
2562 | 798 | ip_offset = (l4ptr - packet); |
2563 | 798 | goto iph_check; |
2564 | 798 | } |
2565 | 798 | } |
2566 | | |
2567 | 73.4k | iph = NULL; |
2568 | 73.4k | } else { |
2569 | 11.1k | static u_int8_t ipv4_warning_used = 0; |
2570 | | |
2571 | 13.6k | v4_warning: |
2572 | 13.6k | if(ipv4_warning_used == 0) { |
2573 | 1 | if(!workflow->prefs.quiet_mode) |
2574 | 1 | LOG(NDPI_LOG_DEBUG, |
2575 | 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"); |
2576 | 1 | ipv4_warning_used = 1; |
2577 | 1 | } |
2578 | | |
2579 | 13.6k | workflow->stats.total_discarded_bytes += header->len; |
2580 | 13.6k | return(nproto); |
2581 | 11.1k | } |
2582 | | |
2583 | 821k | if(workflow->prefs.decode_tunnels && (proto == IPPROTO_UDP)) { |
2584 | 263k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr)) |
2585 | 216 | return(nproto); /* Too short for UDP header*/ |
2586 | 263k | else { |
2587 | 263k | struct ndpi_udphdr *udp = (struct ndpi_udphdr *)&packet[ip_offset+ip_len]; |
2588 | 263k | u_int16_t sport = ntohs(udp->source), dport = ntohs(udp->dest); |
2589 | | |
2590 | 263k | if(((sport == GTP_U_V1_PORT) || (dport == GTP_U_V1_PORT)) && |
2591 | 19.0k | (ip_offset + ip_len + sizeof(struct ndpi_udphdr) + 8 /* Minimum GTPv1 header len */ < header->caplen)) { |
2592 | | /* Check if it's GTPv1 */ |
2593 | 18.8k | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2594 | 18.8k | u_int8_t flags = packet[offset]; |
2595 | 18.8k | u_int8_t message_type = packet[offset+1]; |
2596 | 18.8k | u_int8_t exts_parsing_error = 0; |
2597 | | |
2598 | 18.8k | if((((flags & 0xE0) >> 5) == 1 /* GTPv1 */) && |
2599 | 10.6k | (message_type == 0xFF /* T-PDU */)) { |
2600 | | |
2601 | 10.3k | offset += 8; /* GTPv1 header len */ |
2602 | 10.3k | if(flags & 0x07) |
2603 | 8.48k | offset += 4; /* sequence_number + pdu_number + next_ext_header fields */ |
2604 | | /* Extensions parsing */ |
2605 | 10.3k | if(flags & 0x04) { |
2606 | 1.20k | unsigned int ext_length = 0; |
2607 | | |
2608 | 2.04k | while(offset < header->caplen) { |
2609 | 1.30k | ext_length = packet[offset] << 2; |
2610 | 1.30k | offset += ext_length; |
2611 | 1.30k | if(offset >= header->caplen || ext_length == 0) { |
2612 | 207 | exts_parsing_error = 1; |
2613 | 207 | break; |
2614 | 207 | } |
2615 | 1.09k | if(packet[offset - 1] == 0) |
2616 | 252 | break; |
2617 | 1.09k | } |
2618 | 1.20k | } |
2619 | | |
2620 | 10.3k | if(offset < header->caplen && !exts_parsing_error) { |
2621 | | /* Ok, valid GTP-U */ |
2622 | 2.81k | tunnel_type = ndpi_gtp_tunnel; |
2623 | 2.81k | ip_offset = offset; |
2624 | 2.81k | iph = (struct ndpi_iphdr *)&packet[ip_offset]; |
2625 | 2.81k | if(iph->version == 6) { |
2626 | 90 | iph6 = (struct ndpi_ipv6hdr *)&packet[ip_offset]; |
2627 | 90 | iph = NULL; |
2628 | 90 | if(header->caplen < ip_offset + sizeof(struct ndpi_ipv6hdr)) |
2629 | 45 | return(nproto); |
2630 | 2.72k | } else if(iph->version != IPVERSION) { |
2631 | | // printf("WARNING: not good (packet_id=%u)!\n", (unsigned int)workflow->stats.raw_packet_count); |
2632 | 1.89k | goto v4_warning; |
2633 | 1.89k | } else { |
2634 | 831 | if(header->caplen < ip_offset + sizeof(struct ndpi_iphdr)) |
2635 | 178 | return(nproto); |
2636 | 831 | } |
2637 | 2.81k | } |
2638 | 10.3k | } |
2639 | 244k | } else if((sport == TZSP_PORT) || (dport == TZSP_PORT)) { |
2640 | | /* https://en.wikipedia.org/wiki/TZSP */ |
2641 | 734 | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_udphdr) + 4) |
2642 | 41 | return(nproto); /* Too short for TZSP*/ |
2643 | | |
2644 | 693 | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2645 | 693 | u_int8_t version = packet[offset]; |
2646 | 693 | u_int8_t ts_type = packet[offset+1]; |
2647 | 693 | u_int16_t encapsulates = ntohs(*((u_int16_t*)&packet[offset+2])); |
2648 | | |
2649 | 693 | tunnel_type = ndpi_tzsp_tunnel; |
2650 | | |
2651 | 693 | if((version == 1) && (ts_type == 0) && (encapsulates == 1)) { |
2652 | 179 | u_int8_t stop = 0; |
2653 | | |
2654 | 179 | offset += 4; |
2655 | | |
2656 | 179 | while((!stop) && (offset < header->caplen)) { |
2657 | 155 | u_int8_t tag_type = packet[offset]; |
2658 | 155 | u_int8_t tag_len; |
2659 | | |
2660 | 155 | switch(tag_type) { |
2661 | 60 | case 0: /* PADDING Tag */ |
2662 | 60 | tag_len = 1; |
2663 | 60 | break; |
2664 | 1 | case 1: /* END Tag */ |
2665 | 1 | tag_len = 1, stop = 1; |
2666 | 1 | break; |
2667 | 94 | default: |
2668 | 94 | if(offset + 1 >= header->caplen) |
2669 | 18 | return(nproto); /* Invalid packet */ |
2670 | 76 | tag_len = packet[offset+1]; |
2671 | 76 | break; |
2672 | 155 | } |
2673 | | |
2674 | 137 | offset += tag_len; |
2675 | | |
2676 | 137 | if(offset >= header->caplen) |
2677 | 18 | return(nproto); /* Invalid packet */ |
2678 | 119 | else { |
2679 | 119 | eth_offset = offset; |
2680 | 119 | goto datalink_check; |
2681 | 119 | } |
2682 | 137 | } |
2683 | 179 | } |
2684 | 243k | } else if((sport == NDPI_CAPWAP_DATA_PORT) || (dport == NDPI_CAPWAP_DATA_PORT)) { |
2685 | | /* We dissect ONLY CAPWAP traffic */ |
2686 | 1.28k | u_int offset = ip_offset+ip_len+sizeof(struct ndpi_udphdr); |
2687 | | |
2688 | 1.28k | if((offset+1) < header->caplen) { |
2689 | 1.19k | uint8_t preamble = packet[offset]; |
2690 | | |
2691 | 1.19k | if((preamble & 0x0F) == 0) { /* CAPWAP header */ |
2692 | 844 | u_int16_t msg_len = (packet[offset+1] & 0xF8) >> 1; |
2693 | | |
2694 | 844 | offset += msg_len; |
2695 | | |
2696 | 844 | if((offset + 32 < header->caplen) && |
2697 | 599 | (packet[offset + 1] == 0x08)) { |
2698 | | /* IEEE 802.11 Data */ |
2699 | 114 | offset += 24; |
2700 | | /* LLC header is 8 bytes */ |
2701 | 114 | type = ntohs((u_int16_t)*((u_int16_t*)&packet[offset+6])); |
2702 | | |
2703 | 114 | ip_offset = offset + 8; |
2704 | | |
2705 | 114 | tunnel_type = ndpi_capwap_tunnel; |
2706 | 114 | goto iph_check; |
2707 | 114 | } |
2708 | 844 | } |
2709 | 1.19k | } |
2710 | 242k | }else if(ndpi_is_valid_vxlan(header, packet, ip_offset, ip_len)){ |
2711 | 5.24k | tunnel_type = ndpi_vxlan_tunnel; |
2712 | 5.24k | eth_offset = ndpi_skip_vxlan(ip_offset, ip_len); |
2713 | 5.24k | goto datalink_check; |
2714 | 5.24k | } |
2715 | 263k | } |
2716 | 557k | } else if(workflow->prefs.decode_tunnels && (proto == IPPROTO_GRE)) { |
2717 | 3.91k | if(header->caplen < ip_offset + ip_len + sizeof(struct ndpi_gre_basehdr)) |
2718 | 113 | return(nproto); /* Too short for GRE header*/ |
2719 | 3.80k | u_int32_t offset = 0; |
2720 | 3.80k | if((offset = ndpi_is_valid_gre_tunnel(header, packet, ip_offset, ip_len))) { |
2721 | 2.56k | tunnel_type = ndpi_gre_tunnel; |
2722 | 2.56k | struct ndpi_gre_basehdr *grehdr = (struct ndpi_gre_basehdr*)&packet[ip_offset + ip_len]; |
2723 | 2.56k | if(grehdr->protocol == ntohs(ETH_P_IP) || grehdr->protocol == ntohs(ETH_P_IPV6)) { |
2724 | 329 | ip_offset = offset; |
2725 | 329 | goto iph_check; |
2726 | 2.23k | } else if(grehdr->protocol == NDPI_GRE_PROTO_PPP) { // ppp protocol |
2727 | 1.36k | ip_offset = offset + NDPI_PPP_HDRLEN; |
2728 | 1.36k | goto iph_check; |
2729 | 1.36k | } else { |
2730 | 865 | eth_offset = offset; |
2731 | 865 | goto datalink_check; |
2732 | 865 | } |
2733 | 2.56k | } else { |
2734 | 1.24k | return(nproto); |
2735 | 1.24k | } |
2736 | 3.80k | } |
2737 | | |
2738 | | /* process the packet */ |
2739 | 809k | return(packet_processing(workflow, time_ms, vlan_id, tunnel_type, iph, iph6, |
2740 | 809k | header->caplen - ip_offset, |
2741 | 809k | header->caplen, header, packet, header->ts, |
2742 | 809k | flow_risk, flow)); |
2743 | 821k | } |
2744 | | |
2745 | | /* *********************************************** */ |
2746 | | |
2747 | | #ifdef USE_DPDK |
2748 | | |
2749 | | #include <rte_version.h> |
2750 | | #include <rte_ether.h> |
2751 | | |
2752 | | static const struct rte_eth_conf port_conf_default = { |
2753 | | #if(RTE_VERSION < RTE_VERSION_NUM(19, 8, 0, 0)) |
2754 | | .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } |
2755 | | #else |
2756 | | .rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN } |
2757 | | #endif |
2758 | | }; |
2759 | | |
2760 | | /* ************************************ */ |
2761 | | |
2762 | | int dpdk_port_init(int port, struct rte_mempool *mbuf_pool) { |
2763 | | struct rte_eth_conf port_conf = port_conf_default; |
2764 | | const u_int16_t rx_rings = 1, tx_rings = 1; |
2765 | | int retval; |
2766 | | u_int16_t q; |
2767 | | |
2768 | | /* 1 RX queue */ |
2769 | | retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); |
2770 | | |
2771 | | if(retval != 0) |
2772 | | return retval; |
2773 | | |
2774 | | for(q = 0; q < rx_rings; q++) { |
2775 | | retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, rte_eth_dev_socket_id(port), NULL, mbuf_pool); |
2776 | | if(retval < 0) |
2777 | | return retval; |
2778 | | } |
2779 | | |
2780 | | for(q = 0; q < tx_rings; q++) { |
2781 | | retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, rte_eth_dev_socket_id(port), NULL); |
2782 | | if(retval < 0) |
2783 | | return retval; |
2784 | | } |
2785 | | |
2786 | | retval = rte_eth_dev_start(port); |
2787 | | |
2788 | | if(retval < 0) |
2789 | | return retval; |
2790 | | |
2791 | | rte_eth_promiscuous_enable(port); |
2792 | | |
2793 | | return 0; |
2794 | | } |
2795 | | |
2796 | | int dpdk_port_deinit(int port) { |
2797 | | rte_eth_dev_stop(port); |
2798 | | rte_eth_dev_close(port); |
2799 | | return 0; |
2800 | | } |
2801 | | |
2802 | | #endif |