1 /* packet-falco-bridge.c
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
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
27 #define WS_LOG_DOMAIN "falco-bridge"
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>
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
{
69 BFF_HIDDEN
= 1 << 1, // Unused
71 BFF_CONVERSATION
= 1 << 3
72 } bridge_field_flags_e
;
74 typedef struct conv_filter_info
{
75 hf_register_info
*field_info
;
77 wmem_strbuf_t
*strbuf
;
80 typedef struct bridge_info
{
81 sinsp_source_info_t
*ssi
;
86 hf_register_info
* hf_v4
;
88 hf_register_info
* hf_v6
;
90 int* hf_id_to_addr_id
; // Maps an hf offset to an hf_v[46] offset
91 unsigned visible_fields
;
93 uint32_t* field_flags
;
95 uint32_t num_conversation_filters
;
96 conv_filter_info
*conversation_filters
;
99 typedef struct falco_conv_filter_fields
{
100 const char* container_id
;
104 const char* fd_containername
;
105 } falco_conv_filter_fields
;
107 typedef struct fd_follow_tap_info
{
111 } fd_follow_tap_info
;
113 typedef struct container_io_tap_info
{
114 const char* container_id
;
115 const char* proc_name
;
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
;
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
;
154 * sinsp extractor span
156 sinsp_span_t
*sinsp_span
;
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",
173 { "Field Lengths", "falcobridge.lens",
179 { "Plugin ID", "falcobridge.id",
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.
194 is_string_address_field(enum ftenum ftype
, const char *abbrev
) {
195 if (ftype
!= FT_STRINGZ
) {
198 if (strstr(abbrev
, ".srcip")) { // ct.srcip
200 } else if (strstr(abbrev
, ".client.ip")) { // okta.client.ip
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
) {
215 int proto_id
= proto_registrar_get_parent(cfi
->field_info
->hfinfo
.id
);
221 return proto_is_frame_protocol(pinfo
->layers
, proto_registrar_get_nth(proto_id
)->abbrev
);
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
) {
233 return ws_strdup_printf("%s eq %s", cfi
->field_info
->hfinfo
.abbrev
, cfi
->strbuf
->str
);
236 // Falco rule translation
239 stnode_op_to_string(stnode_op_t 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 "-";
253 case STNODE_OP_NOT_IN
:
260 char *hfinfo_to_filtercheck(header_field_info
*hfinfo
) {
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
];
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
);
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
);
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.
310 bool add_parens
= (op
== STNODE_OP_AND
|| op
== STNODE_OP_OR
) && op
!= parent_bool_op
&& parent_bool_op
!= STNODE_OP_UNINITIALIZED
;
312 g_string_append_c(falco_rule
, '(');
314 if (!visit_dfilter_node(left
, op
, falco_rule
)) {
317 g_string_append_printf(falco_rule
, " %s ", op_str
);
318 if (!visit_dfilter_node(right
, op
, falco_rule
)) {
322 g_string_append_c(falco_rule
, ')');
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
)) {
336 ws_assert_not_reached();
339 else if (stnode_type_id(node
) == STTYPE_SET
) {
342 else if (stnode_type_id(node
) == STTYPE_FUNCTION
) {
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
);
351 g_string_append_printf(falco_rule
, "%s", filtercheck
);
354 else if (stnode_type_id(node
) == STTYPE_FVALUE
) {
355 g_string_append_printf(falco_rule
, "%s", stnode_tostr(node
, true));
358 g_string_append_printf(falco_rule
, "%s", stnode_type_name(node
));
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
);
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;
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
);
386 * Skip the fields that are marked as hidden.
387 * XXX Should we keep them and call proto_item_set_hidden?
391 if (sfi
.is_numeric_address
|| is_string_address_field(sfi
.type
, sfi
.abbrev
)) {
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
);
429 * Skip the fields that are marked as hidden
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
;
445 case FT_RELATIVE_TIME
:
446 case FT_ABSOLUTE_TIME
:
454 // This differs from libsinsp
461 switch (sfi
.display_format
) {
465 case SFDF_HEXADECIMAL
:
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
);
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
),
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
);
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
),
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
),
541 wmem_strdup_printf(wmem_epan_scope(), "%s (IPv6)", sfi
.description
), HFILL
544 bi
->hf_v6
[addr_fld_cnt
] = finfo_v6
;
546 } else if (bi
->hf_id_to_addr_id
) {
547 bi
->hf_id_to_addr_id
[fld_cnt
] = -1;
552 proto_register_field_array(proto_falco_bridge
, bi
->hf
, 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
);
561 import_plugin(char* fname
)
564 bridge_info
* bi
= &bridges
[nbridges
- 1];
566 char *err_str
= create_sinsp_plugin_source(sinsp_span
, fname
, &(bi
->ssi
));
569 report_failure("Unable to load sinsp plugin %s: %s.", fname
, err_str
);
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
);
586 on_wireshark_exit(void)
588 // XXX This currently crashes in a sinsp thread.
589 // destroy_sinsp_span(sinsp_span);
594 extract_syscall_conversation_fields (packet_info
*pinfo
, falco_conv_filter_fields
* args
) {
595 args
->container_id
= NULL
;
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;
607 bool rc
= get_extracted_syscall_source_fields(sinsp_span
, pinfo
->fd
->num
, &sinsp_fields
, &sinsp_fields_count
, &sinp_evt_info
);
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
) {
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);
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
);
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) {
654 static bool sysdig_syscall_filter_valid(packet_info
*pinfo
, void *user_data _U_
) {
655 if (!proto_is_frame_protocol(pinfo
->layers
, "sysdig")) {
659 // This only supports the syscall source.
660 if (pinfo
->rec
->rec_header
.syscall_header
.event_type
== FALCO_PPME_PLUGINEVENT_E
) {
667 static bool sysdig_syscall_container_filter_valid(packet_info
*pinfo
, void *user_data
) {
668 if (!sysdig_syscall_filter_valid(pinfo
, user_data
)) {
672 falco_conv_filter_fields cff
;
673 if (!extract_syscall_conversation_fields(pinfo
, &cff
)) {
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
)) {
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
);
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
")",
718 return ws_strdup_printf("proc.pid==%" PRId64
" || proc.apid.1==%" PRId64
" || proc.apid.2==%" PRId64
" || proc.apid.3==%" PRId64
" || proc.apid.4==%" PRId64
,
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
);
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\"",
744 cff
.fd_containername
);
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
) {
757 return sysdig_fd_build_filter(pinfo
, NULL
);
760 static char *fd_follow_index_filter(unsigned stream _U_
, unsigned sub_stream _U_
)
765 static char *fd_follow_address_filter(address
*src_addr _U_
, address
*dst_addr _U_
, int src_port _U_
, int dst_port _U_
)
771 fd_port_to_display(wmem_allocator_t
*allocator _U_
, unsigned port _U_
)
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
;
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(),
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.
810 get_bridge_info(uint32_t source_id
)
812 if (source_id
== 0) {
816 for(size_t j
= 0; j
< nbridges
; j
++)
818 if(bridges
[j
].source_id
== source_id
)
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
);
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
);
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);
882 const char* get_str_value(sinsp_field_extract_t
*sinsp_fields
, uint32_t sf_idx
) {
884 if (sinsp_fields
[sf_idx
].res_len
< SFE_SMALL_BUF_SIZE
) {
885 res_str
= sinsp_fields
[sf_idx
].res
.small_str
;
887 if (sinsp_fields
[sf_idx
].res
.str
== NULL
) {
888 ws_debug("Field %u has NULL result string", sf_idx
);
891 res_str
= sinsp_fields
[sf_idx
].res
.str
;
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;
914 bool rc
= extract_syscall_source_fields(sinsp_span
, bi
->ssi
, pinfo
->fd
->num
, &sinsp_fields
, &sinsp_fields_count
, &sinp_evt_info
);
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
) {
948 header_field_info
* hfinfo
= &(bi
->hf
[hf_idx
].hfinfo
);
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);
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
);
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
);
989 parent_tree
= lineage_trees
[lnum
];
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
)) ) {
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
) {
1010 proto_tree_add_int(parent_tree
, bi
->hf_ids
[hf_idx
], tvb
, 0, 0, sinsp_fields
[sf_idx
].res
.i32
);
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
;
1029 proto_tree_add_uint(parent_tree
, bi
->hf_ids
[hf_idx
], tvb
, 0, 0, sinsp_fields
[sf_idx
].res
.u32
);
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
);
1038 const char* res_str
= get_str_value(sinsp_fields
, sf_idx
);
1039 if (res_str
== NULL
) {
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
);
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) {
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
;
1070 proto_tree_add_boolean(parent_tree
, bi
->hf_ids
[hf_idx
], tvb
, 0, 0, sinsp_fields
[sf_idx
].res
.boolean
);
1073 proto_tree_add_double(parent_tree
, bi
->hf_ids
[hf_idx
], tvb
, 0, 0, sinsp_fields
[sf_idx
].res
.dbl
);
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
);
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
);
1099 ws_warning("Invalid length %u for address field %u", sinsp_fields
[sf_idx
].res_len
, sf_idx
);
1101 // XXX Add conversation support.
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
);
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
);
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
) {
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
;
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
);
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;
1251 cur_conv_els
[1].type
= CE_ADDRESS
;
1252 copy_address(&cur_conv_els
[1].addr_val
, &pinfo
->net_src
);
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;
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
) {
1270 wmem_strbuf_append_printf(cur_conv_filter
->strbuf
, "%" PRIx64
, sfe
->res
.u64
);
1273 wmem_strbuf_append_printf(cur_conv_filter
->strbuf
, "%" PRIo64
, sfe
->res
.u64
);
1276 wmem_strbuf_append_printf(cur_conv_filter
->strbuf
, "%" PRId64
, sfe
->res
.u64
);
1278 cur_conv_filter
->is_present
= true;
1282 cur_conv_els
[1].type
= CE_UINT64
;
1283 cur_conv_els
[1].uint64_val
= sfe
->res
.u64
;
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);
1298 // conversation_new_full(pinfo->fd->num, pinfo->conv_elements);
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
);
1325 increase_stat_node(st
, "read", fd_name_node
, true, tap_info
->io_bytes
);
1328 return TAP_PACKET_REDRAW
;
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");
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");
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
);
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
1417 if ((dir
= ws_dir_open(spdname
, 0, NULL
)) != NULL
) {
1418 while ((ws_dir_read_name(dir
)) != NULL
) {
1424 if ((dir
= ws_dir_open(ppdname
, 0, NULL
)) != NULL
) {
1425 while ((ws_dir_read_name(dir
)) != NULL
) {
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]);
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
);
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
);
1462 * Setup protocol subtree array
1464 static int *ett
[] = {
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
,
1483 * Setup process lineage subtree array
1485 static int *ett_lin
[] = {
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
);