forked from osmocom/wireshark
Add a systemd Journal Export Format parser and dissector.
Add a file parser and dissector that can handle the output of `journalctl -o export`. From here we can add a systemd journal extcap and possibly support for the JSON and binary formats. Change-Id: I01576959b2c347ce7ac9aa57cdb5c119c81d61e9 Reviewed-on: https://code.wireshark.org/review/29311 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
94735eb2bc
commit
50b9da7bc2
|
@ -62,25 +62,26 @@ since version 2.6.0:
|
|||
// Add one protocol per line between the -- delimiters.
|
||||
[commaize]
|
||||
--
|
||||
Cisco Meraki Discovery Protocol (MDP)
|
||||
DoIP (ISO 13400-2 Diagnostic communication over Internet Protocol)
|
||||
DXL protocol
|
||||
E1AP (5G) protocol
|
||||
Exablaze trailers
|
||||
GLOW Lawo Emberplus Data format
|
||||
GSM-R protocol (User-to-User Information Element usage)
|
||||
GSUP (Osmocom Generic Subscriber Update Protocol)
|
||||
MsgPack protocol
|
||||
NGAP (5G) protocol
|
||||
NR (5G) PDCP protocol
|
||||
TPM 2.0 protocol
|
||||
PROXY (v2) protocol
|
||||
Ruby Marshal format
|
||||
Ruby Distributed protocol
|
||||
GSM-R protocol (User-to-User Information Element usage)
|
||||
Ruby Marshal format
|
||||
S101 Lawo Emberplus transport frame
|
||||
GLOW Lawo Emberplus Data format
|
||||
STCSIG (Spirent Test Center Signature decoding for Ethernet and FibreChannel, disabled by default)
|
||||
Exablaze trailers
|
||||
systemd Journal Export
|
||||
TPM 2.0 protocol
|
||||
Ubiquiti Discovery Protocol (UBDP)
|
||||
Cisco Meraki Discovery Protocol (MDP)
|
||||
XnAP (5G) protocol
|
||||
E1AP (5G) protocol
|
||||
MsgPack protocol
|
||||
DXL protocol
|
||||
--
|
||||
|
||||
=== Updated Protocol Support
|
||||
|
@ -92,6 +93,9 @@ Too many protocols have been updated to list here.
|
|||
//_Non-empty section placeholder._
|
||||
// Add one file type per line between the --sort-and-group-- delimiters.
|
||||
[commaize]
|
||||
--
|
||||
systemd Journal Export
|
||||
--
|
||||
|
||||
=== New and Updated Capture Interfaces support
|
||||
|
||||
|
|
|
@ -170,6 +170,7 @@ set(CLEAN_ASN1_DISSECTOR_SRC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/packet-snmp.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-spnego.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-sv.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-systemd-journal.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-t124.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-t125.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-t38.c
|
||||
|
@ -554,6 +555,7 @@ set(DISSECTOR_PUBLIC_HEADERS
|
|||
packet-stat.h
|
||||
packet-stat-notify.h
|
||||
packet-sv.h
|
||||
packet-syslog.h
|
||||
packet-t124.h
|
||||
packet-t30.h
|
||||
packet-t38.h
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <epan/packet.h>
|
||||
#include <epan/strutil.h>
|
||||
|
||||
#include "packet-syslog.h"
|
||||
|
||||
#define UDP_PORT_SYSLOG 514
|
||||
|
||||
#define PRIORITY_MASK 0x0007 /* 0000 0111 */
|
||||
|
@ -31,15 +33,7 @@ void proto_register_syslog(void);
|
|||
/* The maximum number if priority digits to read in. */
|
||||
#define MAX_DIGITS 3
|
||||
|
||||
#define LEVEL_EMERG 0
|
||||
#define LEVEL_ALERT 1
|
||||
#define LEVEL_CRIT 2
|
||||
#define LEVEL_ERR 3
|
||||
#define LEVEL_WARNING 4
|
||||
#define LEVEL_NOTICE 5
|
||||
#define LEVEL_INFO 6
|
||||
#define LEVEL_DEBUG 7
|
||||
static const value_string short_lev[] = {
|
||||
static const value_string short_level_vals[] = {
|
||||
{ LEVEL_EMERG, "EMERG" },
|
||||
{ LEVEL_ALERT, "ALERT" },
|
||||
{ LEVEL_CRIT, "CRIT" },
|
||||
|
@ -51,31 +45,7 @@ static const value_string short_lev[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#define FAC_KERN 0
|
||||
#define FAC_USER 1
|
||||
#define FAC_MAIL 2
|
||||
#define FAC_DAEMON 3
|
||||
#define FAC_AUTH 4
|
||||
#define FAC_SYSLOG 5
|
||||
#define FAC_LPR 6
|
||||
#define FAC_NEWS 7
|
||||
#define FAC_UUCP 8
|
||||
#define FAC_CRON 9
|
||||
#define FAC_AUTHPRIV 10
|
||||
#define FAC_FTP 11
|
||||
#define FAC_NTP 12
|
||||
#define FAC_LOGAUDIT 13
|
||||
#define FAC_LOGALERT 14
|
||||
#define FAC_CRON_SOL 15
|
||||
#define FAC_LOCAL0 16
|
||||
#define FAC_LOCAL1 17
|
||||
#define FAC_LOCAL2 18
|
||||
#define FAC_LOCAL3 19
|
||||
#define FAC_LOCAL4 20
|
||||
#define FAC_LOCAL5 21
|
||||
#define FAC_LOCAL6 22
|
||||
#define FAC_LOCAL7 23
|
||||
static const value_string short_fac[] = {
|
||||
static const value_string short_facility_vals[] = {
|
||||
{ FAC_KERN, "KERN" },
|
||||
{ FAC_USER, "USER" },
|
||||
{ FAC_MAIL, "MAIL" },
|
||||
|
@ -103,46 +73,6 @@ static const value_string short_fac[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string long_lev[] = {
|
||||
{ LEVEL_EMERG, "EMERG - system is unusable" },
|
||||
{ LEVEL_ALERT, "ALERT - action must be taken immediately" },
|
||||
{ LEVEL_CRIT, "CRIT - critical conditions" },
|
||||
{ LEVEL_ERR, "ERR - error conditions" },
|
||||
{ LEVEL_WARNING, "WARNING - warning conditions" },
|
||||
{ LEVEL_NOTICE, "NOTICE - normal but significant condition" },
|
||||
{ LEVEL_INFO, "INFO - informational" },
|
||||
{ LEVEL_DEBUG, "DEBUG - debug-level messages" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string long_fac[] = {
|
||||
{ FAC_KERN, "KERN - kernel messages" },
|
||||
{ FAC_USER, "USER - random user-level messages" },
|
||||
{ FAC_MAIL, "MAIL - mail system" },
|
||||
{ FAC_DAEMON, "DAEMON - system daemons" },
|
||||
{ FAC_AUTH, "AUTH - security/authorization messages" },
|
||||
{ FAC_SYSLOG, "SYSLOG - messages generated internally by syslogd" },
|
||||
{ FAC_LPR, "LPR - line printer subsystem" },
|
||||
{ FAC_NEWS, "NEWS - network news subsystem" },
|
||||
{ FAC_UUCP, "UUCP - UUCP subsystem" },
|
||||
{ FAC_CRON, "CRON - clock daemon (BSD, Linux)" },
|
||||
{ FAC_AUTHPRIV, "AUTHPRIV - security/authorization messages (private)" },
|
||||
{ FAC_FTP, "FTP - ftp daemon" },
|
||||
{ FAC_NTP, "NTP - ntp subsystem" },
|
||||
{ FAC_LOGAUDIT, "LOGAUDIT - log audit" },
|
||||
{ FAC_LOGALERT, "LOGALERT - log alert" },
|
||||
{ FAC_CRON_SOL, "CRON - clock daemon (Solaris)" },
|
||||
{ FAC_LOCAL0, "LOCAL0 - reserved for local use" },
|
||||
{ FAC_LOCAL1, "LOCAL1 - reserved for local use" },
|
||||
{ FAC_LOCAL2, "LOCAL2 - reserved for local use" },
|
||||
{ FAC_LOCAL3, "LOCAL3 - reserved for local use" },
|
||||
{ FAC_LOCAL4, "LOCAL4 - reserved for local use" },
|
||||
{ FAC_LOCAL5, "LOCAL5 - reserved for local use" },
|
||||
{ FAC_LOCAL6, "LOCAL6 - reserved for local use" },
|
||||
{ FAC_LOCAL7, "LOCAL7 - reserved for local use" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static gint proto_syslog = -1;
|
||||
static gint hf_syslog_level = -1;
|
||||
static gint hf_syslog_facility = -1;
|
||||
|
@ -296,8 +226,8 @@ dissect_syslog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _
|
|||
if (mtp3_tvb == NULL) {
|
||||
if (pri >= 0) {
|
||||
col_add_fstr(pinfo->cinfo, COL_INFO, "%s.%s: %s",
|
||||
val_to_str_const(fac, short_fac, "UNKNOWN"),
|
||||
val_to_str_const(lev, short_lev, "UNKNOWN"), msg_str);
|
||||
val_to_str_const(fac, short_facility_vals, "UNKNOWN"),
|
||||
val_to_str_const(lev, short_level_vals, "UNKNOWN"), msg_str);
|
||||
} else {
|
||||
col_add_str(pinfo->cinfo, COL_INFO, msg_str);
|
||||
}
|
||||
|
@ -307,8 +237,8 @@ dissect_syslog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _
|
|||
if (pri >= 0) {
|
||||
ti = proto_tree_add_protocol_format(tree, proto_syslog, tvb, 0, -1,
|
||||
"Syslog message: %s.%s: %s",
|
||||
val_to_str_const(fac, short_fac, "UNKNOWN"),
|
||||
val_to_str_const(lev, short_lev, "UNKNOWN"), msg_str);
|
||||
val_to_str_const(fac, short_facility_vals, "UNKNOWN"),
|
||||
val_to_str_const(lev, short_level_vals, "UNKNOWN"), msg_str);
|
||||
} else {
|
||||
ti = proto_tree_add_protocol_format(tree, proto_syslog, tvb, 0, -1,
|
||||
"Syslog message: (unknown): %s", msg_str);
|
||||
|
@ -349,12 +279,12 @@ void proto_register_syslog(void)
|
|||
static hf_register_info hf[] = {
|
||||
{ &hf_syslog_facility,
|
||||
{ "Facility", "syslog.facility",
|
||||
FT_UINT8, BASE_DEC, VALS(long_fac), FACILITY_MASK,
|
||||
FT_UINT8, BASE_DEC, VALS(syslog_facility_vals), FACILITY_MASK,
|
||||
"Message facility", HFILL }
|
||||
},
|
||||
{ &hf_syslog_level,
|
||||
{ "Level", "syslog.level",
|
||||
FT_UINT8, BASE_DEC, VALS(long_lev), PRIORITY_MASK,
|
||||
FT_UINT8, BASE_DEC, VALS(syslog_level_vals), PRIORITY_MASK,
|
||||
"Message level", HFILL }
|
||||
},
|
||||
{ &hf_syslog_msg,
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* packet-syslog.h
|
||||
* Routines for syslog message dissection
|
||||
*
|
||||
* Copyright 2000, Gerald Combs <gerald[AT]wireshark.org>
|
||||
*
|
||||
* Support for passing SS7 MSUs (from the Cisco ITP Packet Logging
|
||||
* facility) to the MTP3 dissector by Abhik Sarkar <sarkar.abhik[AT]gmail.com>
|
||||
* with some rework by Jeff Morriss <jeff.morriss.ws [AT] gmail.com>
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald[AT]wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef __PACKET_SYSLOG_H__
|
||||
#define __PACKET_SYSLOG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Level / Priority */
|
||||
#define LEVEL_EMERG 0
|
||||
#define LEVEL_ALERT 1
|
||||
#define LEVEL_CRIT 2
|
||||
#define LEVEL_ERR 3
|
||||
#define LEVEL_WARNING 4
|
||||
#define LEVEL_NOTICE 5
|
||||
#define LEVEL_INFO 6
|
||||
#define LEVEL_DEBUG 7
|
||||
|
||||
static const value_string syslog_level_vals[] = {
|
||||
{ LEVEL_EMERG, "EMERG - system is unusable" },
|
||||
{ LEVEL_ALERT, "ALERT - action must be taken immediately" },
|
||||
{ LEVEL_CRIT, "CRIT - critical conditions" },
|
||||
{ LEVEL_ERR, "ERR - error conditions" },
|
||||
{ LEVEL_WARNING, "WARNING - warning conditions" },
|
||||
{ LEVEL_NOTICE, "NOTICE - normal but significant condition" },
|
||||
{ LEVEL_INFO, "INFO - informational" },
|
||||
{ LEVEL_DEBUG, "DEBUG - debug-level messages" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Facility */
|
||||
#define FAC_KERN 0
|
||||
#define FAC_USER 1
|
||||
#define FAC_MAIL 2
|
||||
#define FAC_DAEMON 3
|
||||
#define FAC_AUTH 4
|
||||
#define FAC_SYSLOG 5
|
||||
#define FAC_LPR 6
|
||||
#define FAC_NEWS 7
|
||||
#define FAC_UUCP 8
|
||||
#define FAC_CRON 9
|
||||
#define FAC_AUTHPRIV 10
|
||||
#define FAC_FTP 11
|
||||
#define FAC_NTP 12
|
||||
#define FAC_LOGAUDIT 13
|
||||
#define FAC_LOGALERT 14
|
||||
#define FAC_CRON_SOL 15
|
||||
#define FAC_LOCAL0 16
|
||||
#define FAC_LOCAL1 17
|
||||
#define FAC_LOCAL2 18
|
||||
#define FAC_LOCAL3 19
|
||||
#define FAC_LOCAL4 20
|
||||
#define FAC_LOCAL5 21
|
||||
#define FAC_LOCAL6 22
|
||||
#define FAC_LOCAL7 23
|
||||
|
||||
static const value_string syslog_facility_vals[] = {
|
||||
{ FAC_KERN, "KERN - kernel messages" },
|
||||
{ FAC_USER, "USER - random user-level messages" },
|
||||
{ FAC_MAIL, "MAIL - mail system" },
|
||||
{ FAC_DAEMON, "DAEMON - system daemons" },
|
||||
{ FAC_AUTH, "AUTH - security/authorization messages" },
|
||||
{ FAC_SYSLOG, "SYSLOG - messages generated internally by syslogd" },
|
||||
{ FAC_LPR, "LPR - line printer subsystem" },
|
||||
{ FAC_NEWS, "NEWS - network news subsystem" },
|
||||
{ FAC_UUCP, "UUCP - UUCP subsystem" },
|
||||
{ FAC_CRON, "CRON - clock daemon (BSD, Linux)" },
|
||||
{ FAC_AUTHPRIV, "AUTHPRIV - security/authorization messages (private)" },
|
||||
{ FAC_FTP, "FTP - ftp daemon" },
|
||||
{ FAC_NTP, "NTP - ntp subsystem" },
|
||||
{ FAC_LOGAUDIT, "LOGAUDIT - log audit" },
|
||||
{ FAC_LOGALERT, "LOGALERT - log alert" },
|
||||
{ FAC_CRON_SOL, "CRON - clock daemon (Solaris)" },
|
||||
{ FAC_LOCAL0, "LOCAL0 - reserved for local use" },
|
||||
{ FAC_LOCAL1, "LOCAL1 - reserved for local use" },
|
||||
{ FAC_LOCAL2, "LOCAL2 - reserved for local use" },
|
||||
{ FAC_LOCAL3, "LOCAL3 - reserved for local use" },
|
||||
{ FAC_LOCAL4, "LOCAL4 - reserved for local use" },
|
||||
{ FAC_LOCAL5, "LOCAL5 - reserved for local use" },
|
||||
{ FAC_LOCAL6, "LOCAL6 - reserved for local use" },
|
||||
{ FAC_LOCAL7, "LOCAL7 - reserved for local use" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // __PACKET_SYSLOG_H__
|
|
@ -0,0 +1,839 @@
|
|||
/* packet-systemd-journal-export.c
|
||||
* Routines for systemd journal export (application/vnd.fdo.journal) dissection
|
||||
* Copyright 2018, Gerald Combs <gerald@wireshark.org>
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dissector for systemd's mostly-text-based Journal Export Format described
|
||||
* at https://www.freedesktop.org/wiki/Software/systemd/export/.
|
||||
*
|
||||
* Registered MIME type: application/vnd.fdo.journal
|
||||
*
|
||||
* To do:
|
||||
* - Add an extcap module.
|
||||
* - Add errno strings.
|
||||
* - Pretty-print _CAP_EFFECTIVE
|
||||
* - Handle Journal JSON Format? https://www.freedesktop.org/wiki/Software/systemd/json/
|
||||
* - Handle raw journal files? https://www.freedesktop.org/wiki/Software/systemd/journal-files/
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <epan/exceptions.h>
|
||||
#include <epan/packet.h>
|
||||
#include <epan/expert.h>
|
||||
|
||||
#include "packet-syslog.h"
|
||||
|
||||
#define PNAME "systemd Journal Entry"
|
||||
#define PSNAME "systemd Journal"
|
||||
#define PFNAME "systemd_journal"
|
||||
|
||||
void proto_reg_handoff_systemd_journal(void);
|
||||
void proto_register_systemd_journal(void);
|
||||
|
||||
/* Initialize the protocol and registered fields */
|
||||
static int proto_systemd_journal = -1;
|
||||
|
||||
// Official entries, listed in
|
||||
// https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
|
||||
// as of 2018-08.
|
||||
static int hf_sj_message = -1;
|
||||
static int hf_sj_message_id = -1;
|
||||
static int hf_sj_priority = -1;
|
||||
static int hf_sj_code_file = -1;
|
||||
static int hf_sj_code_line = -1;
|
||||
static int hf_sj_code_func = -1;
|
||||
static int hf_sj_errno = -1;
|
||||
static int hf_sj_syslog_facility = -1;
|
||||
static int hf_sj_syslog_identifier = -1;
|
||||
static int hf_sj_syslog_pid = -1;
|
||||
|
||||
static int hf_sj_pid = -1;
|
||||
static int hf_sj_uid = -1;
|
||||
static int hf_sj_gid = -1;
|
||||
static int hf_sj_comm = -1;
|
||||
static int hf_sj_exe = -1;
|
||||
static int hf_sj_cmdline = -1;
|
||||
static int hf_sj_cap_effective = -1;
|
||||
static int hf_sj_audit_session = -1;
|
||||
static int hf_sj_audit_loginuid = -1;
|
||||
static int hf_sj_systemd_cgroup = -1;
|
||||
static int hf_sj_systemd_slice = -1;
|
||||
static int hf_sj_systemd_unit = -1;
|
||||
static int hf_sj_systemd_user_unit = -1;
|
||||
static int hf_sj_systemd_session = -1;
|
||||
static int hf_sj_systemd_owner_uid = -1;
|
||||
|
||||
static int hf_sj_selinux_context = -1;
|
||||
static int hf_sj_source_realtime_timestamp = -1;
|
||||
static int hf_sj_boot_id = -1;
|
||||
static int hf_sj_machine_id = -1;
|
||||
static int hf_sj_systemd_invocation_id = -1;
|
||||
static int hf_sj_hostname = -1;
|
||||
static int hf_sj_transport = -1;
|
||||
static int hf_sj_stream_id = -1;
|
||||
static int hf_sj_line_break = -1;
|
||||
|
||||
static int hf_sj_kernel_device = -1;
|
||||
static int hf_sj_kernel_subsystem = -1;
|
||||
static int hf_sj_udev_sysname = -1;
|
||||
static int hf_sj_udev_devnode = -1;
|
||||
static int hf_sj_udev_devlink = -1;
|
||||
|
||||
static int hf_sj_coredump_unit = -1;
|
||||
static int hf_sj_coredump_user_unit = -1;
|
||||
static int hf_sj_object_pid = -1;
|
||||
static int hf_sj_object_uid = -1;
|
||||
static int hf_sj_object_gid = -1;
|
||||
static int hf_sj_object_comm = -1;
|
||||
static int hf_sj_object_exe = -1;
|
||||
static int hf_sj_object_cmdline = -1;
|
||||
static int hf_sj_object_audit_session = -1;
|
||||
static int hf_sj_object_audit_loginuid = -1;
|
||||
static int hf_sj_object_systemd_cgroup = -1;
|
||||
static int hf_sj_object_systemd_session = -1;
|
||||
static int hf_sj_object_systemd_owner_uid = -1;
|
||||
static int hf_sj_object_systemd_unit = -1;
|
||||
static int hf_sj_object_systemd_user_unit = -1;
|
||||
|
||||
static int hf_sj_cursor = -1;
|
||||
static int hf_sj_realtime_timestamp = -1;
|
||||
static int hf_sj_monotonic_timestamp = -1;
|
||||
|
||||
// Unofficial(?) fields. Not listed in the documentation but present in logs.
|
||||
static int hf_sj_result = -1;
|
||||
static int hf_sj_source_monotonic_timestamp = -1;
|
||||
static int hf_sj_journal_name = -1;
|
||||
static int hf_sj_journal_path = -1;
|
||||
static int hf_sj_current_use = -1;
|
||||
static int hf_sj_current_use_pretty = -1;
|
||||
static int hf_sj_max_use = -1;
|
||||
static int hf_sj_max_use_pretty = -1;
|
||||
static int hf_sj_disk_keep_free = -1;
|
||||
static int hf_sj_disk_keep_free_pretty = -1;
|
||||
static int hf_sj_disk_available = -1;
|
||||
static int hf_sj_disk_available_pretty = -1;
|
||||
static int hf_sj_limit = -1;
|
||||
static int hf_sj_limit_pretty = -1;
|
||||
static int hf_sj_available = -1;
|
||||
static int hf_sj_available_pretty = -1;
|
||||
static int hf_sj_audit_type = -1;
|
||||
static int hf_sj_audit_id = -1;
|
||||
static int hf_sj_audit_field_apparmor = -1;
|
||||
static int hf_sj_audit_field_operation = -1;
|
||||
static int hf_sj_audit_field_profile = -1;
|
||||
static int hf_sj_audit_field_name = -1;
|
||||
static int hf_sj_seat_id = -1;
|
||||
static int hf_sj_kernel_usec = -1;
|
||||
static int hf_sj_userspace_usec = -1;
|
||||
static int hf_sj_session_id = -1;
|
||||
static int hf_sj_user_id = -1;
|
||||
static int hf_sj_leader = -1;
|
||||
|
||||
// Metadata.
|
||||
static int hf_sj_binary_data_len = -1;
|
||||
static int hf_sj_unkown_field = -1;
|
||||
static int hf_sj_unkown_field_name = -1;
|
||||
static int hf_sj_unkown_field_value = -1;
|
||||
static int hf_sj_unkown_field_data = -1;
|
||||
static int hf_sj_unhandled_field_type = -1;
|
||||
|
||||
static expert_field ei_unhandled_field_type = EI_INIT;
|
||||
static expert_field ei_nonbinary_field = EI_INIT;
|
||||
|
||||
#define MAX_DATA_SIZE 262144 // WTAP_MAX_PACKET_SIZE_STANDARD. Increase if needed.
|
||||
|
||||
/* Initialize the subtree pointers */
|
||||
static gint ett_systemd_journal_entry = -1;
|
||||
static gint ett_systemd_binary_data = -1;
|
||||
static gint ett_systemd_unknown_field = -1;
|
||||
|
||||
// XXX Use a value_string instead?
|
||||
typedef struct _journal_field_hf_map {
|
||||
int hfid;
|
||||
const char *name;
|
||||
} journal_field_hf_map;
|
||||
|
||||
static journal_field_hf_map *jf_to_hf;
|
||||
|
||||
void init_jf_to_hf_map(void) {
|
||||
journal_field_hf_map jhmap[] = {
|
||||
// Official.
|
||||
{ hf_sj_message, "MESSAGE=" },
|
||||
{ hf_sj_message_id, "MESSAGE_ID=" },
|
||||
{ hf_sj_priority, "PRIORITY=" },
|
||||
{ hf_sj_code_file, "CODE_FILE=" },
|
||||
{ hf_sj_code_line, "CODE_LINE=" },
|
||||
{ hf_sj_code_func, "CODE_FUNC=" },
|
||||
{ hf_sj_result, "RESULT=" },
|
||||
{ hf_sj_errno, "ERRNO=" },
|
||||
{ hf_sj_syslog_facility, "SYSLOG_FACILITY=" },
|
||||
{ hf_sj_syslog_identifier, "SYSLOG_IDENTIFIER=" },
|
||||
{ hf_sj_syslog_pid, "SYSLOG_PID=" },
|
||||
|
||||
{ hf_sj_pid, "_PID=" },
|
||||
{ hf_sj_uid, "_UID=" },
|
||||
{ hf_sj_gid, "_GID=" },
|
||||
{ hf_sj_comm, "_COMM=" },
|
||||
{ hf_sj_exe, "_EXE=" },
|
||||
{ hf_sj_cmdline, "_CMDLINE=" },
|
||||
{ hf_sj_cap_effective, "_CAP_EFFECTIVE=" },
|
||||
{ hf_sj_audit_session, "_AUDIT_SESSION=" },
|
||||
{ hf_sj_audit_loginuid, "_AUDIT_LOGINUID=" },
|
||||
{ hf_sj_systemd_cgroup, "_SYSTEMD_CGROUP=" },
|
||||
{ hf_sj_systemd_slice, "_SYSTEMD_SLICE=" },
|
||||
{ hf_sj_systemd_unit, "_SYSTEMD_UNIT=" },
|
||||
{ hf_sj_systemd_user_unit, "_SYSTEMD_USER_UNIT=" },
|
||||
{ hf_sj_systemd_session, "_SYSTEMD_SESSION=" },
|
||||
{ hf_sj_systemd_owner_uid, "_SYSTEMD_OWNER_UID=" },
|
||||
|
||||
{ hf_sj_selinux_context, "_SELINUX_CONTEXT=" },
|
||||
{ hf_sj_source_realtime_timestamp, "_SOURCE_REALTIME_TIMESTAMP=" },
|
||||
{ hf_sj_source_monotonic_timestamp, "_SOURCE_MONOTONIC_TIMESTAMP=" },
|
||||
{ hf_sj_boot_id, "_BOOT_ID=" },
|
||||
{ hf_sj_machine_id, "_MACHINE_ID=" },
|
||||
{ hf_sj_systemd_invocation_id, "_SYSTEMD_INVOCATION_ID=" },
|
||||
{ hf_sj_hostname, "_HOSTNAME=" },
|
||||
{ hf_sj_transport, "_TRANSPORT=" },
|
||||
{ hf_sj_stream_id, "_STREAM_ID=" },
|
||||
{ hf_sj_line_break, "_LINE_BREAK=" },
|
||||
|
||||
{ hf_sj_kernel_device, "_KERNEL_DEVICE=" },
|
||||
{ hf_sj_kernel_subsystem, "_KERNEL_SUBSYSTEM=" },
|
||||
{ hf_sj_udev_sysname, "_UDEV_SYSNAME=" },
|
||||
{ hf_sj_udev_devnode, "_UDEV_DEVNODE=" },
|
||||
{ hf_sj_udev_devlink, "_UDEV_DEVLINK=" },
|
||||
|
||||
{ hf_sj_coredump_unit, "COREDUMP_UNIT=" },
|
||||
{ hf_sj_coredump_user_unit, "COREDUMP_USER_UNIT=" },
|
||||
{ hf_sj_object_pid, "OBJECT_PID=" },
|
||||
{ hf_sj_object_uid, "OBJECT_UID=" },
|
||||
{ hf_sj_object_gid, "OBJECT_GID=" },
|
||||
{ hf_sj_object_comm, "OBJECT_COMM=" },
|
||||
{ hf_sj_object_exe, "OBJECT_EXE=" },
|
||||
{ hf_sj_object_cmdline, "OBJECT_CMDLINE=" },
|
||||
{ hf_sj_object_audit_session, "OBJECT_AUDIT_SESSION=" },
|
||||
{ hf_sj_object_audit_loginuid, "OBJECT_AUDIT_LOGINUID=" },
|
||||
{ hf_sj_object_systemd_cgroup, "OBJECT_SYSTEMD_CGROUP=" },
|
||||
{ hf_sj_object_systemd_session, "OBJECT_SYSTEMD_SESSION=" },
|
||||
{ hf_sj_object_systemd_owner_uid, "OBJECT_SYSTEMD_OWNER_UID=" },
|
||||
{ hf_sj_object_systemd_unit, "OBJECT_SYSTEMD_UNIT=" },
|
||||
{ hf_sj_object_systemd_user_unit, "OBJECT_SYSTEMD_USER_UNIT=" },
|
||||
|
||||
{ hf_sj_cursor, "__CURSOR=" },
|
||||
{ hf_sj_realtime_timestamp, "__REALTIME_TIMESTAMP=" },
|
||||
{ hf_sj_monotonic_timestamp, "__MONOTONIC_TIMESTAMP=" },
|
||||
|
||||
// Unofficial?
|
||||
{ hf_sj_journal_name, "JOURNAL_NAME=" }, // systemd-journald: Runtime journal (/run/log/journal/) is ...
|
||||
{ hf_sj_journal_path, "JOURNAL_PATH=" }, // ""
|
||||
{ hf_sj_current_use, "CURRENT_USE=" }, // ""
|
||||
{ hf_sj_current_use_pretty, "CURRENT_USE_PRETTY=" }, // ""
|
||||
{ hf_sj_max_use, "MAX_USE=" }, // ""
|
||||
{ hf_sj_max_use_pretty, "MAX_USE_PRETTY=" }, // ""
|
||||
{ hf_sj_disk_keep_free, "DISK_KEEP_FREE=" }, // ""
|
||||
{ hf_sj_disk_keep_free_pretty, "DISK_KEEP_FREE_PRETTY=" }, // ""
|
||||
{ hf_sj_disk_available, "DISK_AVAILABLE=" }, // ""
|
||||
{ hf_sj_disk_available_pretty, "DISK_AVAILABLE_PRETTY=" }, // ""
|
||||
{ hf_sj_limit, "LIMIT=" }, // ""
|
||||
{ hf_sj_limit_pretty, "LIMIT_PRETTY=" }, // ""
|
||||
{ hf_sj_available, "AVAILABLE=" }, // ""
|
||||
{ hf_sj_available_pretty, "AVAILABLE_PRETTY=" }, // ""
|
||||
{ hf_sj_code_func, "CODE_FUNCTION=" }, // Dup / alias of CODE_FUNC?
|
||||
{ hf_sj_systemd_user_unit, "UNIT=" }, // Dup / alias of _SYSTEMD_UNIT?
|
||||
{ hf_sj_systemd_user_unit, "USER_UNIT=" }, // Dup / alias of _SYSTEMD_USER_UNIT?
|
||||
{ hf_sj_audit_type, "_AUDIT_TYPE=" },
|
||||
{ hf_sj_audit_id, "_AUDIT_ID=" },
|
||||
{ hf_sj_audit_field_apparmor, "_AUDIT_FIELD_APPARMOR=" },
|
||||
{ hf_sj_audit_field_operation, "_AUDIT_FIELD_OPERATION=" },
|
||||
{ hf_sj_audit_field_profile, "_AUDIT_FIELD_PROFILE=" },
|
||||
{ hf_sj_audit_field_name, "_AUDIT_FIELD_NAME=" },
|
||||
{ hf_sj_seat_id, "SEAT_ID=" },
|
||||
{ hf_sj_kernel_usec, "KERNEL_USEC=" },
|
||||
{ hf_sj_userspace_usec, "USERSPACE_USEC" },
|
||||
{ hf_sj_session_id, "SESSION_ID" },
|
||||
{ hf_sj_user_id, "USER_ID" },
|
||||
{ hf_sj_leader, "LEADER" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
jf_to_hf = (journal_field_hf_map*) g_memdup(jhmap, sizeof(jhmap));
|
||||
}
|
||||
|
||||
static void
|
||||
dissect_sjle_time_usecs(proto_tree *tree, int hf_idx, tvbuff_t *tvb, int offset, int len) {
|
||||
unsigned long rt_ts = strtoul(tvb_format_text(tvb, offset, len), NULL, 10);
|
||||
// XXX Check errno?
|
||||
nstime_t ts;
|
||||
ts.secs = (time_t) rt_ts / 1000000;
|
||||
ts.nsecs = (rt_ts % 1000000) * 1000;
|
||||
proto_tree_add_time(tree, hf_idx, tvb, offset, len, &ts);
|
||||
}
|
||||
|
||||
static void
|
||||
dissect_sjle_uint(proto_tree *tree, int hf_idx, tvbuff_t *tvb, int offset, int len) {
|
||||
guint32 uint_val = (guint32) strtoul(tvb_format_text(tvb, offset, len), NULL, 10);
|
||||
proto_tree_add_uint(tree, hf_idx, tvb, offset, len, uint_val);
|
||||
}
|
||||
|
||||
static void
|
||||
dissect_sjle_int(proto_tree *tree, int hf_idx, tvbuff_t *tvb, int offset, int len) {
|
||||
gint32 int_val = (gint32) strtol(tvb_format_text(tvb, offset, len), NULL, 10);
|
||||
proto_tree_add_int(tree, hf_idx, tvb, offset, len, int_val);
|
||||
}
|
||||
|
||||
/* Dissect a line-based journal export entry */
|
||||
static int
|
||||
dissect_systemd_journal_line_entry(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
|
||||
void *data _U_)
|
||||
{
|
||||
proto_item *ti;
|
||||
proto_tree *sje_tree;
|
||||
int offset = 0, next_offset = 0;
|
||||
int line_len;
|
||||
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
col_set_str(pinfo->cinfo, COL_INFO, "Journal Entry");
|
||||
|
||||
ti = proto_tree_add_item(tree, proto_systemd_journal, tvb, 0, -1, ENC_NA);
|
||||
sje_tree = proto_item_add_subtree(ti, ett_systemd_journal_entry);
|
||||
|
||||
while ((line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE)) >= 3) { // A=1
|
||||
gboolean found = FALSE;
|
||||
int eq_off = tvb_find_guint8(tvb, offset, line_len, '=') + 1;
|
||||
int val_len = offset + line_len - eq_off;
|
||||
|
||||
for (int i = 0; jf_to_hf[i].name; i++) {
|
||||
if (tvb_memeql(tvb, offset, (const guint8*) jf_to_hf[i].name, strlen(jf_to_hf[i].name)) == 0) {
|
||||
int hf_idx = jf_to_hf[i].hfid;
|
||||
switch (proto_registrar_get_ftype(hf_idx)) {
|
||||
case FT_ABSOLUTE_TIME:
|
||||
case FT_RELATIVE_TIME:
|
||||
dissect_sjle_time_usecs(sje_tree, hf_idx, tvb, eq_off, val_len);
|
||||
break;
|
||||
case FT_UINT32:
|
||||
case FT_UINT16:
|
||||
case FT_UINT8:
|
||||
dissect_sjle_uint(sje_tree, hf_idx, tvb, eq_off, val_len);
|
||||
break;
|
||||
case FT_INT32:
|
||||
case FT_INT16:
|
||||
case FT_INT8:
|
||||
dissect_sjle_int(sje_tree, hf_idx, tvb, eq_off, val_len);
|
||||
break;
|
||||
case FT_STRING:
|
||||
proto_tree_add_item(sje_tree, jf_to_hf[i].hfid, tvb, eq_off, val_len, ENC_UTF_8|ENC_NA);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
proto_item *expert_ti = proto_tree_add_item(sje_tree, hf_sj_unhandled_field_type, tvb, offset, line_len,
|
||||
ENC_UTF_8|ENC_NA);
|
||||
expert_add_info(pinfo, expert_ti, &ei_unhandled_field_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hf_idx == hf_sj_message) {
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
col_set_str(pinfo->cinfo, COL_INFO, tvb_format_text(tvb, eq_off, val_len));
|
||||
}
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && eq_off > offset + 1) {
|
||||
proto_item *unk_ti = proto_tree_add_none_format(sje_tree, hf_sj_unkown_field, tvb, offset, line_len,
|
||||
"Unknown text field: %s", tvb_format_text(tvb, offset, eq_off - offset - 1));
|
||||
proto_tree *unk_tree = proto_item_add_subtree(unk_ti, ett_systemd_unknown_field);
|
||||
proto_tree_add_item(unk_tree, hf_sj_unkown_field_name, tvb, offset, eq_off - offset - 1, ENC_UTF_8|ENC_NA);
|
||||
proto_tree_add_item(unk_tree, hf_sj_unkown_field_value, tvb, eq_off, val_len, ENC_UTF_8|ENC_NA);
|
||||
offset = next_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try again, looking for binary fields.
|
||||
if (!found) {
|
||||
for (int i = 0; jf_to_hf[i].name; i++) {
|
||||
int noeql_len = (int) strlen(jf_to_hf[i].name) - 1;
|
||||
if (tvb_memeql(tvb, offset, (const guint8 *) jf_to_hf[i].name, (size_t) noeql_len) == 0 && tvb_memeql(tvb, offset+noeql_len, (const guint8 *) "\n", 1) == 0) {
|
||||
int hf_idx = jf_to_hf[i].hfid;
|
||||
guint64 data_len = tvb_get_letoh64(tvb, offset + noeql_len + 1);
|
||||
int data_off = offset + noeql_len + 1 + 8; // \n + data len
|
||||
next_offset = data_off + (int) data_len + 1;
|
||||
if (proto_registrar_get_ftype(hf_idx) == FT_STRING) {
|
||||
proto_item *bin_ti = proto_tree_add_item(sje_tree, hf_idx, tvb, data_off, (int) data_len, ENC_NA);
|
||||
proto_tree *bin_tree = proto_item_add_subtree(bin_ti, ett_systemd_binary_data);
|
||||
proto_tree_add_item(bin_tree, hf_sj_binary_data_len, tvb, offset + noeql_len + 1, 8, ENC_LITTLE_ENDIAN);
|
||||
if (hf_idx == hf_sj_message) {
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
col_set_str(pinfo->cinfo, COL_INFO, tvb_format_text(tvb, data_off, (int) data_len));
|
||||
}
|
||||
} else {
|
||||
proto_item *unk_ti = proto_tree_add_none_format(sje_tree, hf_sj_unkown_field, tvb, offset, line_len,
|
||||
"Unknown data field: %s", tvb_format_text(tvb, offset, eq_off - offset - 1));
|
||||
proto_tree *unk_tree = proto_item_add_subtree(unk_ti, ett_systemd_unknown_field);
|
||||
proto_item *expert_ti = proto_tree_add_item(unk_tree, hf_sj_unkown_field_name, tvb, offset, offset + noeql_len, ENC_UTF_8|ENC_NA);
|
||||
proto_tree_add_item(unk_tree, hf_sj_unkown_field_data, tvb, data_off, (int) data_len, ENC_UTF_8|ENC_NA);
|
||||
expert_add_info(pinfo, expert_ti, &ei_nonbinary_field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
offset = next_offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the protocol with Wireshark.
|
||||
*/
|
||||
void
|
||||
proto_register_systemd_journal(void)
|
||||
{
|
||||
expert_module_t *expert_systemd_journal;
|
||||
|
||||
static hf_register_info hf[] = {
|
||||
{ &hf_sj_message,
|
||||
{ "Message", "systemd_journal.message",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_message_id,
|
||||
{ "Message ID", "systemd_journal.message_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_priority,
|
||||
{ "Priority", "systemd_journal.priority",
|
||||
FT_UINT8, BASE_DEC, VALS(syslog_level_vals), 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_code_file,
|
||||
{ "Code file", "systemd_journal.code_file",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_code_line,
|
||||
{ "Code line", "systemd_journal.code_line",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_code_func,
|
||||
{ "Code func", "systemd_journal.code_func",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_errno,
|
||||
{ "Errno", "systemd_journal.errno",
|
||||
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_syslog_facility,
|
||||
{ "Syslog facility", "systemd_journal.syslog_facility",
|
||||
FT_UINT8, BASE_NONE, VALS(syslog_facility_vals), 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_syslog_identifier,
|
||||
{ "Syslog identifier", "systemd_journal.syslog_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_syslog_pid,
|
||||
{ "Syslog PID", "systemd_journal.syslog_pid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_pid,
|
||||
{ "PID", "systemd_journal.pid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_uid,
|
||||
{ "UID", "systemd_journal.uid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_gid,
|
||||
{ "GID", "systemd_journal.gid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_comm,
|
||||
{ "Command name", "systemd_journal.comm",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_exe,
|
||||
{ "Executable path", "systemd_journal.exe",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_cmdline,
|
||||
{ "Command line", "systemd_journal.cmdline",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_cap_effective,
|
||||
{ "Effective capability", "systemd_journal.cap_effective",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_session,
|
||||
{ "Audit session", "systemd_journal.audit_session",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_loginuid,
|
||||
{ "Audit login UID", "systemd_journal.audit_loginuid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_systemd_cgroup,
|
||||
{ "Systemd cgroup", "systemd_journal.systemd_cgroup",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_slice,
|
||||
{ "Systemd slice", "systemd_journal.systemd_slice",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_unit,
|
||||
{ "Systemd unit", "systemd_journal.systemd_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_user_unit,
|
||||
{ "Systemd user unit", "systemd_journal.systemd_user_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_session,
|
||||
{ "Systemd session", "systemd_journal.systemd_session",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_owner_uid,
|
||||
{ "Systemd owner UID", "systemd_journal.systemd_owner_uid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_selinux_context,
|
||||
{ "SELinux context", "systemd_journal.selinux_context",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_source_realtime_timestamp,
|
||||
{ "Source realtime timestamp", "systemd_journal.source_realtime_timestamp",
|
||||
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_boot_id,
|
||||
{ "Boot ID", "systemd_journal.boot_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_machine_id,
|
||||
{ "Machine ID", "systemd_journal.machine_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_systemd_invocation_id,
|
||||
{ "Systemd invocation ID", "systemd_journal.systemd_invocation_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_hostname,
|
||||
{ "Hostname", "systemd_journal.hostname",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_transport,
|
||||
{ "Transport", "systemd_journal.transport",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_stream_id,
|
||||
{ "Stream ID", "systemd_journal.stream_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_line_break,
|
||||
{ "Line break", "systemd_journal.line_break",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_kernel_device,
|
||||
{ "Kernel device", "systemd_journal.kernel_device",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_kernel_subsystem,
|
||||
{ "Kernel subsystem", "systemd_journal.kernel_subsystem",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_udev_sysname,
|
||||
{ "Device tree name", "systemd_journal.udev_sysname",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_udev_devnode,
|
||||
{ "Device tree node", "systemd_journal.udev_devnode",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_udev_devlink,
|
||||
{ "Device tree symlink", "systemd_journal.udev_devlink",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_coredump_unit,
|
||||
{ "Coredump unit", "systemd_journal.coredump_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_coredump_user_unit,
|
||||
{ "Coredump user unit", "systemd_journal.coredump_user_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_pid,
|
||||
{ "Object PID", "systemd_journal.object_pid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_uid,
|
||||
{ "Object UID", "systemd_journal.object_uid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_gid,
|
||||
{ "Object GID", "systemd_journal.object_gid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_comm,
|
||||
{ "Object command name", "systemd_journal.object_comm",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_exe,
|
||||
{ "Object executable path", "systemd_journal.object_exe",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_cmdline,
|
||||
{ "Object command line", "systemd_journal.object_cmdline",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_audit_session,
|
||||
{ "Object audit session", "systemd_journal.object_audit_session",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_audit_loginuid,
|
||||
{ "Object audit login UID", "systemd_journal.object_audit_loginuid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_systemd_cgroup,
|
||||
{ "Object systemd cgroup", "systemd_journal.object_systemd_cgroup",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_systemd_session,
|
||||
{ "Object systemd session", "systemd_journal.object_systemd_session",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_systemd_owner_uid,
|
||||
{ "Object systemd owner UID", "systemd_journal.object_systemd_owner_uid",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_systemd_unit,
|
||||
{ "Object systemd unit", "systemd_journal.object_systemd_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_object_systemd_user_unit,
|
||||
{ "Object systemd user unit", "systemd_journal.object_systemd_user_unit",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_cursor,
|
||||
{ "Cursor", "systemd_journal.cursor",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_realtime_timestamp,
|
||||
{ "Realtime Timestamp", "systemd_journal.realtime_timestamp",
|
||||
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_monotonic_timestamp,
|
||||
{ "Monotonic Timestamp", "systemd_journal.monotonic_timestamp",
|
||||
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_journal_name,
|
||||
{ "Journal name", "systemd_journal.journal_name",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_journal_path,
|
||||
{ "Journal path", "systemd_journal.journal_path",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_current_use,
|
||||
{ "Current use", "systemd_journal.current_use",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_current_use_pretty,
|
||||
{ "Human readable current use", "systemd_journal.current_use_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_max_use,
|
||||
{ "Max use", "systemd_journal.max_use",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_max_use_pretty,
|
||||
{ "Human readable max use", "systemd_journal.max_use_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_disk_keep_free,
|
||||
{ "Disk keep free", "systemd_journal.disk_keep_free",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_disk_keep_free_pretty,
|
||||
{ "Human readable disk keep free", "systemd_journal.disk_keep_free_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_disk_available,
|
||||
{ "Disk available", "systemd_journal.disk_available",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_disk_available_pretty,
|
||||
{ "Human readable disk available", "systemd_journal.disk_available_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_limit,
|
||||
{ "Limit", "systemd_journal.limit",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_limit_pretty,
|
||||
{ "Human readable limit", "systemd_journal.limit_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_available,
|
||||
{ "Available", "systemd_journal.available",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_available_pretty,
|
||||
{ "Human readable available", "systemd_journal.available_pretty",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_result,
|
||||
{ "Result", "systemd_journal.result",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_source_monotonic_timestamp,
|
||||
{ "Source monotonic timestamp", "systemd_journal.source_monotonic_timestamp",
|
||||
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_type,
|
||||
{ "Audit type", "systemd_journal.audit_type",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_id,
|
||||
{ "Audit ID", "systemd_journal.audit_id",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_field_apparmor,
|
||||
{ "Audit field AppArmor", "systemd_journal.audit_field_apparmor",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_field_operation,
|
||||
{ "Audit field operation", "systemd_journal.audit_field_operation",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_field_profile,
|
||||
{ "Audit field profile", "systemd_journal.audit_field_profile",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_audit_field_name,
|
||||
{ "Audit field name", "systemd_journal.audit_field_name",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_seat_id,
|
||||
{ "Seat ID", "systemd_journal.seat_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_kernel_usec,
|
||||
{ "Kernel microseconds", "systemd_journal.kernel_usec",
|
||||
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_userspace_usec,
|
||||
{ "Userspace microseconds", "systemd_journal.userspace_usec",
|
||||
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_session_id,
|
||||
{ "Session ID", "systemd_journal.session_id",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_user_id,
|
||||
{ "User ID", "systemd_journal.user_id",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_leader,
|
||||
{ "Leader", "systemd_journal.leader",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_sj_binary_data_len,
|
||||
{ "Binary data length", "systemd_journal.binary_data_len",
|
||||
FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_unkown_field,
|
||||
{ "Unknown field", "systemd_journal.field",
|
||||
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_unkown_field_name,
|
||||
{ "Field name", "systemd_journal.field.name",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_unkown_field_value,
|
||||
{ "Field value", "systemd_journal.field.value",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_unkown_field_data,
|
||||
{ "Field data", "systemd_journal.field.data",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
},
|
||||
{ &hf_sj_unhandled_field_type,
|
||||
{ "Field data", "systemd_journal.unhandled_field_type",
|
||||
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
|
||||
}
|
||||
};
|
||||
|
||||
/* Setup protocol subtree array */
|
||||
static gint *ett[] = {
|
||||
&ett_systemd_journal_entry,
|
||||
&ett_systemd_binary_data,
|
||||
&ett_systemd_unknown_field
|
||||
};
|
||||
|
||||
/* Setup protocol expert items */
|
||||
static ei_register_info ei[] = {
|
||||
{ &ei_unhandled_field_type,
|
||||
{ "systemd_journal.unhandled_field_type", PI_UNDECODED, PI_ERROR,
|
||||
"Unhandled field type", EXPFILL }
|
||||
},
|
||||
{ &ei_nonbinary_field,
|
||||
{ "systemd_journal.nonbinary_field", PI_UNDECODED, PI_WARN,
|
||||
"Field shouldn't be binary", EXPFILL }
|
||||
}
|
||||
};
|
||||
|
||||
/* Register the protocol name and description */
|
||||
proto_systemd_journal = proto_register_protocol(PNAME, PSNAME, PFNAME);
|
||||
|
||||
/* Required function calls to register the header fields and subtrees */
|
||||
proto_register_field_array(proto_systemd_journal, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
||||
/* Required function calls to register expert items */
|
||||
expert_systemd_journal = expert_register_protocol(proto_systemd_journal);
|
||||
expert_register_field_array(expert_systemd_journal, ei, array_length(ei));
|
||||
|
||||
init_jf_to_hf_map();
|
||||
}
|
||||
|
||||
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_encap", WTAP_ENCAP_SYSTEMD_JOURNAL, sje_handle);
|
||||
// It's possible to ship journal entries over HTTP/HTTPS using
|
||||
// systemd-journal-remote. Dissecting them on the wire isn't very
|
||||
// useful since it's easy to end up with a packet containing a
|
||||
// single, huge reassembled journal with many entries.
|
||||
dissector_add_string("media_type", "application/vnd.fdo.journal", sje_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -74,6 +74,7 @@ set(WIRETAP_NONGENERATED_FILES
|
|||
ruby_marshal.c
|
||||
snoop.c
|
||||
stanag4607.c
|
||||
systemd_journal.c
|
||||
tnef.c
|
||||
toshiba.c
|
||||
visual.c
|
||||
|
|
|
@ -32,22 +32,22 @@ To add the ability to read a new capture file format, you have to:
|
|||
otherwise leave it set to NULL;
|
||||
|
||||
add a pointer to the "open" routine to the "open_routines_base[]"
|
||||
table in "wiretap/file_access.c" - if it uses a magic number, put
|
||||
it in the first section of that list, and, if it uses a heuristic,
|
||||
table in "wiretap/file_access.c" - if it uses a magic number, put
|
||||
it in the first section of that list, and, if it uses a heuristic,
|
||||
put it in the second section, preferably putting the heuristic
|
||||
routines for binary files before the heuristic routines for text
|
||||
files;
|
||||
|
||||
add an entry for that file type in the "dump_open_table_base[]" in
|
||||
"wiretap/file_access.c", giving a descriptive name, a short name
|
||||
"wiretap/file_access.c", giving a descriptive name, a short name
|
||||
that's convenient to type on a command line (no blanks or capital
|
||||
letters, please), common file extensions to open and save, a flag
|
||||
if it can be compressed with gzip (currently unused) and pointers
|
||||
to the "can_write_encap" and "dump_open" routines if writing that
|
||||
letters, please), common file extensions to open and save, a flag
|
||||
if it can be compressed with gzip (currently unused) and pointers
|
||||
to the "can_write_encap" and "dump_open" routines if writing that
|
||||
file is supported (see below), otherwise just null pointers.
|
||||
|
||||
Wiretap applications typically first perform sequential reads through
|
||||
the capture file and may later do "seek and read" for individual frames.
|
||||
the capture file and may later do "seek and read" for individual frames.
|
||||
The "read" routine should set the variable data_offset to the byte
|
||||
offset within the capture file from which the "seek and read" routine
|
||||
will read. If the capture records consist of:
|
||||
|
@ -58,9 +58,9 @@ will read. If the capture records consist of:
|
|||
|
||||
then data_offset should point to the pseudo-header. The first
|
||||
sequential read pass will process and store the capture record header
|
||||
data, but it will not store the pseudo-header. Note that the
|
||||
data, but it will not store the pseudo-header. Note that the
|
||||
seek_and_read routine should work with the "random_fh" file handle
|
||||
of the passed in wtap struct, instead of the "fh" file habndle used
|
||||
of the passed in wtap struct, instead of the "fh" file handle used
|
||||
in the normal read routine.
|
||||
|
||||
To add the ability to write a new capture file format, you have to:
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "dpa400.h"
|
||||
#include "rfc7468.h"
|
||||
#include "ruby_marshal.h"
|
||||
#include "systemd_journal.h"
|
||||
|
||||
/*
|
||||
* Add an extension, and all compressed versions thereof, to a GSList
|
||||
|
@ -405,7 +406,8 @@ static const struct open_info open_info_base[] = {
|
|||
{ "Ixia IxVeriWave .vwr Raw Capture", OPEN_INFO_HEURISTIC, vwr_open, "vwr", NULL, NULL },
|
||||
{ "CAM Inspector file", OPEN_INFO_HEURISTIC, camins_open, "camins", NULL, NULL },
|
||||
{ "JavaScript Object Notation", OPEN_INFO_HEURISTIC, json_open, "json", NULL, NULL },
|
||||
{ "Ruby Marshal Object", OPEN_INFO_HEURISTIC, ruby_marshal_open, "", NULL, NULL }
|
||||
{ "Ruby Marshal Object", OPEN_INFO_HEURISTIC, ruby_marshal_open, "", NULL, NULL },
|
||||
{ "Systemd Journal", OPEN_INFO_HEURISTIC, systemd_journal_open, "log;jnl;journal", NULL, NULL }
|
||||
};
|
||||
|
||||
/* this is only used to build the dynamic array on load, do NOT use this
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/* systemd_journal.c
|
||||
*
|
||||
* Wiretap Library
|
||||
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "wtap-int.h"
|
||||
#include "file_wrappers.h"
|
||||
#include "systemd_journal.h"
|
||||
|
||||
// To do:
|
||||
// - Request a pcap encapsulation type.
|
||||
// - Should we add separate types for binary, plain, and JSON or add a metadata header?
|
||||
|
||||
// Systemd journals are stored in the following formats:
|
||||
// Journal File Format (native binary): https://www.freedesktop.org/wiki/Software/systemd/journal-files/
|
||||
// Journal Export Format: https://www.freedesktop.org/wiki/Software/systemd/export/
|
||||
// Journal JSON format: https://www.freedesktop.org/wiki/Software/systemd/json/
|
||||
// This reads Journal Export Format files but could be extended to support
|
||||
// the binary and JSON formats.
|
||||
|
||||
// Example data:
|
||||
// __CURSOR=s=1d56bab64d414960b9907ab0cc7f7c62;i=2;b=1497926e8b4b4d3ca6a5805e157fa73c;m=5d0ae5;t=56f2f5b66ce6f;x=20cb01e28bb496a8
|
||||
// __REALTIME_TIMESTAMP=1529624071163503
|
||||
// __MONOTONIC_TIMESTAMP=6097637
|
||||
// _BOOT_ID=1497926e8b4b4d3ca6a5805e157fa73c
|
||||
// PRIORITY=6
|
||||
// _MACHINE_ID=62c342838a6e436dacea041aa4b5064b
|
||||
// _HOSTNAME=example.wireshark.org
|
||||
// _SOURCE_MONOTONIC_TIMESTAMP=0
|
||||
// _TRANSPORT=kernel
|
||||
// SYSLOG_FACILITY=0
|
||||
// SYSLOG_IDENTIFIER=kernel
|
||||
// MESSAGE=Initializing cgroup subsys cpuset
|
||||
|
||||
static gboolean systemd_journal_read(wtap *wth, int *err, gchar **err_info,
|
||||
gint64 *data_offset);
|
||||
static gboolean systemd_journal_seek_read(wtap *wth, gint64 seek_off,
|
||||
wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
|
||||
static gboolean systemd_journal_read_export_entry(FILE_T fh, wtap_rec *rec,
|
||||
Buffer *buf, int *err, gchar **err_info);
|
||||
|
||||
// The Journal Export Format specification doesn't place limits on entry
|
||||
// lengths or lines per entry. We do.
|
||||
#define MAX_EXPORT_ENTRY_LENGTH WTAP_MAX_PACKET_SIZE_STANDARD
|
||||
#define MAX_EXPORT_ENTRY_LINES 100
|
||||
|
||||
#define FLD__CURSOR "__CURSOR="
|
||||
#define FLD__REALTIME_TIMESTAMP "__REALTIME_TIMESTAMP="
|
||||
#define FLD__MONOTONIC_TIMESTAMP "__MONOTONIC_TIMESTAMP="
|
||||
|
||||
wtap_open_return_val systemd_journal_open(wtap *wth, int *err _U_, gchar **err_info _U_)
|
||||
{
|
||||
gchar *entry_buff = (gchar*) g_malloc(MAX_EXPORT_ENTRY_LENGTH);
|
||||
gchar *entry_line = NULL;
|
||||
gboolean got_cursor = FALSE;
|
||||
gboolean got_rt_ts = FALSE;
|
||||
gboolean got_mt_ts = FALSE;
|
||||
int line_num;
|
||||
|
||||
errno = 0;
|
||||
for (line_num = 0; line_num < MAX_EXPORT_ENTRY_LINES; line_num++) {
|
||||
entry_line = file_gets(entry_buff, MAX_EXPORT_ENTRY_LENGTH, wth->fh);
|
||||
if (!entry_line) {
|
||||
break;
|
||||
}
|
||||
if (entry_line[0] == '\n') {
|
||||
break;
|
||||
} else if (strncmp(entry_line, FLD__CURSOR, strlen(FLD__CURSOR)) == 0) {
|
||||
got_cursor = TRUE;
|
||||
} else if (strncmp(entry_line, FLD__REALTIME_TIMESTAMP, strlen(FLD__REALTIME_TIMESTAMP)) == 0) {
|
||||
got_rt_ts = TRUE;
|
||||
} else if (strncmp(entry_line, FLD__MONOTONIC_TIMESTAMP, strlen(FLD__MONOTONIC_TIMESTAMP)) == 0) {
|
||||
got_mt_ts = TRUE;
|
||||
}
|
||||
}
|
||||
g_free(entry_buff);
|
||||
|
||||
if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
|
||||
return WTAP_OPEN_ERROR;
|
||||
}
|
||||
|
||||
if (!got_cursor || !got_rt_ts || !got_mt_ts) {
|
||||
return WTAP_OPEN_NOT_MINE;
|
||||
}
|
||||
|
||||
wth->subtype_read = systemd_journal_read;
|
||||
wth->subtype_seek_read = systemd_journal_seek_read;
|
||||
wth->file_encap = WTAP_ENCAP_SYSTEMD_JOURNAL;
|
||||
wth->file_tsprec = WTAP_TSPREC_USEC;
|
||||
return WTAP_OPEN_MINE;
|
||||
}
|
||||
|
||||
/* Read the next packet */
|
||||
static gboolean systemd_journal_read(wtap *wth, int *err _U_, gchar **err_info,
|
||||
gint64 *data_offset)
|
||||
{
|
||||
*data_offset = file_tell(wth->fh);
|
||||
|
||||
/* Read record. */
|
||||
if (!systemd_journal_read_export_entry(wth->fh, &wth->rec, wth->rec_data, err, err_info)) {
|
||||
/* Read error or EOF */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
systemd_journal_seek_read(wtap *wth, gint64 seek_off,
|
||||
wtap_rec *rec, Buffer *buf,
|
||||
int *err, gchar **err_info)
|
||||
{
|
||||
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
|
||||
return FALSE;
|
||||
|
||||
/* Read record. */
|
||||
if (!systemd_journal_read_export_entry(wth->random_fh, rec, buf, err, err_info)) {
|
||||
/* Read error or EOF */
|
||||
if (*err == 0) {
|
||||
/* EOF means "short read" in random-access mode */
|
||||
*err = WTAP_ERR_SHORT_READ;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
systemd_journal_read_export_entry(FILE_T fh, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
|
||||
{
|
||||
size_t fld_end = 0;
|
||||
gchar *entry_buff = (gchar*) g_malloc(MAX_EXPORT_ENTRY_LENGTH);
|
||||
gchar *entry_line = NULL;
|
||||
gboolean got_cursor = FALSE;
|
||||
gboolean got_rt_ts = FALSE;
|
||||
gboolean got_mt_ts = FALSE;
|
||||
gboolean got_double_newline = FALSE;
|
||||
int line_num;
|
||||
size_t rt_ts_len = strlen(FLD__REALTIME_TIMESTAMP);
|
||||
|
||||
for (line_num = 0; line_num < MAX_EXPORT_ENTRY_LINES; line_num++) {
|
||||
entry_line = file_gets(entry_buff + fld_end, MAX_EXPORT_ENTRY_LENGTH - (int) fld_end, fh);
|
||||
if (!entry_line) {
|
||||
break;
|
||||
}
|
||||
fld_end += strlen(entry_line);
|
||||
if (entry_line[0] == '\n') {
|
||||
got_double_newline = TRUE;
|
||||
break;
|
||||
} else if (strncmp(entry_line, FLD__CURSOR, strlen(FLD__CURSOR)) == 0) {
|
||||
got_cursor = TRUE;
|
||||
} else if (strncmp(entry_line, FLD__REALTIME_TIMESTAMP, rt_ts_len) == 0) {
|
||||
errno = 0;
|
||||
unsigned long rt_ts = strtoul(entry_line+rt_ts_len, NULL, 10);
|
||||
if (!errno) {
|
||||
rec->ts.secs = (time_t) rt_ts / 1000000;
|
||||
rec->ts.nsecs = (rt_ts % 1000000) * 1000;
|
||||
rec->tsprec = WTAP_TSPREC_USEC;
|
||||
got_rt_ts = TRUE;
|
||||
}
|
||||
} else if (strncmp(entry_line, FLD__MONOTONIC_TIMESTAMP, strlen(FLD__MONOTONIC_TIMESTAMP)) == 0) {
|
||||
got_mt_ts = TRUE;
|
||||
} else if (!strstr(entry_line, "=")) {
|
||||
// Start of binary data.
|
||||
if (fld_end >= MAX_EXPORT_ENTRY_LENGTH - 8) {
|
||||
*err = WTAP_ERR_BAD_FILE;
|
||||
*err_info = g_strdup_printf("systemd: binary length too long");
|
||||
return FALSE;
|
||||
}
|
||||
guint64 data_len, le_data_len;
|
||||
if (!wtap_read_bytes(fh, &le_data_len, 8, err, err_info)) {
|
||||
return FALSE;
|
||||
}
|
||||
memcpy(entry_buff + fld_end, &le_data_len, 8);
|
||||
fld_end += 8;
|
||||
data_len = pletoh64(&le_data_len);
|
||||
if (data_len < 1 || data_len - 1 >= MAX_EXPORT_ENTRY_LENGTH - fld_end) {
|
||||
*err = WTAP_ERR_BAD_FILE;
|
||||
*err_info = g_strdup_printf("systemd: binary data too long");
|
||||
return FALSE;
|
||||
}
|
||||
// Data + trailing \n
|
||||
if (!wtap_read_bytes(fh, entry_buff + fld_end, (unsigned) data_len + 1, err, err_info)) {
|
||||
return FALSE;
|
||||
}
|
||||
fld_end += data_len + 1;
|
||||
}
|
||||
if (MAX_EXPORT_ENTRY_LENGTH < fld_end + 2) { // \n\0
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!got_cursor || !got_rt_ts || !got_mt_ts) {
|
||||
g_free(entry_buff);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!got_double_newline && !file_eof(fh)) {
|
||||
g_free(entry_buff);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rec->rec_type = REC_TYPE_PACKET;
|
||||
rec->presence_flags = WTAP_HAS_TS;
|
||||
rec->rec_header.packet_header.caplen = (guint32) fld_end;
|
||||
rec->rec_header.packet_header.len = rec->rec_header.packet_header.caplen;
|
||||
|
||||
ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen + 1);
|
||||
guint8 *pd = ws_buffer_start_ptr(buf);
|
||||
entry_buff[fld_end+1] = '\0';
|
||||
memcpy(pd, entry_buff, rec->rec_header.packet_header.caplen + 1);
|
||||
g_free(entry_buff);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -0,0 +1,19 @@
|
|||
/* systemd_journal.h
|
||||
*
|
||||
* Wiretap Library
|
||||
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SYSTEMD_JOURNAL_H__
|
||||
#define __SYSTEMD_JOURNAL_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "wtap.h"
|
||||
#include "ws_symbol_export.h"
|
||||
|
||||
wtap_open_return_val systemd_journal_open(wtap *wth, int *err, gchar **err_info);
|
||||
|
||||
#endif // __SYSTEMD_JOURNAL_H__
|
|
@ -283,6 +283,7 @@ extern "C" {
|
|||
#define WTAP_ENCAP_DPAUXMON 200
|
||||
#define WTAP_ENCAP_RUBY_MARSHAL 201
|
||||
#define WTAP_ENCAP_RFC7468 202
|
||||
#define WTAP_ENCAP_SYSTEMD_JOURNAL 203
|
||||
|
||||
/* After adding new item here, please also add new item to encap_table_base array */
|
||||
|
||||
|
@ -377,6 +378,7 @@ extern "C" {
|
|||
#define WTAP_FILE_TYPE_SUBTYPE_DPA400 81
|
||||
#define WTAP_FILE_TYPE_SUBTYPE_RFC7468 82
|
||||
#define WTAP_FILE_TYPE_SUBTYPE_RUBY_MARSHAL 83
|
||||
#define WTAP_FILE_TYPE_SUBTYPE_SYSTEMD_JOURNAL 84
|
||||
|
||||
#define WTAP_NUM_FILE_TYPES_SUBTYPES wtap_get_num_file_types_subtypes()
|
||||
|
||||
|
|
Loading…
Reference in New Issue