diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index 7b4ab0950b..b761e193c7 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -51,6 +51,8 @@ void proto_reg_handoff_frame(void); static int proto_frame = -1; static int proto_pkt_comment = -1; +static int proto_syscall = -1; + static int hf_frame_arrival_time = -1; static int hf_frame_shift_offset = -1; static int hf_frame_arrival_time_epoch = -1; @@ -98,6 +100,7 @@ static expert_field ei_incomplete = EI_INIT; static int frame_tap = -1; static dissector_handle_t docsis_handle; +static dissector_handle_t sysdig_handle; /* Preferences */ static gboolean show_file_off = FALSE; @@ -250,6 +253,10 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* pinfo->current_proto = "Report"; break; + case REC_TYPE_SYSCALL: + pinfo->current_proto = "System Call"; + break; + default: g_assert_not_reached(); break; @@ -283,17 +290,37 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* cap_plurality = plurality(cap_len, "", "s"); frame_plurality = plurality(frame_len, "", "s"); - ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb), - "Frame %u: %u byte%s on wire", - pinfo->num, frame_len, frame_plurality); - if (generate_bits_field) - proto_item_append_text(ti, " (%u bits)", frame_len * 8); - proto_item_append_text(ti, ", %u byte%s captured", - cap_len, cap_plurality); - if (generate_bits_field) { - proto_item_append_text(ti, " (%u bits)", - cap_len * 8); + switch (pinfo->phdr->rec_type) { + case REC_TYPE_PACKET: + case REC_TYPE_FT_SPECIFIC_EVENT: + case REC_TYPE_FT_SPECIFIC_REPORT: + ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb), + "Frame %u: %u byte%s on wire", + pinfo->num, frame_len, frame_plurality); + if (generate_bits_field) + proto_item_append_text(ti, " (%u bits)", frame_len * 8); + proto_item_append_text(ti, ", %u byte%s captured", + cap_len, cap_plurality); + if (generate_bits_field) { + proto_item_append_text(ti, " (%u bits)", + cap_len * 8); + } + break; + + case REC_TYPE_SYSCALL: + /* + * This gives us a top-of-tree "syscall" protocol + * with "frame" fields underneath. Should we create + * corresponding syscall.time, .time_epoch, etc + * fields and use them instead or would frame.* + * be preferred? + */ + ti = proto_tree_add_protocol_format(tree, proto_syscall, tvb, 0, tvb_captured_length(tvb), + "System Call %u: %u byte%s", + pinfo->num, frame_len, frame_plurality); + break; } + if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) { proto_item_append_text(ti, " on interface %u", pinfo->phdr->interface_id); @@ -501,6 +528,15 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* } } break; + + case REC_TYPE_SYSCALL: + /* Sysdig is the only type we currently handle. */ + if (sysdig_handle) { + call_dissector_with_data(sysdig_handle, + tvb, pinfo, parent_tree, + (void *)pinfo->pseudo_header); + } + break; } #ifdef _MSC_VER } __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) { @@ -867,6 +903,8 @@ proto_register_frame(void) proto_frame = proto_register_protocol("Frame", "Frame", "frame"); proto_pkt_comment = proto_register_protocol("Packet comments", "Pkt_Comment", "pkt_comment"); + proto_syscall = proto_register_protocol("System Call", "Syscall", "syscall"); + proto_register_field_array(proto_frame, hf, array_length(hf)); proto_register_field_array(proto_frame, &hf_encap, 1); proto_register_subtree_array(ett, array_length(ett)); @@ -914,6 +952,7 @@ void proto_reg_handoff_frame(void) { docsis_handle = find_dissector_add_dependency("docsis", proto_frame); + sysdig_handle = find_dissector_add_dependency("sysdig", proto_frame); } /* diff --git a/epan/dissectors/packet-sysdig-event.c b/epan/dissectors/packet-sysdig-event.c index 15536903df..90ea1a2b34 100644 --- a/epan/dissectors/packet-sysdig-event.c +++ b/epan/dissectors/packet-sysdig-event.c @@ -2176,6 +2176,8 @@ proto_register_sysdig_event(void) /* Required function calls to register the header fields and subtrees */ proto_register_field_array(proto_sysdig_event, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + + register_dissector("sysdig", dissect_sysdig_event, proto_sysdig_event); } #define BLOCK_TYPE_SYSDIG_EVENT 0x00000204 diff --git a/epan/packet.c b/epan/packet.c index 8deef8fdef..a3b024747b 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -474,6 +474,10 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, record_type = "Report"; break; + case REC_TYPE_SYSCALL: + record_type = "System Call"; + break; + default: /* * XXX - if we add record types that shouldn't be diff --git a/wiretap/merge.c b/wiretap/merge.c index c0c26e2852..eced520ac7 100644 --- a/wiretap/merge.c +++ b/wiretap/merge.c @@ -699,11 +699,14 @@ map_phdr_interface_id(struct wtap_pkthdr *phdr, const merge_in_file_t *in_file) if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) { current_interface_id = phdr->interface_id; + } else { + return TRUE; } if (current_interface_id >= in_file->idb_index_map->len) { /* this shouldn't happen, but in a malformed input file it could */ - merge_debug("merge::map_phdr_interface_id: current_interface_id >= in_file->idb_index_map->len (ERROR?)"); + merge_debug("merge::map_phdr_interface_id: current_interface_id (%u) >= in_file->idb_index_map->len (%u) (ERROR?)", + current_interface_id, in_file->idb_index_map->len); return FALSE; } diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 4f2d90428e..305a252d46 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -146,7 +146,8 @@ typedef struct pcapng_name_resolution_block_s { /* * Minimum Sysdig size = minimum block size + packed size of sysdig_event_phdr. */ -#define MIN_SYSDIG_EVENT_SIZE ((guint32)(MIN_BLOCK_SIZE)) + ((16 + 64 + 64 + 32 + 16) / 8) +#define SYSDIG_EVENT_HEADER_SIZE ((16 + 64 + 64 + 32 + 16)/8) /* CPU ID + TS + TID + Event len + Event type */ +#define MIN_SYSDIG_EVENT_SIZE ((guint32)(MIN_BLOCK_SIZE + SYSDIG_EVENT_HEADER_SIZE)) /* pcapng: common option header file encoding for every option type */ typedef struct pcapng_option_header_s { @@ -2144,7 +2145,7 @@ pcapng_read_sysdig_event_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *p pcapng_debug("pcapng_read_sysdig_event_block: block_total_length %u", bh->block_total_length); - wblock->packet_header->rec_type = REC_TYPE_FT_SPECIFIC_EVENT; + wblock->packet_header->rec_type = REC_TYPE_SYSCALL; wblock->packet_header->pseudo_header.sysdig_event.record_type = BLOCK_TYPE_SYSDIG_EVENT; wblock->packet_header->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN /*|WTAP_HAS_INTERFACE_ID */; wblock->packet_header->pkt_tsprec = WTAP_TSPREC_NSEC; @@ -2175,6 +2176,7 @@ pcapng_read_sysdig_event_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *p block_read -= MIN_SYSDIG_EVENT_SIZE; wblock->packet_header->pseudo_header.sysdig_event.byte_order = G_BYTE_ORDER; + /* XXX Use Gxxx_FROM_LE macros instead? */ if (pn->byte_swapped) { wblock->packet_header->pseudo_header.sysdig_event.byte_order = G_BYTE_ORDER == G_LITTLE_ENDIAN ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; @@ -2202,6 +2204,8 @@ pcapng_read_sysdig_event_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *p block_read, err, err_info)) return FALSE; + /* XXX Read comment? */ + return TRUE; } @@ -3097,6 +3101,118 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, return TRUE; } +static gboolean +pcapng_write_sysdig_event_block(wtap_dumper *wdh, + const struct wtap_pkthdr *phdr, + const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err) +{ + pcapng_block_header_t bh; + const guint32 zero_pad = 0; + guint32 pad_len; + guint32 phdr_len; +#if 0 + gboolean have_options = FALSE; + struct option option_hdr; + guint32 comment_len = 0, comment_pad_len = 0; +#endif + guint32 options_total_length = 0; + guint16 cpu_id; + guint64 hdr_ts; + guint64 ts; + guint64 thread_id; + guint32 event_len; + guint16 event_type; + + /* Don't write anything we're not willing to read. */ + if (phdr->caplen > WTAP_MAX_PACKET_SIZE) { + *err = WTAP_ERR_PACKET_TOO_LARGE; + return FALSE; + } + + phdr_len = (guint32)pcap_get_phdr_size(phdr->pkt_encap, pseudo_header); + if ((phdr_len + phdr->caplen) % 4) { + pad_len = 4 - ((phdr_len + phdr->caplen) % 4); + } else { + pad_len = 0; + } + +#if 0 + /* Check if we should write comment option */ + if (phdr->opt_comment) { + have_options = TRUE; + comment_len = (guint32)strlen(phdr->opt_comment) & 0xffff; + if ((comment_len % 4)) { + comment_pad_len = 4 - (comment_len % 4); + } else { + comment_pad_len = 0; + } + options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ; + } + if (have_options) { + /* End-of options tag */ + options_total_length += 4; + } +#endif + + /* write sysdig event block header */ + bh.block_type = BLOCK_TYPE_SYSDIG_EVENT; + bh.block_total_length = (guint32)sizeof(bh) + SYSDIG_EVENT_HEADER_SIZE + phdr_len + phdr->caplen + pad_len + options_total_length + 4; + + if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh; + + /* Sysdig is always LE? */ + cpu_id = GUINT16_TO_LE(pseudo_header->sysdig_event.cpu_id); + hdr_ts = (((guint64)phdr->ts.secs) * 1000000000) + phdr->ts.nsecs; + ts = GUINT64_TO_LE(hdr_ts); + thread_id = GUINT64_TO_LE(pseudo_header->sysdig_event.thread_id); + event_len = GUINT32_TO_LE(pseudo_header->sysdig_event.event_len); + event_type = GUINT16_TO_LE(pseudo_header->sysdig_event.event_type); + + if (!wtap_dump_file_write(wdh, &cpu_id, sizeof cpu_id, err)) + return FALSE; + wdh->bytes_dumped += sizeof cpu_id; + + if (!wtap_dump_file_write(wdh, &ts, sizeof ts, err)) + return FALSE; + wdh->bytes_dumped += sizeof ts; + + if (!wtap_dump_file_write(wdh, &thread_id, sizeof thread_id, err)) + return FALSE; + wdh->bytes_dumped += sizeof thread_id; + + if (!wtap_dump_file_write(wdh, &event_len, sizeof event_len, err)) + return FALSE; + wdh->bytes_dumped += sizeof event_len; + + if (!wtap_dump_file_write(wdh, &event_type, sizeof event_type, err)) + return FALSE; + wdh->bytes_dumped += sizeof event_type; + + /* write event data */ + if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) + return FALSE; + wdh->bytes_dumped += phdr->caplen; + + /* write padding (if any) */ + if (pad_len != 0) { + if (!wtap_dump_file_write(wdh, &zero_pad, pad_len, err)) + return FALSE; + wdh->bytes_dumped += pad_len; + } + + /* XXX Write comment? */ + + /* write block footer */ + if (!wtap_dump_file_write(wdh, &bh.block_total_length, + sizeof bh.block_total_length, err)) + return FALSE; + + return TRUE; + +} + /* Arbitrary. */ #define NRES_REC_MAX_SIZE ((WTAP_MAX_PACKET_SIZE * 4) + 16) static gboolean @@ -3842,6 +3958,12 @@ static gboolean pcapng_dump(wtap_dumper *wdh, } break; + case REC_TYPE_SYSCALL: + if (!pcapng_write_sysdig_event_block(wdh, phdr, pseudo_header, pd, err)) { + return FALSE; + } + break; + default: /* We don't support writing this record type. */ *err = WTAP_ERR_UNWRITABLE_REC_TYPE; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 6d257ea002..acffcb3d0a 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1203,6 +1203,7 @@ union wtap_pseudo_header { #define REC_TYPE_PACKET 0 /**< packet */ #define REC_TYPE_FT_SPECIFIC_EVENT 1 /**< file-type-specific event */ #define REC_TYPE_FT_SPECIFIC_REPORT 2 /**< file-type-specific report */ +#define REC_TYPE_SYSCALL 3 /**< system call */ struct wtap_pkthdr { guint rec_type; /* what type of record is this? */