From 889e0d5cb6a4e082e13d71c88c0fe40a4e8f8d2d Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Tue, 27 Oct 2020 20:06:26 -0700 Subject: [PATCH] Add a new record type REC_TYPE_SYSTEMD_JOURNAL. Systemd journal entries aren't file-type-specific; they're found in both systemd journal entry blocks in pcapng files and in systemd journal export files. Give it a record type, for use with both file types. This fixes #16955. It also means that you can open a systemd journal export file and save it as a pcapng file. --- editcap.c | 5 ++++ epan/dissectors/packet-frame.c | 27 +++++++++++++++++++++ epan/dissectors/packet-systemd-journal.c | 12 ++++----- epan/frame_data.c | 9 +++++++ epan/packet.c | 8 ++++++ ui/file_dialog.c | 1 + wiretap/pcapng.c | 31 ++++++++++++------------ wiretap/systemd_journal.c | 5 ++-- wiretap/wtap.h | 6 +++++ 9 files changed, 78 insertions(+), 26 deletions(-) diff --git a/editcap.c b/editcap.c index e06324ff83..acbf02f05c 100644 --- a/editcap.c +++ b/editcap.c @@ -2078,6 +2078,11 @@ invalid_time: caplen = rec->rec_header.syscall_header.event_filelen; do_mutation = TRUE; break; + + case REC_TYPE_SYSTEMD_JOURNAL: + caplen = rec->rec_header.systemd_journal_header.record_len; + do_mutation = TRUE; + break; } if (change_offset > caplen) { diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index ce6a7368f8..44e4024b1a 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -105,6 +105,7 @@ static int frame_tap = -1; static dissector_handle_t docsis_handle; static dissector_handle_t sysdig_handle; +static dissector_handle_t systemd_journal_handle; /* Preferences */ static gboolean show_file_off = FALSE; @@ -379,6 +380,10 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* pinfo->current_proto = "System Call"; break; + case REC_TYPE_SYSTEMD_JOURNAL: + pinfo->current_proto = "Systemd Journal"; + break; + default: g_assert_not_reached(); break; @@ -493,6 +498,19 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* "System Call %u: %u byte%s", pinfo->num, frame_len, frame_plurality); break; + + case REC_TYPE_SYSTEMD_JOURNAL: + /* + * XXX - we need to rethink what's handled by + * packet-record.c, what's handled by packet-frame.c. + * and what's handled by the syscall and systemd + * journal dissectors (and maybe even the packet + * dissector). + */ + ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb), + "Systemd Journal Entry %u: %u byte%s", + pinfo->num, frame_len, frame_plurality); + break; } fh_tree = proto_item_add_subtree(ti, ett_frame); @@ -799,6 +817,14 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* (void *)pinfo->pseudo_header); } break; + + case REC_TYPE_SYSTEMD_JOURNAL: + if (systemd_journal_handle) { + call_dissector_with_data(systemd_journal_handle, + tvb, pinfo, parent_tree, + (void *)pinfo->pseudo_header); + } + break; } #ifdef _MSC_VER } __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) { @@ -1274,6 +1300,7 @@ proto_reg_handoff_frame(void) { docsis_handle = find_dissector_add_dependency("docsis", proto_frame); sysdig_handle = find_dissector_add_dependency("sysdig", proto_frame); + systemd_journal_handle = find_dissector_add_dependency("systemd_journal", proto_frame); } /* diff --git a/epan/dissectors/packet-systemd-journal.c b/epan/dissectors/packet-systemd-journal.c index 5171302fb9..b2d03f5914 100644 --- a/epan/dissectors/packet-systemd-journal.c +++ b/epan/dissectors/packet-systemd-journal.c @@ -161,6 +161,8 @@ static expert_field ei_unhandled_field_type = EI_INIT; static expert_field ei_nonbinary_field = EI_INIT; static expert_field ei_undecoded_field = EI_INIT; +static dissector_handle_t sje_handle = NULL; + #define MAX_DATA_SIZE 262144 // WTAP_MAX_PACKET_SIZE_STANDARD. Increase if needed. /* Initialize the subtree pointers */ @@ -877,6 +879,9 @@ proto_register_systemd_journal(void) expert_systemd_journal = expert_register_protocol(proto_systemd_journal); expert_register_field_array(expert_systemd_journal, ei, array_length(ei)); + sje_handle = register_dissector("systemd_journal", dissect_systemd_journal_line_entry, + proto_systemd_journal); + init_jf_to_hf_map(); } @@ -884,13 +889,6 @@ proto_register_systemd_journal(void) void proto_reg_handoff_systemd_journal(void) { - static dissector_handle_t sje_handle = NULL; - - if (!sje_handle) { - sje_handle = create_dissector_handle(dissect_systemd_journal_line_entry, - proto_systemd_journal); - } - dissector_add_uint("wtap_fts_rec", WTAP_FILE_TYPE_SUBTYPE_SYSTEMD_JOURNAL, sje_handle); dissector_add_uint("pcapng.block_type", BLOCK_TYPE_SYSTEMD_JOURNAL, sje_handle); // It's possible to ship journal entries over HTTP/HTTPS using diff --git a/epan/frame_data.c b/epan/frame_data.c index cac0f217f5..1900b6ac59 100644 --- a/epan/frame_data.c +++ b/epan/frame_data.c @@ -192,6 +192,15 @@ frame_data_init(frame_data *fdata, guint32 num, const wtap_rec *rec, fdata->cum_bytes = cum_bytes + rec->rec_header.syscall_header.event_len; fdata->cap_len = rec->rec_header.syscall_header.event_filelen; break; + + case REC_TYPE_SYSTEMD_JOURNAL: + /* + * XXX - is cum_bytes supposed to count non-packet bytes? + */ + fdata->pkt_len = rec->rec_header.systemd_journal_header.record_len; + fdata->cum_bytes = cum_bytes + rec->rec_header.systemd_journal_header.record_len; + fdata->cap_len = rec->rec_header.systemd_journal_header.record_len; + break; } /* To save some memory, we coerce it into 4 bits */ diff --git a/epan/packet.c b/epan/packet.c index 49edd9aa04..3bdb6281e2 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -501,6 +501,10 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, record_type = "System Call"; break; + case REC_TYPE_SYSTEMD_JOURNAL: + record_type = "Systemd Journal Entry"; + break; + default: /* * XXX - if we add record types that shouldn't be @@ -544,6 +548,10 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, case REC_TYPE_SYSCALL: edt->pi.pseudo_header = NULL; break; + + case REC_TYPE_SYSTEMD_JOURNAL: + edt->pi.pseudo_header = NULL; + break; } edt->pi.fd = fd; diff --git a/ui/file_dialog.c b/ui/file_dialog.c index e3a9a5a386..d41ebb9c15 100644 --- a/ui/file_dialog.c +++ b/ui/file_dialog.c @@ -69,6 +69,7 @@ get_stats_for_preview(wtap *wth, ws_file_preview_stats *stats, case REC_TYPE_FT_SPECIFIC_EVENT: case REC_TYPE_FT_SPECIFIC_REPORT: case REC_TYPE_SYSCALL: + case REC_TYPE_SYSTEMD_JOURNAL: data_records++; break; } diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index d5c7fde82a..1f8b68330a 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -2519,9 +2519,8 @@ pcapng_read_systemd_journal_export_block(wtap *wth, FILE_T fh, pcapng_block_head return FALSE; } - wblock->rec->rec_type = REC_TYPE_FT_SPECIFIC_EVENT; - wblock->rec->rec_header.ft_specific_header.record_type = BLOCK_TYPE_SYSTEMD_JOURNAL; - wblock->rec->rec_header.ft_specific_header.record_len = entry_length; + wblock->rec->rec_type = REC_TYPE_SYSTEMD_JOURNAL; + wblock->rec->rec_header.systemd_journal_header.record_len = entry_length; wblock->rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; wblock->rec->tsprec = WTAP_TSPREC_USEC; @@ -3863,23 +3862,23 @@ pcapng_write_systemd_journal_export_block(wtap_dumper *wdh, const wtap_rec *rec, guint32 pad_len; /* Don't write anything we're not willing to read. */ - if (rec->rec_header.ft_specific_header.record_len > WTAP_MAX_PACKET_SIZE_STANDARD) { + if (rec->rec_header.systemd_journal_header.record_len > WTAP_MAX_PACKET_SIZE_STANDARD) { *err = WTAP_ERR_PACKET_TOO_LARGE; return FALSE; } - if (rec->rec_header.ft_specific_header.record_len % 4) { - pad_len = 4 - (rec->rec_header.ft_specific_header.record_len % 4); + if (rec->rec_header.systemd_journal_header.record_len % 4) { + pad_len = 4 - (rec->rec_header.systemd_journal_header.record_len % 4); } else { pad_len = 0; } /* write systemd journal export block header */ bh.block_type = BLOCK_TYPE_SYSTEMD_JOURNAL; - bh.block_total_length = (guint32)sizeof(bh) + rec->rec_header.ft_specific_header.record_len + pad_len + 4; + bh.block_total_length = (guint32)sizeof(bh) + rec->rec_header.systemd_journal_header.record_len + pad_len + 4; pcapng_debug("%s: writing %u bytes, %u padded", G_STRFUNC, - rec->rec_header.ft_specific_header.record_len, + rec->rec_header.systemd_journal_header.record_len, bh.block_total_length); if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) @@ -3887,9 +3886,9 @@ pcapng_write_systemd_journal_export_block(wtap_dumper *wdh, const wtap_rec *rec, wdh->bytes_dumped += sizeof bh; /* write entry data */ - if (!wtap_dump_file_write(wdh, pd, rec->rec_header.ft_specific_header.record_len, err)) + if (!wtap_dump_file_write(wdh, pd, rec->rec_header.systemd_journal_header.record_len, err)) return FALSE; - wdh->bytes_dumped += rec->rec_header.ft_specific_header.record_len; + wdh->bytes_dumped += rec->rec_header.systemd_journal_header.record_len; /* write padding (if any) */ if (pad_len != 0) { @@ -4824,12 +4823,6 @@ static gboolean pcapng_dump(wtap_dumper *wdh, case REC_TYPE_FT_SPECIFIC_EVENT: case REC_TYPE_FT_SPECIFIC_REPORT: - if (rec->rec_header.ft_specific_header.record_type == WTAP_FILE_TYPE_SUBTYPE_SYSTEMD_JOURNAL) { - if (!pcapng_write_systemd_journal_export_block(wdh, rec, pd, err)) { - return FALSE; - } - return TRUE; - } #ifdef HAVE_PLUGINS /* * Do we have a handler for this block type? @@ -4855,6 +4848,12 @@ static gboolean pcapng_dump(wtap_dumper *wdh, } break; + case REC_TYPE_SYSTEMD_JOURNAL: + if (!pcapng_write_systemd_journal_export_block(wdh, rec, pd, err)) { + return FALSE; + } + break; + default: /* We don't support writing this record type. */ *err = WTAP_ERR_UNWRITABLE_REC_TYPE; diff --git a/wiretap/systemd_journal.c b/wiretap/systemd_journal.c index c247bd5411..4414404199 100644 --- a/wiretap/systemd_journal.c +++ b/wiretap/systemd_journal.c @@ -225,10 +225,9 @@ systemd_journal_read_export_entry(FILE_T fh, wtap_rec *rec, Buffer *buf, int *er return FALSE; } - rec->rec_type = REC_TYPE_FT_SPECIFIC_EVENT; + rec->rec_type = REC_TYPE_SYSTEMD_JOURNAL; rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; - rec->rec_header.ft_specific_header.record_type = WTAP_FILE_TYPE_SUBTYPE_SYSTEMD_JOURNAL; - rec->rec_header.ft_specific_header.record_len = (guint32) fld_end; + rec->rec_header.systemd_journal_header.record_len = (guint32) fld_end; return TRUE; } diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 6c64dd5e57..e01b30c461 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1296,6 +1296,7 @@ union wtap_pseudo_header { #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 */ +#define REC_TYPE_SYSTEMD_JOURNAL 4 /**< systemd journal entry */ typedef struct { guint32 caplen; /* data length in the file */ @@ -1402,6 +1403,10 @@ typedef struct { /* ... Event ... */ } wtap_syscall_header; +typedef struct { + guint32 record_len; /* length of the record */ +} wtap_systemd_journal_header; + typedef struct { guint rec_type; /* what type of record is this? */ guint32 presence_flags; /* what stuff do we have? */ @@ -1411,6 +1416,7 @@ typedef struct { wtap_packet_header packet_header; wtap_ft_specific_header ft_specific_header; wtap_syscall_header syscall_header; + wtap_systemd_journal_header systemd_journal_header; } rec_header; /* * XXX - this should become a full set of options.