Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / plugins / epan / falco_bridge / packet-falco-bridge.c
blob3b9c84f7b9440d51711a9ea4b636f92ee4a7784f
1 /* packet-falco-bridge.c
3 * By Loris Degioanni
4 * Copyright (C) 2021 Sysdig, Inc.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 // To do:
14 // - Convert this to C++? It would let us get rid of the glue that is
15 // sinsp-span and make string handling a lot easier. However,
16 // epan/address.h and driver/ppm_events_public.h both define PT_NONE.
17 // - Add a configuration preference for configure_plugin?
18 // - Add a configuration preference for individual conversation filters vs ANDing them?
19 // We would need to add deregister_(|log_)conversation_filter before we implement this.
20 // - Add syscall IP address conversation support
21 // - Add prefs for
22 // - set_snaplen
23 // - set_dopfailed
24 // - set_import_users
26 #include "config.h"
27 #define WS_LOG_DOMAIN "falco-bridge"
29 #include <stddef.h>
30 #include <stdint.h>
31 #include <stdio.h>
33 #ifndef _WIN32
34 #include <unistd.h>
35 #include <dlfcn.h>
36 #endif
38 #include <wiretap/wtap.h>
40 #include <epan/conversation.h>
41 #include <epan/conversation_filter.h>
42 #include <epan/dfilter/dfilter-translator.h>
43 #include <epan/dfilter/sttype-field.h>
44 #include <epan/dfilter/sttype-op.h>
45 #include <epan/exceptions.h>
46 #include <epan/follow.h>
47 #include <epan/packet.h>
48 #include <epan/prefs.h>
49 #include <epan/proto.h>
50 #include <epan/proto_data.h>
51 #include <epan/stats_tree.h>
52 #include <epan/stat_tap_ui.h>
53 #include <epan/tap.h>
55 #include <epan/dissectors/packet-sysdig-event.h>
57 #include <wsutil/file_util.h>
58 #include <wsutil/filesystem.h>
59 #include <wsutil/inet_addr.h>
60 #include <wsutil/report_message.h>
61 #include <wsutil/strtoi.h>
63 #include "sinsp-span.h"
65 #define FALCO_PPME_PLUGINEVENT_E 322
67 typedef enum bridge_field_flags_e {
68 BFF_NONE = 0,
69 BFF_HIDDEN = 1 << 1, // Unused
70 BFF_INFO = 1 << 2,
71 BFF_CONVERSATION = 1 << 3
72 } bridge_field_flags_e;
74 typedef struct conv_filter_info {
75 hf_register_info *field_info;
76 bool is_present;
77 wmem_strbuf_t *strbuf;
78 } conv_filter_info;
80 typedef struct bridge_info {
81 sinsp_source_info_t *ssi;
82 uint32_t source_id;
83 int proto;
84 hf_register_info* hf;
85 int* hf_ids;
86 hf_register_info* hf_v4;
87 int *hf_v4_ids;
88 hf_register_info* hf_v6;
89 int *hf_v6_ids;
90 int* hf_id_to_addr_id; // Maps an hf offset to an hf_v[46] offset
91 unsigned visible_fields;
92 unsigned addr_fields;
93 uint32_t* field_flags;
94 int* field_ids;
95 uint32_t num_conversation_filters;
96 conv_filter_info *conversation_filters;
97 } bridge_info;
99 typedef struct falco_conv_filter_fields {
100 const char* container_id;
101 int64_t pid;
102 int64_t tid;
103 int64_t fd;
104 const char* fd_containername;
105 } falco_conv_filter_fields;
107 typedef struct fd_follow_tap_info {
108 const char* data;
109 int32_t datalen;
110 bool is_write;
111 } fd_follow_tap_info;
113 typedef struct container_io_tap_info {
114 const char* container_id;
115 const char* proc_name;
116 const char* fd_name;
117 int32_t io_bytes;
118 bool is_write;
119 } container_io_tap_info;
121 static int proto_falco_bridge;
122 static int proto_syscalls[NUM_SINSP_SYSCALL_CATEGORIES];
124 static int ett_falco_bridge;
125 static int ett_syscalls[NUM_SINSP_SYSCALL_CATEGORIES];
126 static int ett_lineage[N_PROC_LINEAGE_ENTRIES];
128 static int ett_sinsp_enriched;
129 static int ett_sinsp_span;
130 static int ett_address;
131 static int ett_json;
133 static int container_io_tap;
135 static bool pref_show_internal;
137 static dissector_table_t ptype_dissector_table;
138 static dissector_handle_t json_handle;
140 static int fd_follow_tap;
142 static int dissect_sinsp_enriched(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *bi_ptr, sysdig_event_param_data *event_param_data);
143 static int dissect_sinsp_plugin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *bi_ptr);
144 static bridge_info* get_bridge_info(uint32_t source_id);
145 const char* get_str_value(sinsp_field_extract_t *sinsp_fields, uint32_t sf_idx);
148 * Array of plugin bridges
150 bridge_info* bridges;
151 size_t nbridges;
154 * sinsp extractor span
156 sinsp_span_t *sinsp_span;
159 * Fields
161 static int hf_sdp_source_id_size;
162 static int hf_sdp_lengths;
163 static int hf_sdp_source_id;
165 static hf_register_info hf[] = {
166 { &hf_sdp_source_id_size,
167 { "Plugin ID size", "falcobridge.id.size",
168 FT_UINT32, BASE_DEC,
169 NULL, 0x0,
170 NULL, HFILL }
172 { &hf_sdp_lengths,
173 { "Field Lengths", "falcobridge.lens",
174 FT_UINT32, BASE_DEC,
175 NULL, 0x0,
176 NULL, HFILL }
178 { &hf_sdp_source_id,
179 { "Plugin ID", "falcobridge.id",
180 FT_UINT32, BASE_DEC,
181 NULL, 0x0,
182 NULL, HFILL }
186 static void
187 falco_bridge_cleanup(void) {
188 close_sinsp_capture(sinsp_span);
191 // Returns true if the field might contain an IPv4 or IPv6 address.
192 // XXX This should probably be a preference.
193 static bool
194 is_string_address_field(enum ftenum ftype, const char *abbrev) {
195 if (ftype != FT_STRINGZ) {
196 return false;
198 if (strstr(abbrev, ".srcip")) { // ct.srcip
199 return true;
200 } else if (strstr(abbrev, ".client.ip")) { // okta.client.ip
201 return true;
203 return false;
206 static bool
207 is_filter_valid(packet_info *pinfo, void *cfi_ptr)
209 conv_filter_info *cfi = (conv_filter_info *)cfi_ptr;
211 if (!cfi->is_present) {
212 return false;
215 int proto_id = proto_registrar_get_parent(cfi->field_info->hfinfo.id);
217 if (proto_id < 0) {
218 return false;
221 return proto_is_frame_protocol(pinfo->layers, proto_registrar_get_nth(proto_id)->abbrev);
224 static char*
225 build_conversation_filter(packet_info *pinfo _U_, void *cfi_ptr)
227 conv_filter_info *cfi = (conv_filter_info *)cfi_ptr;
229 if (!cfi->is_present) {
230 return NULL;
233 return ws_strdup_printf("%s eq %s", cfi->field_info->hfinfo.abbrev, cfi->strbuf->str);
236 // Falco rule translation
238 const char *
239 stnode_op_to_string(stnode_op_t op) {
240 switch (op) {
241 case STNODE_OP_NOT: return "!";
242 case STNODE_OP_AND: return "and";
243 case STNODE_OP_OR: return "or";
244 case STNODE_OP_ANY_EQ: return "=";
245 case STNODE_OP_ALL_NE: return "!=";
246 case STNODE_OP_GT: return ">";
247 case STNODE_OP_GE: return ">=";
248 case STNODE_OP_LT: return "<";
249 case STNODE_OP_LE: return "<=";
250 case STNODE_OP_CONTAINS: return "icontains";
251 case STNODE_OP_UNARY_MINUS: return "-";
252 case STNODE_OP_IN:
253 case STNODE_OP_NOT_IN:
254 default:
255 break;
257 return NULL;
260 char *hfinfo_to_filtercheck(header_field_info *hfinfo) {
261 if (!hfinfo) {
262 return NULL;
265 const char *filtercheck = NULL;
266 for (size_t br_idx = 0; br_idx < nbridges && !filtercheck; br_idx++) {
267 bridge_info *bridge = &bridges[br_idx];
268 unsigned hf_idx;
269 for (hf_idx = 0; hf_idx < bridge->visible_fields; hf_idx++) {
270 if (hfinfo->id == bridge->hf_ids[hf_idx]) {
271 ptrdiff_t pfx_off = 0;
272 if (g_str_has_prefix(hfinfo->abbrev, FALCO_FIELD_NAME_PREFIX)) {
273 pfx_off = strlen(FALCO_FIELD_NAME_PREFIX);
275 return g_strdup(hfinfo->abbrev + pfx_off);
278 for (hf_idx = 0; hf_idx < bridge->addr_fields; hf_idx++) {
279 if (hfinfo->id == bridge->hf_v4_ids[hf_idx] || hfinfo->id == bridge->hf_v6_ids[hf_idx]) {
280 size_t fc_len = strlen(hfinfo->abbrev) - strlen(".v?");
281 return g_strndup(hfinfo->abbrev, fc_len);
285 return NULL;
288 // Falco rule syntax is specified at
289 // https://github.com/falcosecurity/libs/blob/master/userspace/libsinsp/filter/parser.h
291 // NOLINTNEXTLINE(misc-no-recursion)
292 bool visit_dfilter_node(stnode_t *node, stnode_op_t parent_bool_op, GString *falco_rule)
294 stnode_t *left, *right;
296 if (stnode_type_id(node) == STTYPE_TEST) {
297 stnode_op_t op = STNODE_OP_UNINITIALIZED;
298 sttype_oper_get(node, &op, &left, &right);
300 const char *op_str = stnode_op_to_string(op);
301 if (!op_str) {
302 return false;
305 if (left && right) {
306 if ((op == STNODE_OP_ANY_EQ || op == STNODE_OP_ALL_NE) && stnode_type_id(right) != STTYPE_FVALUE) {
307 // XXX Not yet supported; need to add a version check.
308 return false;
310 bool add_parens = (op == STNODE_OP_AND || op == STNODE_OP_OR) && op != parent_bool_op && parent_bool_op != STNODE_OP_UNINITIALIZED;
311 if (add_parens) {
312 g_string_append_c(falco_rule, '(');
314 if (!visit_dfilter_node(left, op, falco_rule)) {
315 return false;
317 g_string_append_printf(falco_rule, " %s ", op_str);
318 if (!visit_dfilter_node(right, op, falco_rule)) {
319 return false;
321 if (add_parens) {
322 g_string_append_c(falco_rule, ')');
325 else if (left) {
326 op = op == STNODE_OP_NOT ? op : parent_bool_op;
327 if (falco_rule->len > 0) {
328 g_string_append_c(falco_rule, ' ');
330 g_string_append_printf(falco_rule, "%s ", op_str);
331 if (!visit_dfilter_node(left, op, falco_rule)) {
332 return false;
335 else if (right) {
336 ws_assert_not_reached();
339 else if (stnode_type_id(node) == STTYPE_SET) {
340 return false;
342 else if (stnode_type_id(node) == STTYPE_FUNCTION) {
343 return false;
345 else if (stnode_type_id(node) == STTYPE_FIELD) {
346 header_field_info *hfinfo = sttype_field_hfinfo(node);
347 char *filtercheck = hfinfo_to_filtercheck(hfinfo);
348 if (!filtercheck) {
349 return false;
351 g_string_append_printf(falco_rule, "%s", filtercheck);
352 g_free(filtercheck);
354 else if (stnode_type_id(node) == STTYPE_FVALUE) {
355 g_string_append_printf(falco_rule, "%s", stnode_tostr(node, true));
357 else {
358 g_string_append_printf(falco_rule, "%s", stnode_type_name(node));
361 return true;
364 bool dfilter_to_falco_rule(stnode_t *root_node, GString *falco_rule) {
365 return visit_dfilter_node(root_node, STNODE_OP_UNINITIALIZED, falco_rule);
368 static void
369 create_source_hfids(bridge_info* bi)
372 * Initialize the plugin
374 bi->source_id = get_sinsp_source_id(bi->ssi);
376 size_t tot_fields = get_sinsp_source_nfields(bi->ssi);
377 bi->visible_fields = 0;
378 bi->addr_fields = 0;
379 sinsp_field_info_t sfi;
380 bi->num_conversation_filters = 0;
382 for (size_t j = 0; j < tot_fields; j++) {
383 get_sinsp_source_field_info(bi->ssi, j, &sfi);
384 if (sfi.is_hidden) {
386 * Skip the fields that are marked as hidden.
387 * XXX Should we keep them and call proto_item_set_hidden?
389 continue;
391 if (sfi.is_numeric_address || is_string_address_field(sfi.type, sfi.abbrev)) {
392 bi->addr_fields++;
394 bi->visible_fields++;
396 if (sfi.is_conversation) {
397 bi->num_conversation_filters++;
401 if (bi->visible_fields) {
402 bi->hf = (hf_register_info*)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(hf_register_info));
403 bi->hf_ids = (int*)wmem_alloc0(wmem_epan_scope(), bi->visible_fields * sizeof(int));
404 bi->field_ids = (int*)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(int));
405 bi->field_flags = (uint32_t*)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(uint32_t));
407 if (bi->addr_fields) {
408 bi->hf_id_to_addr_id = (int *)wmem_alloc(wmem_epan_scope(), bi->visible_fields * sizeof(int));
409 bi->hf_v4 = (hf_register_info*)wmem_alloc(wmem_epan_scope(), bi->addr_fields * sizeof(hf_register_info));
410 bi->hf_v4_ids = (int*)wmem_alloc0(wmem_epan_scope(), bi->addr_fields * sizeof(int));
411 bi->hf_v6 = (hf_register_info*)wmem_alloc(wmem_epan_scope(), bi->addr_fields * sizeof(hf_register_info));
412 bi->hf_v6_ids = (int*)wmem_alloc0(wmem_epan_scope(), bi->addr_fields * sizeof(int));
415 if (bi->num_conversation_filters) {
416 bi->conversation_filters = (conv_filter_info *)wmem_alloc(wmem_epan_scope(), bi->num_conversation_filters * sizeof (conv_filter_info));
419 uint32_t fld_cnt = 0;
420 size_t conv_fld_cnt = 0;
421 uint32_t addr_fld_cnt = 0;
423 for (size_t j = 0; j < tot_fields; j++)
425 get_sinsp_source_field_info(bi->ssi, j, &sfi);
427 if (sfi.is_hidden) {
429 * Skip the fields that are marked as hidden
431 continue;
434 ws_assert(fld_cnt < bi->visible_fields);
435 bi->field_ids[fld_cnt] = (int) j;
436 bi->field_flags[fld_cnt] = BFF_NONE;
438 enum ftenum ftype = sfi.type;
439 int fdisplay = BASE_NONE;
440 switch (sfi.type) {
441 case FT_STRINGZ:
442 case FT_BOOLEAN:
443 case FT_BYTES:
444 break;
445 case FT_RELATIVE_TIME:
446 case FT_ABSOLUTE_TIME:
447 fdisplay = BASE_DEC;
448 break;
449 case FT_INT8:
450 case FT_INT16:
451 case FT_INT32:
452 case FT_INT64:
453 case FT_DOUBLE:
454 // This differs from libsinsp
455 fdisplay = BASE_DEC;
456 break;
457 case FT_UINT8:
458 case FT_UINT16:
459 case FT_UINT32:
460 case FT_UINT64:
461 switch (sfi.display_format) {
462 case SFDF_DECIMAL:
463 fdisplay = BASE_DEC;
464 break;
465 case SFDF_HEXADECIMAL:
466 fdisplay = BASE_HEX;
467 break;
468 case SFDF_OCTAL:
469 fdisplay = BASE_OCT;
470 break;
471 default:
472 THROW_FORMATTED(DissectorError, "error in Falco bridge plugin %s: format %d for field %s is not supported",
473 get_sinsp_source_name(bi->ssi), sfi.display_format, sfi.abbrev);
475 break;
476 default:
477 ftype = FT_NONE;
478 ws_warning("plugin %s: type of field %s (%d) is not supported",
479 get_sinsp_source_name(bi->ssi),
480 sfi.abbrev, sfi.type);
483 if(strlen(sfi.display) == 0) {
484 THROW_FORMATTED(DissectorError, "error in Falco bridge plugin %s: field %s is missing display name",
485 get_sinsp_source_name(bi->ssi), sfi.abbrev);
488 hf_register_info finfo = {
489 bi->hf_ids + fld_cnt,
491 wmem_strdup(wmem_epan_scope(), sfi.display), wmem_strdup(wmem_epan_scope(), sfi.abbrev),
492 ftype, fdisplay,
493 NULL, 0x0,
494 wmem_strdup(wmem_epan_scope(), sfi.description), HFILL
497 bi->hf[fld_cnt] = finfo;
499 if (sfi.is_conversation) {
500 ws_assert(conv_fld_cnt < bi->num_conversation_filters);
501 bi->field_flags[fld_cnt] |= BFF_CONVERSATION;
502 bi->conversation_filters[conv_fld_cnt].field_info = &bi->hf[fld_cnt];
503 bi->conversation_filters[conv_fld_cnt].strbuf = wmem_strbuf_new(wmem_epan_scope(), "");
505 const char *source_name = get_sinsp_source_name(bi->ssi);
506 const char *conv_filter_name = wmem_strdup_printf(wmem_epan_scope(), "%s %s", source_name, bi->hf[fld_cnt].hfinfo.name);
507 register_log_conversation_filter(source_name, conv_filter_name, is_filter_valid, build_conversation_filter, &bi->conversation_filters[conv_fld_cnt]);
508 if (conv_fld_cnt == 0) {
509 add_conversation_filter_protocol(source_name);
511 conv_fld_cnt++;
514 if (sfi.is_info) {
515 bi->field_flags[fld_cnt] |= BFF_INFO;
518 if (sfi.is_numeric_address || is_string_address_field(sfi.type, sfi.abbrev)) {
519 ws_assert(addr_fld_cnt < bi->addr_fields);
520 bi->hf_id_to_addr_id[fld_cnt] = addr_fld_cnt;
522 hf_register_info finfo_v4 = {
523 bi->hf_v4_ids + addr_fld_cnt,
525 wmem_strdup_printf(wmem_epan_scope(), "%s (IPv4)", sfi.display),
526 wmem_strdup_printf(wmem_epan_scope(), "%s.v4", sfi.abbrev),
527 FT_IPv4, BASE_NONE,
528 NULL, 0x0,
529 wmem_strdup_printf(wmem_epan_scope(), "%s (IPv4)", sfi.description), HFILL
532 bi->hf_v4[addr_fld_cnt] = finfo_v4;
534 hf_register_info finfo_v6 = {
535 bi->hf_v6_ids + addr_fld_cnt,
537 wmem_strdup_printf(wmem_epan_scope(), "%s (IPv6)", sfi.display),
538 wmem_strdup_printf(wmem_epan_scope(), "%s.v6", sfi.abbrev),
539 FT_IPv6, BASE_NONE,
540 NULL, 0x0,
541 wmem_strdup_printf(wmem_epan_scope(), "%s (IPv6)", sfi.description), HFILL
544 bi->hf_v6[addr_fld_cnt] = finfo_v6;
545 addr_fld_cnt++;
546 } else if (bi->hf_id_to_addr_id) {
547 bi->hf_id_to_addr_id[fld_cnt] = -1;
549 fld_cnt++;
552 proto_register_field_array(proto_falco_bridge, bi->hf, fld_cnt);
553 if (addr_fld_cnt) {
554 proto_register_field_array(proto_falco_bridge, bi->hf_v4, addr_fld_cnt);
555 proto_register_field_array(proto_falco_bridge, bi->hf_v6, addr_fld_cnt);
560 void
561 import_plugin(char* fname)
563 nbridges++;
564 bridge_info* bi = &bridges[nbridges - 1];
566 char *err_str = create_sinsp_plugin_source(sinsp_span, fname, &(bi->ssi));
567 if (err_str) {
568 nbridges--;
569 report_failure("Unable to load sinsp plugin %s: %s.", fname, err_str);
570 g_free(err_str);
571 return;
574 create_source_hfids(bi);
576 const char *source_name = get_sinsp_source_name(bi->ssi);
577 const char *plugin_name = g_strdup_printf("%s Falco Bridge Plugin", source_name);
578 bi->proto = proto_register_protocol(plugin_name, source_name, source_name);
580 static dissector_handle_t ct_handle;
581 ct_handle = create_dissector_handle(dissect_sinsp_plugin, bi->proto);
582 dissector_add_uint("falcobridge.id", bi->source_id, ct_handle);
585 static void
586 on_wireshark_exit(void)
588 // XXX This currently crashes in a sinsp thread.
589 // destroy_sinsp_span(sinsp_span);
590 sinsp_span = NULL;
593 static bool
594 extract_syscall_conversation_fields (packet_info *pinfo, falco_conv_filter_fields* args) {
595 args->container_id = NULL;
596 args->pid = -1;
597 args->tid = -1;
598 args->fd = -1;
599 args->fd_containername = NULL;
601 // Syscalls are always the bridge with source_id 0.
602 bridge_info* bi = get_bridge_info(0);
604 sinsp_field_extract_t *sinsp_fields = NULL;
605 uint32_t sinsp_fields_count = 0;
606 void* sinp_evt_info;
607 bool rc = get_extracted_syscall_source_fields(sinsp_span, pinfo->fd->num, &sinsp_fields, &sinsp_fields_count, &sinp_evt_info);
609 if (!rc) {
610 REPORT_DISSECTOR_BUG("cannot extract falco conversation fields for event %" PRIu32, pinfo->fd->num);
613 for (uint32_t hf_idx = 0, sf_idx = 0; hf_idx < bi->visible_fields && sf_idx < sinsp_fields_count; hf_idx++) {
614 if (sinsp_fields[sf_idx].field_idx != hf_idx) {
615 continue;
618 header_field_info* hfinfo = &(bi->hf[hf_idx].hfinfo);
620 if (strcmp(hfinfo->abbrev, "container.id") == 0) {
621 args->container_id = get_str_value(sinsp_fields, sf_idx);
622 // if (args->container_id == NULL) {
623 // REPORT_DISSECTOR_BUG("cannot extract the container ID for event %" PRIu32, pinfo->fd->num);
624 // }
627 if (strcmp(hfinfo->abbrev, "proc.pid") == 0) {
628 args->pid = sinsp_fields[sf_idx].res.u64;
631 if (strcmp(hfinfo->abbrev, "thread.tid") == 0) {
632 args->tid = sinsp_fields[sf_idx].res.u64;
635 if (strcmp(hfinfo->abbrev, "fd.num") == 0) {
636 args->fd = sinsp_fields[sf_idx].res.u64;
639 if (strcmp(hfinfo->abbrev, "fd.containername") == 0) {
640 args->fd_containername = get_str_value(sinsp_fields, sf_idx);
643 sf_idx++;
646 // args->fd=-1 means that either there's no FD (e.g. a clone syscall), or that the FD is not a valid one (e.g., failed open).
647 if (args->fd == -1) {
648 return false;
651 return true;
654 static bool sysdig_syscall_filter_valid(packet_info *pinfo, void *user_data _U_) {
655 if (!proto_is_frame_protocol(pinfo->layers, "sysdig")) {
656 return false;
659 // This only supports the syscall source.
660 if (pinfo->rec->rec_header.syscall_header.event_type == FALCO_PPME_PLUGINEVENT_E) {
661 return false;
664 return true;
667 static bool sysdig_syscall_container_filter_valid(packet_info *pinfo, void *user_data) {
668 if (!sysdig_syscall_filter_valid(pinfo, user_data)) {
669 return false;
672 falco_conv_filter_fields cff;
673 if (!extract_syscall_conversation_fields(pinfo, &cff)) {
674 return false;
677 return cff.container_id != NULL;
680 static bool sysdig_syscall_fd_filter_valid(packet_info *pinfo, void *user_data) {
681 if (!sysdig_syscall_filter_valid(pinfo, user_data)) {
682 return false;
685 falco_conv_filter_fields cff;
686 return extract_syscall_conversation_fields(pinfo, &cff);
689 static char* sysdig_container_build_filter(packet_info *pinfo, void *user_data _U_) {
690 falco_conv_filter_fields cff;
691 extract_syscall_conversation_fields(pinfo, &cff);
692 return ws_strdup_printf("container.id==\"%s\"", cff.container_id);
695 static char* sysdig_proc_build_filter(packet_info *pinfo, void *user_data _U_) {
696 falco_conv_filter_fields cff;
697 extract_syscall_conversation_fields(pinfo, &cff);
698 if (cff.container_id) {
699 return ws_strdup_printf("container.id==\"%s\" && proc.pid==%" PRId64, cff.container_id, cff.pid);
700 } else {
701 return ws_strdup_printf("proc.pid==%" PRId64, cff.pid);
705 static char* sysdig_procdescendants_build_filter(packet_info *pinfo, void *user_data _U_) {
706 falco_conv_filter_fields cff;
707 extract_syscall_conversation_fields(pinfo, &cff);
709 if (cff.container_id) {
710 return ws_strdup_printf("container.id==\"%s\" && (proc.pid==%" PRId64 " || proc.apid.1==%" PRId64 " || proc.apid.2==%" PRId64 " || proc.apid.3==%" PRId64 " || proc.apid.4==%" PRId64 ")",
711 cff.container_id,
712 cff.pid,
713 cff.pid,
714 cff.pid,
715 cff.pid,
716 cff.pid);
717 } else {
718 return ws_strdup_printf("proc.pid==%" PRId64 " || proc.apid.1==%" PRId64 " || proc.apid.2==%" PRId64 " || proc.apid.3==%" PRId64 " || proc.apid.4==%" PRId64,
719 cff.pid,
720 cff.pid,
721 cff.pid,
722 cff.pid,
723 cff.pid);
727 static char* sysdig_thread_build_filter(packet_info *pinfo, void *user_data _U_) {
728 falco_conv_filter_fields cff;
729 extract_syscall_conversation_fields(pinfo, &cff);
730 if (cff.container_id) {
731 return ws_strdup_printf("container.id==\"%s\" && thread.tid==%" PRIu64, cff.container_id, cff.tid);
732 } else {
733 return ws_strdup_printf("thread.tid==%" PRId64, cff.tid);
737 static char* sysdig_fd_build_filter(packet_info *pinfo, void *user_data _U_) {
738 falco_conv_filter_fields cff;
739 extract_syscall_conversation_fields(pinfo, &cff);
740 if (cff.container_id) {
741 return ws_strdup_printf("container.id==\"%s\" && thread.tid==%" PRId64 " && fd.containername==\"%s\"",
742 cff.container_id,
743 cff.tid,
744 cff.fd_containername);
745 } else {
746 return ws_strdup_printf("thread.tid==%" PRId64, cff.tid);
750 static char *fd_follow_conv_filter(epan_dissect_t *edt _U_, packet_info *pinfo _U_, unsigned *stream _U_, unsigned *sub_stream _U_)
752 // This only supports the syscall source.
753 if (pinfo->rec->rec_header.syscall_header.event_type == FALCO_PPME_PLUGINEVENT_E) {
754 return NULL;
757 return sysdig_fd_build_filter(pinfo, NULL);
760 static char *fd_follow_index_filter(unsigned stream _U_, unsigned sub_stream _U_)
762 return NULL;
765 static char *fd_follow_address_filter(address *src_addr _U_, address *dst_addr _U_, int src_port _U_, int dst_port _U_)
767 return NULL;
770 char *
771 fd_port_to_display(wmem_allocator_t *allocator _U_, unsigned port _U_)
773 return NULL;
776 tap_packet_status
777 fd_tap_listener(void *tapdata, packet_info *pinfo,
778 epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_)
780 follow_record_t *follow_record;
781 follow_info_t *follow_info = (follow_info_t *)tapdata;
782 fd_follow_tap_info *tap_info = (fd_follow_tap_info *)data;
783 bool is_server;
785 is_server = tap_info->is_write;
787 follow_record = g_new0(follow_record_t, 1);
788 follow_record->is_server = is_server;
789 follow_record->packet_num = pinfo->fd->num;
790 follow_record->abs_ts = pinfo->fd->abs_ts;
791 follow_record->data = g_byte_array_append(g_byte_array_new(),
792 tap_info->data,
793 tap_info->datalen);
795 follow_info->bytes_written[is_server] += follow_record->data->len;
796 follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
798 return TAP_PACKET_DONT_REDRAW;
801 uint32_t get_fd_stream_count(void)
803 // This effectively disables the "streams" dropdown, which is we don't really care about for the moment in stratoshark.
804 return 1;
809 static bridge_info*
810 get_bridge_info(uint32_t source_id)
812 if (source_id == 0) {
813 return &bridges[0];
816 for(size_t j = 0; j < nbridges; j++)
818 if(bridges[j].source_id == source_id)
820 return &bridges[j];
824 return NULL;
827 static int
828 dissect_falco_bridge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *epd_p)
830 int encoding = pinfo->rec->rec_header.syscall_header.byte_order == G_BIG_ENDIAN ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
832 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Falco Bridge");
834 // https://github.com/falcosecurity/libs/blob/9c942f27/userspace/libscap/scap.c#L1900
836 uint32_t source_id = 0;
837 if (pinfo->rec->rec_header.syscall_header.event_type == FALCO_PPME_PLUGINEVENT_E) {
838 source_id = tvb_get_uint32(tvb, 8, encoding);
841 bridge_info* bi = get_bridge_info(source_id);
843 if (bi && bi->source_id == 0) {
844 sysdig_event_param_data *event_param_data = (sysdig_event_param_data *) epd_p;
845 dissect_sinsp_enriched(tvb, pinfo, tree, bi, event_param_data);
846 } else {
847 proto_item *ti = proto_tree_add_item(tree, proto_falco_bridge, tvb, 0, 12, ENC_NA);
848 proto_tree *fb_tree = proto_item_add_subtree(ti, ett_falco_bridge);
850 proto_tree_add_item(fb_tree, hf_sdp_source_id_size, tvb, 0, 4, encoding);
851 proto_tree_add_item(fb_tree, hf_sdp_lengths, tvb, 4, 4, encoding);
852 /* Clear out stuff in the info column */
853 col_clear(pinfo->cinfo,COL_INFO);
854 col_add_fstr(pinfo->cinfo, COL_INFO, "Plugin ID: %u", source_id);
856 proto_item *idti = proto_tree_add_item(fb_tree, hf_sdp_source_id, tvb, 8, 4, encoding);
857 if (bi == NULL) {
858 proto_item_append_text(idti, " (NOT SUPPORTED)");
859 col_append_str(pinfo->cinfo, COL_INFO, " (NOT SUPPORTED)");
860 return tvb_captured_length(tvb);
863 const char *source_name = get_sinsp_source_name(bi->ssi);
864 proto_item_append_text(idti, " (%s)", source_name);
865 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", source_name);
867 tvbuff_t* plugin_tvb = tvb_new_subset_length(tvb, 12, tvb_captured_length(tvb) - 12);
868 dissect_sinsp_plugin(plugin_tvb, pinfo, fb_tree, bi);
871 return tvb_captured_length(tvb);
874 int extract_lineage_number(const char *fld_name) {
875 char *last_dot = strrchr(fld_name, '.');
876 if (last_dot != NULL) {
877 return atoi(last_dot + 1);
879 return -1;
882 const char* get_str_value(sinsp_field_extract_t *sinsp_fields, uint32_t sf_idx) {
883 const char *res_str;
884 if (sinsp_fields[sf_idx].res_len < SFE_SMALL_BUF_SIZE) {
885 res_str = sinsp_fields[sf_idx].res.small_str;
886 } else {
887 if (sinsp_fields[sf_idx].res.str == NULL) {
888 ws_debug("Field %u has NULL result string", sf_idx);
889 return NULL;
891 res_str = sinsp_fields[sf_idx].res.str;
894 return res_str;
897 static int
898 dissect_sinsp_enriched(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* bi_ptr, sysdig_event_param_data *event_param_data)
900 bridge_info* bi = (bridge_info *) bi_ptr;
902 if (!pinfo->fd->visited) {
903 if (pinfo->fd->num == 1) {
904 // Open the capture file using libsinsp, which reads the meta events
905 // at the beginning of the file. We can't call this via register_init_routine
906 // because we don't have the file path at that point.
907 open_sinsp_capture(sinsp_span, pinfo->rec->rec_header.syscall_header.pathname);
911 sinsp_field_extract_t *sinsp_fields = NULL;
912 uint32_t sinsp_fields_count = 0;
913 void* sinp_evt_info;
914 bool rc = extract_syscall_source_fields(sinsp_span, bi->ssi, pinfo->fd->num, &sinsp_fields, &sinsp_fields_count, &sinp_evt_info);
916 if (!rc) {
917 REPORT_DISSECTOR_BUG("Falco plugin %s extract error: %s", get_sinsp_source_name(bi->ssi), get_sinsp_source_last_error(bi->ssi));
920 if (sinsp_fields_count == 0) {
921 col_append_str(pinfo->cinfo, COL_INFO, " [Internal event]");
922 if (!pref_show_internal) {
923 pinfo->fd->passed_dfilter = false;
925 return tvb_captured_length(tvb);
928 proto_tree *parent_trees[NUM_SINSP_SYSCALL_CATEGORIES] = {0};
929 proto_tree *lineage_trees[N_PROC_LINEAGE_ENTRIES] = {0};
930 bool is_io_write = false;
931 const char* io_buffer = NULL;
932 uint32_t io_buffer_len = 0;
934 const char *container_id = "host";
935 const char *proc_name = NULL;
936 const char *fd_name = NULL;
938 // Conversation discoverable through conversation_filter_from_pinfo.
939 // Used for related event indicators in the packet list.
940 // Fields should match sysdig_proc_build_filter.
941 conversation_element_t *pinfo_conv_els = NULL; // thread.tid hfid + thread.tid + container.id hfid + container.id + CONVERSATION_LOG
943 for (uint32_t hf_idx = 0, sf_idx = 0; hf_idx < bi->visible_fields && sf_idx < sinsp_fields_count; hf_idx++) {
944 if (sinsp_fields[sf_idx].field_idx != hf_idx) {
945 continue;
948 header_field_info* hfinfo = &(bi->hf[hf_idx].hfinfo);
950 proto_tree *ti;
953 // XXX Should we add this back?
954 // if (sinsp_fields[sf_idx].type != hfinfo->type) {
955 // REPORT_DISSECTOR_BUG("Field %s has an unrecognized or mismatched type %u != %u",
956 // hfinfo->abbrev, sinsp_fields[sf_idx].type, hfinfo->type);
957 // }
959 sinsp_syscall_category_e parent_category = get_syscall_parent_category(bi->ssi, sinsp_fields[sf_idx].field_idx);
960 if (!parent_trees[parent_category]) {
961 int bytes_offset = 0;
962 uint32_t bytes_length = 0;
963 if (parent_category == SSC_FD) {
964 bytes_offset = event_param_data->data_bytes_offset;
965 bytes_length = event_param_data->data_bytes_length;
967 ti = proto_tree_add_item(tree, proto_syscalls[parent_category], tvb, bytes_offset, bytes_length, BASE_NONE);
968 parent_trees[parent_category] = proto_item_add_subtree(ti, ett_syscalls[parent_category]);
970 proto_tree *parent_tree = parent_trees[parent_category];
972 if (parent_category == SSC_PROCLINEAGE) {
973 int32_t lnum = extract_lineage_number(hfinfo->abbrev);
974 if (lnum == -1) {
975 ws_error("Invalid lineage field name %s", hfinfo->abbrev);
978 if (!lineage_trees[lnum]) {
979 const char* res_str = get_str_value(sinsp_fields, sf_idx);
980 if (res_str == NULL) {
981 ws_error("empty value for field %s", hfinfo->abbrev);
984 lineage_trees[lnum] = proto_tree_add_subtree_format(parent_tree, tvb, 0, 0, ett_lineage[0], NULL, "%" PRIu32 ". %s", lnum, res_str);
985 sf_idx++;
986 continue;
989 parent_tree = lineage_trees[lnum];
992 int32_t arg_num;
993 #define EVT_ARG_PFX "evt.arg."
994 if (! (g_str_has_prefix(hfinfo->abbrev, EVT_ARG_PFX) && ws_strtoi32(hfinfo->abbrev + sizeof(EVT_ARG_PFX) - 1, NULL, &arg_num)) ) {
995 arg_num = -1;
998 if (strcmp(hfinfo->abbrev, "evt.is_io_write") == 0) {
999 is_io_write = sinsp_fields[sf_idx].res.boolean;
1001 if (strcmp(hfinfo->abbrev, "evt.buffer") == 0) {
1002 io_buffer = sinsp_fields[sf_idx].res.str;
1003 io_buffer_len = sinsp_fields[sf_idx].res_len;
1006 switch (hfinfo->type) {
1007 case FT_INT8:
1008 case FT_INT16:
1009 case FT_INT32:
1010 proto_tree_add_int(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.i32);
1011 break;
1012 case FT_INT64:
1013 proto_tree_add_int64(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.i64);
1014 if (strcmp(hfinfo->abbrev, "thread.tid") == 0) {
1015 if (!pinfo_conv_els) {
1016 pinfo_conv_els = wmem_alloc0(pinfo->pool, sizeof(conversation_element_t) * 5);
1017 pinfo_conv_els[0].type = CE_INT;
1018 pinfo_conv_els[1].type = CE_INT64;
1019 pinfo_conv_els[2].type = CE_INT;
1020 pinfo_conv_els[3].type = CE_STRING;
1022 pinfo_conv_els[0].int_val = hfinfo->id;
1023 pinfo_conv_els[1].int64_val = sinsp_fields[sf_idx].res.i64;
1025 break;
1026 case FT_UINT8:
1027 case FT_UINT16:
1028 case FT_UINT32:
1029 proto_tree_add_uint(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.u32);
1030 break;
1031 case FT_UINT64:
1032 case FT_RELATIVE_TIME:
1033 case FT_ABSOLUTE_TIME:
1034 proto_tree_add_uint64(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.u64);
1035 break;
1036 case FT_STRINGZ:
1038 const char* res_str = get_str_value(sinsp_fields, sf_idx);
1039 if (res_str == NULL) {
1040 continue;
1043 if (arg_num != -1) {
1044 // When the field is an argument, we want to display things in a way that includes the argument name and value.
1045 char* argname = get_evt_arg_name(sinp_evt_info, arg_num);
1046 ti = proto_tree_add_string_format(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, res_str, "%s: %s", argname, res_str);
1047 } else {
1048 ti = proto_tree_add_string(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, res_str);
1051 if (bi->field_flags[hf_idx] & BFF_INFO) {
1052 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s", res_str);
1053 // Mark it hidden, otherwise we end up with a bunch of empty "Info" tree items.
1054 proto_item_set_hidden(ti);
1057 if (strcmp(hfinfo->abbrev, "proc.name") == 0) {
1058 proc_name = res_str;
1059 } else if (strcmp(hfinfo->abbrev, "fd.name") == 0) {
1060 fd_name = res_str;
1061 } else if (strcmp(hfinfo->abbrev, "container.id") == 0) {
1062 container_id = res_str;
1063 if (pinfo_conv_els) {
1064 pinfo_conv_els[2].int_val = hfinfo->id;
1068 break;
1069 case FT_BOOLEAN:
1070 proto_tree_add_boolean(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.boolean);
1071 break;
1072 case FT_DOUBLE:
1073 proto_tree_add_double(parent_tree, bi->hf_ids[hf_idx], tvb, 0, 0, sinsp_fields[sf_idx].res.dbl);
1074 break;
1075 case FT_BYTES:
1077 int addr_fld_idx = bi->hf_id_to_addr_id[hf_idx];
1078 if (addr_fld_idx < 0) {
1079 int bytes_offset = 0;
1080 uint32_t bytes_length = 0;
1081 if (io_buffer) { // evt.buffer
1082 bytes_offset = event_param_data->data_bytes_offset;
1083 bytes_length = event_param_data->data_bytes_length;
1085 proto_tree_add_bytes_with_length(parent_tree, bi->hf_ids[hf_idx], tvb, bytes_offset, bytes_length, sinsp_fields[sf_idx].res.str, sinsp_fields[sf_idx].res_len);
1086 } else {
1087 // XXX Need to differentiate between src and dest. Falco libs supply client vs server and local vs remote.
1088 if (sinsp_fields[sf_idx].res_len == 4) {
1089 ws_in4_addr v4_addr;
1090 memcpy(&v4_addr, sinsp_fields[sf_idx].res.bytes, 4);
1091 proto_tree_add_ipv4(parent_tree, bi->hf_v4_ids[addr_fld_idx], tvb, 0, 0, v4_addr);
1092 set_address(&pinfo->net_src, AT_IPv4, sizeof(ws_in4_addr), &v4_addr);
1093 } else if (sinsp_fields[sf_idx].res_len == 16) {
1094 ws_in6_addr v6_addr;
1095 memcpy(&v6_addr, sinsp_fields[sf_idx].res.bytes, 16);
1096 proto_tree_add_ipv6(parent_tree, bi->hf_v6_ids[addr_fld_idx], tvb, 0, 0, &v6_addr);
1097 set_address(&pinfo->net_src, AT_IPv6, sizeof(ws_in6_addr), &v6_addr);
1098 } else {
1099 ws_warning("Invalid length %u for address field %u", sinsp_fields[sf_idx].res_len, sf_idx);
1101 // XXX Add conversation support.
1103 break;
1105 default:
1106 break;
1108 sf_idx++;
1111 if (pinfo_conv_els) {
1112 pinfo_conv_els[3].str_val = container_id;
1113 pinfo_conv_els[4].type = CE_CONVERSATION_TYPE;
1114 pinfo_conv_els[4].conversation_type_val = CONVERSATION_LOG;
1115 pinfo->conv_elements = pinfo_conv_els;
1116 find_or_create_conversation(pinfo);
1119 if (io_buffer_len > 0) {
1120 if (have_tap_listener(fd_follow_tap)) {
1121 fd_follow_tap_info *tap_info = wmem_new(pinfo->pool, fd_follow_tap_info);
1122 tap_info->data = io_buffer;
1123 tap_info->datalen = io_buffer_len;
1124 tap_info->is_write = is_io_write;
1125 tap_queue_packet(fd_follow_tap, pinfo, tap_info);
1127 if (have_tap_listener(container_io_tap) && proc_name && fd_name) {
1128 container_io_tap_info *tap_info = wmem_new(pinfo->pool, container_io_tap_info);
1129 tap_info->proc_name = proc_name;
1130 tap_info->fd_name = fd_name;
1131 tap_info->container_id = container_id;
1132 tap_info->io_bytes = io_buffer_len;
1133 tap_info->is_write = is_io_write;
1134 tap_queue_packet(container_io_tap, pinfo, tap_info);
1138 return tvb_captured_length(tvb);
1141 static int
1142 dissect_sinsp_plugin(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* bi_ptr)
1144 bridge_info* bi = (bridge_info *) bi_ptr;
1145 unsigned payload_len = tvb_captured_length(tvb);
1147 col_set_str(pinfo->cinfo, COL_PROTOCOL, "oops");
1148 /* Clear out stuff in the info column */
1149 col_clear(pinfo->cinfo, COL_INFO);
1151 proto_item *ti = tree;
1152 proto_tree* fb_tree = proto_item_add_subtree(ti, ett_sinsp_span);
1154 uint8_t* payload = (uint8_t*)tvb_get_ptr(tvb, 0, payload_len);
1156 plugin_field_extract_t *sinsp_fields = (plugin_field_extract_t*) wmem_alloc(pinfo->pool, sizeof(plugin_field_extract_t) * bi->visible_fields);
1157 for (uint32_t fld_idx = 0; fld_idx < bi->visible_fields; fld_idx++) {
1158 header_field_info* hfinfo = &(bi->hf[fld_idx].hfinfo);
1159 plugin_field_extract_t *sfe = &sinsp_fields[fld_idx];
1161 sfe->field_id = bi->field_ids[fld_idx];
1162 sfe->field_name = hfinfo->abbrev;
1163 sfe->type = hfinfo->type == FT_STRINGZ ? FT_STRINGZ : FT_UINT64;
1166 // If we have a failure, try to dissect what we can first, then bail out with an error.
1167 bool rc = extract_plugin_source_fields(bi->ssi, pinfo->num, payload, payload_len, pinfo->pool, sinsp_fields, bi->visible_fields);
1169 if (!rc) {
1170 REPORT_DISSECTOR_BUG("Falco plugin %s extract error: %s", get_sinsp_source_name(bi->ssi), get_sinsp_source_last_error(bi->ssi));
1173 for (uint32_t idx = 0; idx < bi->num_conversation_filters; idx++) {
1174 bi->conversation_filters[idx].is_present = false;
1175 wmem_strbuf_truncate(bi->conversation_filters[idx].strbuf, 0);
1178 conversation_element_t *first_conv_els = NULL; // hfid + field val + CONVERSATION_LOG
1180 for (uint32_t fld_idx = 0; fld_idx < bi->visible_fields; fld_idx++) {
1181 plugin_field_extract_t *sfe = &sinsp_fields[fld_idx];
1182 header_field_info* hfinfo = &(bi->hf[fld_idx].hfinfo);
1184 if (!sfe->is_present) {
1185 continue;
1188 conv_filter_info *cur_conv_filter = NULL;
1189 conversation_element_t *cur_conv_els = NULL;
1190 if ((bi->field_flags[fld_idx] & BFF_CONVERSATION) != 0) {
1191 for (uint32_t cf_idx = 0; cf_idx < bi->num_conversation_filters; cf_idx++) {
1192 if (&(bi->conversation_filters[cf_idx].field_info)->hfinfo == hfinfo) {
1193 cur_conv_filter = &bi->conversation_filters[cf_idx];
1194 if (!first_conv_els) {
1195 first_conv_els = wmem_alloc0(pinfo->pool, sizeof(conversation_element_t) * 3);
1196 first_conv_els[0].type = CE_INT;
1197 first_conv_els[0].int_val = hfinfo->id;
1198 cur_conv_els = first_conv_els;
1200 break;
1206 if (sfe->type == FT_STRINGZ && hfinfo->type == FT_STRINGZ) {
1207 proto_item *pi = proto_tree_add_string(fb_tree, bi->hf_ids[fld_idx], tvb, 0, payload_len, sfe->res.str);
1208 if (bi->field_flags[fld_idx] & BFF_INFO) {
1209 col_append_sep_fstr(pinfo->cinfo, COL_INFO, ", ", "%s", sfe->res.str);
1210 // Mark it hidden, otherwise we end up with a bunch of empty "Info" tree items.
1211 proto_item_set_hidden(pi);
1214 if ((strcmp(hfinfo->abbrev, "ct.response") == 0 ||
1215 strcmp(hfinfo->abbrev, "ct.request") == 0 ||
1216 strcmp(hfinfo->abbrev, "ct.additionaleventdata") == 0 ||
1217 strcmp(hfinfo->abbrev, "ct.resources") == 0 ) &&
1218 strcmp(sfe->res.str, "null") != 0) {
1219 tvbuff_t *json_tvb = tvb_new_child_real_data(tvb, sfe->res.str, (unsigned)strlen(sfe->res.str), (unsigned)strlen(sfe->res.str));
1220 add_new_data_source(pinfo, json_tvb, "JSON Object");
1221 proto_tree *json_tree = proto_item_add_subtree(pi, ett_json);
1222 char *col_info_text = wmem_strdup(pinfo->pool, col_get_text(pinfo->cinfo, COL_INFO));
1223 call_dissector(json_handle, json_tvb, pinfo, json_tree);
1225 /* Restore Protocol and Info columns */
1226 col_set_str(pinfo->cinfo, COL_INFO, col_info_text);
1228 int addr_fld_idx = bi->hf_id_to_addr_id[fld_idx];
1229 if (addr_fld_idx >= 0) {
1230 ws_in4_addr v4_addr;
1231 ws_in6_addr v6_addr;
1232 proto_tree *addr_tree;
1233 proto_item *addr_item = NULL;
1234 if (ws_inet_pton4(sfe->res.str, &v4_addr)) {
1235 addr_tree = proto_item_add_subtree(pi, ett_address);
1236 addr_item = proto_tree_add_ipv4(addr_tree, bi->hf_v4_ids[addr_fld_idx], tvb, 0, 0, v4_addr);
1237 set_address(&pinfo->net_src, AT_IPv4, sizeof(ws_in4_addr), &v4_addr);
1238 } else if (ws_inet_pton6(sfe->res.str, &v6_addr)) {
1239 addr_tree = proto_item_add_subtree(pi, ett_address);
1240 addr_item = proto_tree_add_ipv6(addr_tree, bi->hf_v6_ids[addr_fld_idx], tvb, 0, 0, &v6_addr);
1241 set_address(&pinfo->net_src, AT_IPv6, sizeof(ws_in6_addr), &v6_addr);
1243 if (addr_item) {
1244 proto_item_set_generated(addr_item);
1246 if (cur_conv_filter) {
1247 wmem_strbuf_append(cur_conv_filter->strbuf, sfe->res.str);
1248 cur_conv_filter->is_present = true;
1250 if (cur_conv_els) {
1251 cur_conv_els[1].type = CE_ADDRESS;
1252 copy_address(&cur_conv_els[1].addr_val, &pinfo->net_src);
1254 } else {
1255 if (cur_conv_filter) {
1256 wmem_strbuf_append_printf(cur_conv_filter->strbuf, "\"%s\"", sfe->res.str);
1257 cur_conv_filter->is_present = true;
1259 if (cur_conv_els) {
1260 cur_conv_els[1].type = CE_STRING;
1261 cur_conv_els[1].str_val = wmem_strdup(pinfo->pool, sfe->res.str);
1265 else if (sfe->type == FT_UINT64 && hfinfo->type == FT_UINT64) {
1266 proto_tree_add_uint64(fb_tree, bi->hf_ids[fld_idx], tvb, 0, payload_len, sfe->res.u64);
1267 if (cur_conv_filter) {
1268 switch (hfinfo->display) {
1269 case BASE_HEX:
1270 wmem_strbuf_append_printf(cur_conv_filter->strbuf, "%" PRIx64, sfe->res.u64);
1271 break;
1272 case BASE_OCT:
1273 wmem_strbuf_append_printf(cur_conv_filter->strbuf, "%" PRIo64, sfe->res.u64);
1274 break;
1275 default:
1276 wmem_strbuf_append_printf(cur_conv_filter->strbuf, "%" PRId64, sfe->res.u64);
1278 cur_conv_filter->is_present = true;
1281 if (cur_conv_els) {
1282 cur_conv_els[1].type = CE_UINT64;
1283 cur_conv_els[1].uint64_val = sfe->res.u64;
1286 else {
1287 REPORT_DISSECTOR_BUG("Field %s has an unrecognized or mismatched type %u != %u",
1288 hfinfo->abbrev, sfe->type, hfinfo->type);
1292 if (first_conv_els) {
1293 first_conv_els[2].type = CE_CONVERSATION_TYPE;
1294 first_conv_els[2].conversation_type_val = CONVERSATION_LOG;
1295 pinfo->conv_elements = first_conv_els;
1296 // conversation_t *conv = find_or_create_conversation(pinfo);
1297 // if (!conv) {
1298 // conversation_new_full(pinfo->fd->num, pinfo->conv_elements);
1299 // }
1302 return payload_len;
1305 const char *st_str_container_total_io = "Total";
1307 static void container_io_stats_tree_init(stats_tree* st _U_)
1309 stats_tree_create_node(st, st_str_container_total_io, 0, STAT_DT_INT, true);
1310 stat_node_set_flags(st, st_str_container_total_io, 0, false, ST_FLG_SORT_TOP);
1314 static tap_packet_status container_io_stats_tree_event(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* tap_info_p, tap_flags_t flags _U_)
1316 const container_io_tap_info* tap_info = (const container_io_tap_info*) tap_info_p;
1318 increase_stat_node(st, st_str_container_total_io, 0, false, tap_info->io_bytes);
1319 int container_id_node = increase_stat_node(st, tap_info->container_id, 0, true, tap_info->io_bytes);
1320 int proc_name_node = increase_stat_node(st, tap_info->proc_name, container_id_node, true, tap_info->io_bytes);
1321 int fd_name_node = increase_stat_node(st, tap_info->fd_name, proc_name_node, true, tap_info->io_bytes);
1322 if (tap_info->is_write) {
1323 increase_stat_node(st, "write", fd_name_node, true, tap_info->io_bytes);
1324 } else {
1325 increase_stat_node(st, "read", fd_name_node, true, tap_info->io_bytes);
1328 return TAP_PACKET_REDRAW;
1331 void
1332 proto_reg_handoff_falcoplugin(void)
1334 // Register statistics trees
1335 stats_tree_cfg *st_config = stats_tree_register_plugin("container_io", "container_io", "Container I/O", 0, container_io_stats_tree_event, container_io_stats_tree_init, NULL);
1336 stats_tree_set_group(st_config, REGISTER_LOG_STAT_GROUP_UNSORTED);
1337 stats_tree_set_first_column_name(st_config, "Container, process, and FD I/O");
1339 json_handle = find_dissector("json");
1342 void
1343 proto_register_falcoplugin(void)
1345 // Opening requires a file path, so we do that in dissect_sinsp_enriched.
1346 register_cleanup_routine(&falco_bridge_cleanup);
1348 proto_falco_bridge = proto_register_protocol("Falco Bridge", "Falco Bridge", "falcobridge");
1349 register_dissector("falcobridge", dissect_falco_bridge, proto_falco_bridge);
1351 // Register the syscall conversation filters.
1352 // These show up in the "Conversation Filter" and "Colorize Conversation" context menus.
1353 // The first match is also used for "Go" menu navigation.
1354 register_log_conversation_filter("falcobridge", "Thread", sysdig_syscall_filter_valid, sysdig_thread_build_filter, NULL);
1355 register_log_conversation_filter("falcobridge", "Process", sysdig_syscall_filter_valid, sysdig_proc_build_filter, NULL);
1356 register_log_conversation_filter("falcobridge", "Container", sysdig_syscall_container_filter_valid, sysdig_container_build_filter, NULL);
1357 register_log_conversation_filter("falcobridge", "Process and Descendants", sysdig_syscall_filter_valid, sysdig_procdescendants_build_filter, NULL);
1358 register_log_conversation_filter("falcobridge", "File Descriptor", sysdig_syscall_fd_filter_valid, sysdig_fd_build_filter, NULL);
1359 add_conversation_filter_protocol("falcobridge");
1361 // Register statistics taps
1362 container_io_tap = register_tap("container_io");
1364 // Register the "follow" handlers
1365 fd_follow_tap = register_tap("fd_follow");
1367 register_follow_stream(proto_falco_bridge, "fd_follow", fd_follow_conv_filter, fd_follow_index_filter, fd_follow_address_filter,
1368 fd_port_to_display, fd_tap_listener, get_fd_stream_count, NULL);
1370 // Try to have a 1:1 mapping for as many Sysdig / Falco fields as possible.
1371 // The exceptions are SSC_EVTARGS and SSC_PROCLINEAGE, which exposes the event arguments in a way that is convenient for the user.
1372 proto_syscalls[SSC_EVENT] = proto_register_protocol("Event Information", "Falco Event", "evt");
1373 proto_syscalls[SSC_EVTARGS] = proto_register_protocol("Event Arguments", "Falco Event Info", "evt.arg");
1374 proto_syscalls[SSC_PROCESS] = proto_register_protocol("Process Information", "Falco Process", "process");
1375 proto_syscalls[SSC_PROCLINEAGE] = proto_register_protocol("Process Ancestors", "Falco Process Lineage", "proc.aname");
1376 proto_syscalls[SSC_USER] = proto_register_protocol("User Information", "Falco User", "user");
1377 proto_syscalls[SSC_GROUP] = proto_register_protocol("Group Information", "Falco Group", "group");
1378 proto_syscalls[SSC_CONTAINER] = proto_register_protocol("Container Information", "Falco Container", "container");
1379 proto_syscalls[SSC_FD] = proto_register_protocol("File Descriptor Information", "Falco FD", "fd");
1380 proto_syscalls[SSC_FS] = proto_register_protocol("Filesystem Information", "Falco FS", "fs");
1381 // syslog.facility collides with the Syslog dissector, so let syslog fall through to "falco".
1382 proto_syscalls[SSC_FDLIST] = proto_register_protocol("File Descriptor List", "Falco FD List", "fdlist");
1383 proto_syscalls[SSC_OTHER] = proto_register_protocol("Unknown or Miscellaneous Falco", "Falco Misc", "falco");
1385 // Preferences
1386 module_t *falco_bridge_module = prefs_register_protocol(proto_falco_bridge, NULL);
1387 prefs_register_bool_preference(falco_bridge_module, "show_internal_events",
1388 "Show internal events",
1389 "Show internal libsinsp events in the event list.",
1390 &pref_show_internal);
1394 * Create the dissector table that we will use to route the dissection to
1395 * the appropriate Falco plugin.
1397 ptype_dissector_table = register_dissector_table("falcobridge.id",
1398 "Falco Bridge Plugin ID", proto_falco_bridge, FT_UINT32, BASE_DEC);
1401 * Load the plugins
1403 WS_DIR *dir;
1404 WS_DIRENT *file;
1405 char *filename;
1406 // XXX Falco plugins should probably be installed in a path that reflects
1407 // the Falco version or its plugin API version.
1408 char *spdname = g_build_filename(get_plugins_dir(), "falco", NULL);
1409 char *ppdname = g_build_filename(get_plugins_pers_dir(), "falco", NULL);
1412 * We scan the plugins directory twice. The first time we count how many
1413 * plugins we have, which we need to know in order to allocate the right
1414 * amount of memory. The second time we actually load and configure
1415 * each plugin.
1417 if ((dir = ws_dir_open(spdname, 0, NULL)) != NULL) {
1418 while ((ws_dir_read_name(dir)) != NULL) {
1419 nbridges++;
1421 ws_dir_close(dir);
1424 if ((dir = ws_dir_open(ppdname, 0, NULL)) != NULL) {
1425 while ((ws_dir_read_name(dir)) != NULL) {
1426 nbridges++;
1428 ws_dir_close(dir);
1431 sinsp_span = create_sinsp_span();
1433 bridges = g_new0(bridge_info, nbridges + 1);
1435 create_sinsp_syscall_source(sinsp_span, &bridges[0].ssi);
1437 create_source_hfids(&bridges[0]);
1438 nbridges = 1;
1440 if ((dir = ws_dir_open(spdname, 0, NULL)) != NULL) {
1441 while ((file = ws_dir_read_name(dir)) != NULL) {
1442 filename = g_build_filename(spdname, ws_dir_get_name(file), NULL);
1443 import_plugin(filename);
1444 g_free(filename);
1446 ws_dir_close(dir);
1449 if ((dir = ws_dir_open(ppdname, 0, NULL)) != NULL) {
1450 while ((file = ws_dir_read_name(dir)) != NULL) {
1451 filename = g_build_filename(ppdname, ws_dir_get_name(file), NULL);
1452 import_plugin(filename);
1453 g_free(filename);
1455 ws_dir_close(dir);
1458 g_free(spdname);
1459 g_free(ppdname);
1462 * Setup protocol subtree array
1464 static int *ett[] = {
1465 &ett_falco_bridge,
1466 &ett_syscalls[SSC_EVENT],
1467 &ett_syscalls[SSC_EVTARGS],
1468 &ett_syscalls[SSC_PROCESS],
1469 &ett_syscalls[SSC_PROCLINEAGE],
1470 &ett_syscalls[SSC_USER],
1471 &ett_syscalls[SSC_GROUP],
1472 &ett_syscalls[SSC_FD],
1473 &ett_syscalls[SSC_FS],
1474 &ett_syscalls[SSC_FDLIST],
1475 &ett_syscalls[SSC_OTHER],
1476 &ett_sinsp_enriched,
1477 &ett_sinsp_span,
1478 &ett_address,
1479 &ett_json,
1483 * Setup process lineage subtree array
1485 static int *ett_lin[] = {
1486 &ett_lineage[0],
1487 &ett_lineage[1],
1488 &ett_lineage[2],
1489 &ett_lineage[3],
1490 &ett_lineage[4],
1491 &ett_lineage[5],
1492 &ett_lineage[6],
1493 &ett_lineage[7],
1494 &ett_lineage[8],
1495 &ett_lineage[9],
1496 &ett_lineage[10],
1497 &ett_lineage[11],
1498 &ett_lineage[12],
1499 &ett_lineage[13],
1500 &ett_lineage[14],
1501 &ett_lineage[15],
1504 proto_register_field_array(proto_falco_bridge, hf, array_length(hf));
1505 proto_register_subtree_array(ett, array_length(ett));
1506 proto_register_subtree_array(ett_lin, array_length(ett_lin));
1508 register_dfilter_translator("Falco rule", dfilter_to_falco_rule);
1510 register_shutdown_routine(on_wireshark_exit);