wireshark/epan/dissectors/packet-zabbix.c

1108 lines
48 KiB
C

/* packet-zabbix.c
* Routines for Zabbix protocol dissection
* Copyright 2023, Markku Leiniö <markku.leinio@gmail.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/*
* Zabbix protocol specifications can be found in Zabbix documentation:
* https://www.zabbix.com/documentation/current/en/manual/appendix/protocols
*/
#include "config.h"
#include <epan/conversation.h>
#include <epan/expert.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <wsutil/inet_addr.h>
#include <wsutil/nstime.h>
#include <wsutil/wsjson.h>
#include "packet-tcp.h"
void proto_register_zabbix(void);
void proto_reg_handoff_zabbix(void);
static dissector_handle_t zabbix_handle;
/* Desegmentation of Zabbix protocol over TCP */
static gboolean zabbix_desegment = true;
/* Initialize the protocol and registered fields */
static int proto_zabbix;
static int hf_zabbix_header;
static int hf_zabbix_flags;
static int hf_zabbix_flag_zabbix_communications;
static int hf_zabbix_flag_compressed;
static int hf_zabbix_flag_largepacket;
static int hf_zabbix_flag_reserved;
static int hf_zabbix_length;
static int hf_zabbix_reserved;
static int hf_zabbix_uncompressed_length;
static int hf_zabbix_large_length;
static int hf_zabbix_large_reserved;
static int hf_zabbix_large_uncompressed_length;
static int hf_zabbix_data;
static int hf_zabbix_time;
static int hf_zabbix_agent;
static int hf_zabbix_agent_config;
static int hf_zabbix_agent_data;
static int hf_zabbix_agent_passive;
static int hf_zabbix_agent_name;
static int hf_zabbix_agent_hb;
static int hf_zabbix_agent_hb_freq;
static int hf_zabbix_agent_hostmetadata;
static int hf_zabbix_agent_hostinterface;
static int hf_zabbix_agent_listenipv4;
static int hf_zabbix_agent_listenipv6;
static int hf_zabbix_agent_listenport;
static int hf_zabbix_proxy;
static int hf_zabbix_proxy_hb;
static int hf_zabbix_proxy_name;
static int hf_zabbix_proxy_data;
static int hf_zabbix_proxy_config;
static int hf_zabbix_proxy_fullsync;
static int hf_zabbix_proxy_incr_config;
static int hf_zabbix_proxy_no_config_change;
static int hf_zabbix_sender;
static int hf_zabbix_sender_name;
static int hf_zabbix_request;
static int hf_zabbix_response;
static int hf_zabbix_success;
static int hf_zabbix_failed;
static int hf_zabbix_config_revision;
static int hf_zabbix_session;
static int hf_zabbix_version;
/* Initialize the subtree pointers */
static int ett_zabbix;
/* Initialize expert fields */
static expert_field ei_zabbix_packet_too_large;
static expert_field ei_zabbix_json_error;
/* Other dissector-specifics */
static range_t *zabbix_port_range;
static const guint8 ZABBIX_HDR_SIGNATURE[] = "ZBXD";
static const char ZABBIX_UNKNOWN[] = "<unknown>";
typedef struct _zabbix_conv_info_t {
guint32 req_framenum;
nstime_t req_timestamp;
uint16_t oper_flags; /* ZABBIX_T_XXX macros below */
const guint8 *host_name;
} zabbix_conv_info_t;
#define ZABBIX_HDR_MIN_LEN 13 /* When not large packet */
#define ZABBIX_HDR_MAX_LEN 21 /* When large packet */
#define ZABBIX_MAX_LENGTH_ALLOWED 1024*1024*1024 /* 1 GB */
#define ZABBIX_TCP_PORTS "10050,10051" /* IANA registered ports */
#define ZABBIX_FLAG_ZABBIX_COMMUNICATIONS 0x01
#define ZABBIX_FLAG_COMPRESSED 0x02
#define ZABBIX_FLAG_LARGEPACKET 0x04
#define ZABBIX_FLAG_RESERVED 0xf8
/* Response flags are not saved in the conversations */
#define ZABBIX_RESPONSE_SUCCESS 0x01
#define ZABBIX_RESPONSE_FAILED 0x02
#define ZABBIX_RESPONSE_FULLSYNC 0x04
#define ZABBIX_RESPONSE_INCREMENTAL 0x08
#define ZABBIX_RESPONSE_NOCHANGE 0x10
/* Flags for saving and comparing operation types,
* max 16 bits as defined in zabbix_conv_info_t above */
#define ZABBIX_T_REQUEST 0x00000001 /* Not set for heartbeats */
#define ZABBIX_T_RESPONSE 0x00000002
#define ZABBIX_T_ACTIVE 0x00000004
#define ZABBIX_T_PASSIVE 0x00000008
#define ZABBIX_T_AGENT 0x00000010
#define ZABBIX_T_PROXY 0x00000020
#define ZABBIX_T_SENDER 0x00000040
#define ZABBIX_T_CONFIG 0x00000080
#define ZABBIX_T_DATA 0x00000100
#define ZABBIX_T_HEARTBEAT 0x00000200
#define ADD_ZABBIX_T_FLAGS(flags) (zabbix_info->oper_flags |= (flags))
#define CLEAR_ZABBIX_T_FLAGS(flags) (zabbix_info->oper_flags &= (0xffff-(flags)))
#define IS_ZABBIX_T_FLAGS(flags) ((zabbix_info->oper_flags & (flags)) == (flags))
#define CONV_IS_ZABBIX_REQUEST(zabbix_info,pinfo) ((zabbix_info)->req_framenum == (pinfo)->fd->num)
#define CONV_IS_ZABBIX_RESPONSE(zabbix_info,pinfo) ((zabbix_info)->req_framenum != (pinfo)->fd->num)
static zabbix_conv_info_t*
zabbix_find_conversation_and_get_conv_data(packet_info *pinfo)
{
conversation_t *conversation;
zabbix_conv_info_t *zabbix_info = NULL;
conversation = find_conversation_pinfo(pinfo, 0);
if (conversation) {
zabbix_info = (zabbix_conv_info_t *)conversation_get_proto_data(conversation, proto_zabbix);
} else {
conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
conversation_pt_to_conversation_type(pinfo->ptype),
pinfo->srcport, pinfo->destport, 0);
}
if (!zabbix_info) {
/* New conversation, or there was no Zabbix data yet in the existing conv */
zabbix_info = wmem_alloc(wmem_file_scope(), sizeof(zabbix_conv_info_t));
if (value_is_in_range(zabbix_port_range, pinfo->destport)) {
/* Let's assume this is the first Zabbix packet (request) */
zabbix_info->req_framenum = pinfo->fd->num;
zabbix_info->req_timestamp = pinfo->abs_ts;
}
else {
/* For any reason we didn't have Zabbix data yet but this is not
* the first packet for the connection, so don't save it as a request
*/
zabbix_info->req_framenum = 0;
nstime_set_unset(&zabbix_info->req_timestamp);
/* For some reason this produces "syntax error: '{'" when compiling:
zabbix_info->req_timestamp = NSTIME_INIT_UNSET;
*/
}
zabbix_info->oper_flags = 0;
zabbix_info->host_name = NULL;
conversation_add_proto_data(conversation, proto_zabbix, (void *)zabbix_info);
}
return zabbix_info;
}
static void
zabbix_add_expert_info_if_too_large(packet_info *pinfo, proto_tree *tree_item,
uint64_t length, bool *is_too_large)
{
if (length > ZABBIX_MAX_LENGTH_ALLOWED) {
expert_add_info(pinfo, tree_item, &ei_zabbix_packet_too_large);
*is_too_large = true;
}
return;
}
static int
dissect_zabbix_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
int offset = 0;
int agent_hb_freq = 0;
unsigned oper_response = 0;
proto_item *ti;
proto_item *pi;
proto_tree *temp_ti;
proto_tree *zabbix_tree = NULL;
uint8_t flags;
uint16_t agent_listenport = 0;
uint64_t length;
uint64_t uncompressed_length;
uint64_t datalen;
int64_t config_revision = -1;
bool is_compressed;
bool is_large_packet;
bool is_too_large = false;
char *json_str;
jsmntok_t *data_array = NULL;
jsmntok_t *data_object = NULL;
const char *agent_name = NULL;
const char *agent_hostmetadata = NULL;
const char *agent_hostinterface = NULL;
const char *agent_listenip = NULL;
const char *proxy_name = NULL;
const char *sender_name = NULL;
const char *session = NULL;
const char *request_type = NULL;
const char *response_status = NULL;
const char *version = NULL;
gdouble temp_double;
tvbuff_t *next_tvb;
zabbix_conv_info_t *zabbix_info;
static int* const flagbits[] = {
&hf_zabbix_flag_reserved,
&hf_zabbix_flag_largepacket,
&hf_zabbix_flag_compressed,
&hf_zabbix_flag_zabbix_communications,
NULL
};
/* Make entries in Protocol column and Info column on summary display */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Zabbix");
col_clear(pinfo->cinfo, COL_INFO);
if ((tvb_reported_length(tvb) < ZABBIX_HDR_MIN_LEN) ||
(tvb_memeql(tvb, offset, ZABBIX_HDR_SIGNATURE, 4) == -1)) {
/* Encrypted or not Zabbix at all */
return 0;
}
flags = tvb_get_guint8(tvb, offset+4);
if (!(flags & ZABBIX_FLAG_ZABBIX_COMMUNICATIONS)) {
return 0;
}
zabbix_info = zabbix_find_conversation_and_get_conv_data(pinfo);
is_compressed = (flags & ZABBIX_FLAG_COMPRESSED) > 0;
is_large_packet = (flags & ZABBIX_FLAG_LARGEPACKET) > 0;
/* create display subtree for the protocol */
ti = proto_tree_add_item(tree, proto_zabbix, tvb, 0, -1, ENC_NA);
zabbix_tree = proto_item_add_subtree(ti, ett_zabbix);
proto_tree_add_item(zabbix_tree, hf_zabbix_header, tvb, offset, 4, ENC_UTF_8);
offset += 4;
proto_tree_add_bitmask(zabbix_tree, tvb, offset, hf_zabbix_flags, ett_zabbix, flagbits, ENC_BIG_ENDIAN);
offset += 1;
if (is_large_packet) {
/* 8-byte values */
temp_ti = proto_tree_add_item_ret_uint64(zabbix_tree,
hf_zabbix_large_length, tvb, offset, 8, ENC_LITTLE_ENDIAN, &length);
zabbix_add_expert_info_if_too_large(pinfo, temp_ti, length, &is_too_large);
offset += 8;
if (is_compressed) {
temp_ti = proto_tree_add_item_ret_uint64(zabbix_tree,
hf_zabbix_large_uncompressed_length, tvb, offset, 8, ENC_LITTLE_ENDIAN, &uncompressed_length);
zabbix_add_expert_info_if_too_large(pinfo, temp_ti, uncompressed_length, &is_too_large);
} else {
proto_tree_add_item(zabbix_tree, hf_zabbix_large_reserved, tvb, offset, 8, ENC_LITTLE_ENDIAN);
}
offset += 8;
} else {
/* 4-byte values */
uint32_t temp_uint32;
temp_ti = proto_tree_add_item_ret_uint(zabbix_tree,
hf_zabbix_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &temp_uint32);
length = (uint64_t)temp_uint32;
zabbix_add_expert_info_if_too_large(pinfo, temp_ti, length, &is_too_large);
offset += 4;
if (is_compressed) {
temp_ti = proto_tree_add_item_ret_uint(zabbix_tree,
hf_zabbix_uncompressed_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &temp_uint32);
uncompressed_length = (uint64_t)temp_uint32;
zabbix_add_expert_info_if_too_large(pinfo, temp_ti, uncompressed_length, &is_too_large);
} else {
proto_tree_add_item(zabbix_tree, hf_zabbix_reserved, tvb, offset, 4, ENC_LITTLE_ENDIAN);
}
offset += 4;
}
if (is_too_large) {
/* Set next_tvb for response time calculation to work later */
next_tvb = tvb_new_subset_remaining(tvb, offset);
/* ... but don't do any content-based inspection, just skip to the end */
goto final_outputs;
} else if (is_compressed) {
next_tvb = tvb_uncompress(tvb, offset, tvb_reported_length_remaining(tvb, offset));
if (next_tvb) {
tvb_set_child_real_data_tvbuff(tvb, next_tvb);
add_new_data_source(pinfo, next_tvb, "Uncompressed data");
datalen = uncompressed_length;
} else {
/* Handle uncompressed */
next_tvb = tvb_new_subset_remaining(tvb, offset);
datalen = length;
}
} else {
next_tvb = tvb_new_subset_remaining(tvb, offset);
datalen = length;
}
/* Use only next_tvb and datalen for data extraction from here on! */
offset = 0;
/* Rewrite the default texts in the protocol tree and initialize request/response flags */
if (CONV_IS_ZABBIX_REQUEST(zabbix_info, pinfo)) {
proto_item_set_text(ti, "Zabbix Protocol request");
ADD_ZABBIX_T_FLAGS(ZABBIX_T_REQUEST);
CLEAR_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE);
}
else if (CONV_IS_ZABBIX_RESPONSE(zabbix_info, pinfo)) {
proto_item_set_text(ti, "Zabbix Protocol response");
ADD_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE);
CLEAR_ZABBIX_T_FLAGS(ZABBIX_T_REQUEST);
}
/*
* Note that json_str is modified when using json_get_xxx() functions below!
* So don't use it to anything else (make a wmem_strdup() if needed)
*/
json_str = tvb_get_string_enc(pinfo->pool, next_tvb, offset, (int)datalen, ENC_UTF_8);
if (CONV_IS_ZABBIX_REQUEST(zabbix_info, pinfo) && !json_validate(json_str, datalen)) {
/* The only non-JSON Zabbix request is passive agent, update the conversation data */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_AGENT | ZABBIX_T_PASSIVE);
}
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_AGENT | ZABBIX_T_PASSIVE)) {
if (CONV_IS_ZABBIX_REQUEST(zabbix_info, pinfo)) {
proto_item_set_text(ti, "Zabbix Passive agent request");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive agent request");
} else if (CONV_IS_ZABBIX_RESPONSE(zabbix_info, pinfo)) {
proto_item_set_text(ti, "Zabbix Passive agent response");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive agent response");
}
/* Don't do content-based searches for passive agents */
goto show_agent_outputs;
}
/* Parse JSON, first get the token count */
int token_count = json_parse(json_str, NULL, 0);
if (token_count <= 0) {
temp_ti = proto_tree_add_item(zabbix_tree, hf_zabbix_data, next_tvb, 0, (int)datalen, ENC_UTF_8);
expert_add_info_format(pinfo, temp_ti, &ei_zabbix_json_error, "Error in initial JSON parse");
goto final_outputs;
}
jsmntok_t *tokens = wmem_alloc_array(pinfo->pool, jsmntok_t, token_count);
int ret = json_parse(json_str, tokens, token_count);
if (ret <= 0) {
temp_ti = proto_tree_add_item(zabbix_tree, hf_zabbix_data, next_tvb, 0, (int)datalen, ENC_UTF_8);
expert_add_info_format(pinfo, temp_ti, &ei_zabbix_json_error, "Error parsing JSON tokens");
goto final_outputs;
}
/*
* Now we have JSON tokens analyzed, let's do all the logic to populate the fields.
* Also set Zabbix tree item and Info column texts, Len= and ports will be added later below.
*/
/* First populate common fields */
version = json_get_string(json_str, tokens, "version");
session = json_get_string(json_str, tokens, "session");
if (json_get_double(json_str, tokens, "config_revision", &temp_double)) {
config_revision = (int64_t)temp_double;
}
request_type = json_get_string(json_str, tokens, "request");
response_status = json_get_string(json_str, tokens, "response");
data_array = json_get_array(json_str, tokens, "data");
data_object = json_get_object(json_str, tokens, "data");
if (request_type) {
if (strcmp(request_type, "active checks") == 0) {
/* Active agent requesting configs */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_AGENT | ZABBIX_T_CONFIG | ZABBIX_T_ACTIVE);
agent_name = json_get_string(json_str, tokens, "host");
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), agent_name);
proto_item_set_text(ti,
"Zabbix Request for active checks for \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Request for active checks for \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
agent_hostmetadata = json_get_string(json_str, tokens, "host_metadata");
agent_hostinterface = json_get_string(json_str, tokens, "interface");
agent_listenip = json_get_string(json_str, tokens, "ip");
if (json_get_double(json_str, tokens, "port", &temp_double)) {
agent_listenport = (uint16_t)temp_double;
}
}
else if (strcmp(request_type, "agent data") == 0) {
/* Active agent sending data */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_AGENT | ZABBIX_T_DATA | ZABBIX_T_ACTIVE);
/* Zabbix Agent 2 has Host in the top level */
agent_name = json_get_string(json_str, tokens, "host");
if (!agent_name) {
/* For Zabbix Agent try parsing agent name inside data array */
jsmntok_t *tok = json_get_array(json_str, tokens, "data");
if (tok && json_get_array_len(tok) > 0) {
jsmntok_t *datatok = json_get_array_index(tok, 0);
agent_name = json_get_string(json_str, datatok, "host");
}
}
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), agent_name);
proto_item_set_text(ti,
"Zabbix Send agent data from \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Send agent data from \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
}
else if (strcmp(request_type, "active check heartbeat") == 0) {
/* Active agent sending heartbeat */
/* Clear the request flag first */
zabbix_info->oper_flags = 0;
ADD_ZABBIX_T_FLAGS(ZABBIX_T_AGENT | ZABBIX_T_HEARTBEAT | ZABBIX_T_ACTIVE);
agent_name = json_get_string(json_str, tokens, "host");
if (json_get_double(json_str, tokens, "heartbeat_freq", &temp_double)) {
agent_hb_freq = (int)temp_double;
}
proto_item_set_text(ti,
"Zabbix Agent heartbeat from \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Agent heartbeat from \"%s\"", (agent_name ? agent_name : ZABBIX_UNKNOWN));
}
else if (strcmp(request_type, "sender data") == 0) {
/* Sender/trapper */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_SENDER);
/* Try to get the sender name from the first data array item */
jsmntok_t *tok = json_get_array(json_str, tokens, "data");
if (tok && json_get_array_len(tok) > 0) {
jsmntok_t *datatok = json_get_array_index(tok, 0);
sender_name = json_get_string(json_str, datatok, "host");
}
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), sender_name);
proto_item_set_text(ti,
"Zabbix Sender data from \"%s\"", (sender_name ? sender_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Sender data from \"%s\"", (sender_name ? sender_name : ZABBIX_UNKNOWN));
}
else if ((strcmp(request_type, "proxy data") == 0) ||
(strcmp(request_type, "host availability") == 0) ||
(strcmp(request_type, "history data") == 0) ||
(strcmp(request_type, "discovery data") == 0) ||
(strcmp(request_type, "auto registration") == 0)) {
/* Either active or passive proxy; "proxy data" = Zabbix 3.4+,
* others = Zabbix 3.2 or older */
proxy_name = json_get_string(json_str, tokens, "host");
if (token_count == 3) { /* Only '{"request":"xxx"}' */
/* This is Zabbix server connecting to passive proxy */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_DATA | ZABBIX_T_PASSIVE);
proto_item_set_text(ti, "Zabbix Request for passive proxy data");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Request for passive proxy data");
}
else if (proxy_name) {
/* This is an active proxy connecting to server */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_DATA | ZABBIX_T_ACTIVE);
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), proxy_name);
proto_item_set_text(ti, "Zabbix Proxy data from \"%s\"", proxy_name);
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Proxy data from \"%s\"", proxy_name);
}
}
else if (strcmp(request_type, "proxy config") == 0) {
/* Either active or passive proxy */
proxy_name = json_get_string(json_str, tokens, "host");
if (token_count == 3) { /* Only '{"request":"proxy config"}' */
/* This is Zabbix 6.4+ server connecting to passive proxy */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG | ZABBIX_T_PASSIVE);
proto_item_set_text(ti, "Zabbix Start send proxy config to passive proxy");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Start send proxy config to passive proxy");
}
else if (proxy_name) {
/* This is an active proxy connecting to server */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG | ZABBIX_T_ACTIVE);
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), proxy_name);
proto_item_set_text(ti, "Zabbix Request proxy config for \"%s\"", proxy_name);
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Request proxy config for \"%s\"", proxy_name);
}
}
else if (strcmp(request_type, "proxy heartbeat") == 0) {
/* Heartbeat from active proxy, not used in Zabbix 6.4+ */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_HEARTBEAT | ZABBIX_T_ACTIVE);
proxy_name = json_get_string(json_str, tokens, "host");
zabbix_info->host_name = wmem_strdup(wmem_file_scope(), proxy_name);
proto_item_set_text(ti, "Zabbix Proxy heartbeat from \"%s\"", proxy_name);
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Proxy heartbeat from \"%s\"", proxy_name);
}
}
else if (json_get_object(json_str, tokens, "globalmacro")) {
/* This is Zabbix server before 6.4 sending configurations to active proxy */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG | ZABBIX_T_ACTIVE);
proxy_name = zabbix_info->host_name;
proto_item_set_text(ti,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
}
else if (json_get_double(json_str, tokens, "full_sync", &temp_double)) {
/* This is Zabbix 6.4+ server sending proxy config to active or passive proxy */
/* Only present when value is 1 */
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG);
oper_response |= ZABBIX_RESPONSE_FULLSYNC;
/* Active/passive flag was set in the earlier packet */
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PASSIVE)) {
/* There is no proxy name anywhere to use */
proto_item_set_text(ti, "Zabbix Passive proxy config");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive proxy config");
}
else {
proxy_name = zabbix_info->host_name;
proto_item_set_text(ti,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
}
}
else if (response_status) {
if (strcmp(response_status, "success") == 0) {
oper_response |= ZABBIX_RESPONSE_SUCCESS;
}
else if (strcmp(response_status, "failed") == 0) {
oper_response |= ZABBIX_RESPONSE_FAILED;
}
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_AGENT)) {
agent_name = zabbix_info->host_name;
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_CONFIG | ZABBIX_T_ACTIVE)) {
proto_item_set_text(ti,
"Zabbix Response for active checks for \"%s\" (%s)", (agent_name ? agent_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for active checks for \"%s\" (%s)", (agent_name ? agent_name : ZABBIX_UNKNOWN), response_status);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_DATA | ZABBIX_T_ACTIVE)) {
proto_item_set_text(ti,
"Zabbix Response for agent data for \"%s\" (%s)", (agent_name ? agent_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for agent data for \"%s\" (%s)", (agent_name ? agent_name : ZABBIX_UNKNOWN), response_status);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PROXY)) {
proxy_name = zabbix_info->host_name;
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_CONFIG | ZABBIX_T_ACTIVE)) {
proto_item_set_text(ti,
"Zabbix Response for active proxy config request for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for active proxy config request for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_DATA | ZABBIX_T_ACTIVE)) {
proto_item_set_text(ti,
"Zabbix Response for active proxy data for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for active proxy data for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_CONFIG | ZABBIX_T_PASSIVE)) {
proto_item_set_text(ti,
"Zabbix Response for passive proxy config (%s)", response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for passive proxy config (%s)", response_status);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_DATA | ZABBIX_T_PASSIVE)) {
proto_item_set_text(ti,
"Zabbix Response for passive proxy data (%s)", response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for passive proxy data (%s)", response_status);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_HEARTBEAT | ZABBIX_T_ACTIVE)) {
proto_item_set_text(ti,
"Zabbix Response for active proxy heartbeat for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for active proxy heartbeat for \"%s\" (%s)", (proxy_name ? proxy_name : ZABBIX_UNKNOWN), response_status);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_SENDER)) {
sender_name = zabbix_info->host_name;
proto_item_set_text(ti,
"Zabbix Response for sender data for \"%s\" (%s)", (sender_name ? sender_name : ZABBIX_UNKNOWN), response_status);
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for sender data for \"%s\" (%s)", (sender_name ? sender_name : ZABBIX_UNKNOWN), response_status);
}
}
else if (data_object || data_array) {
/* No other match above, let's assume this is server sending incremental
* configuration to a proxy
*/
ADD_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG);
if (data_object && (data_object->size == 0)) {
/* Empty data object */
oper_response |= ZABBIX_RESPONSE_NOCHANGE;
}
else if (data_array) {
/* This was not a "full_sync" but data array exists */
oper_response |= ZABBIX_RESPONSE_INCREMENTAL;
}
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PASSIVE)) {
/* There is no proxy name anywhere to use */
proto_item_set_text(ti, "Zabbix Passive proxy config");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive proxy config");
}
else {
proxy_name = zabbix_info->host_name;
proto_item_set_text(ti,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
col_add_fstr(pinfo->cinfo, COL_INFO,
"Zabbix Response for proxy config for \"%s\"", (proxy_name ? proxy_name : ZABBIX_UNKNOWN));
}
}
else if (session && version) {
/* Last guesses: responses from passive proxy */
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_CONFIG | ZABBIX_T_PASSIVE)) {
proto_item_set_text(ti, "Zabbix Passive proxy response for config push");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive proxy response for config push");
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PROXY | ZABBIX_T_DATA | ZABBIX_T_PASSIVE)) {
proto_item_set_text(ti, "Zabbix Passive proxy data response");
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Passive proxy data response");
}
}
/* Add all relevant fields to the tree */
show_agent_outputs:
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_AGENT)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_agent, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "This is an agent connection");
proto_item_set_generated(temp_ti);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_DATA)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_agent_data, NULL, 0, 0, true);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE)) {
/* Set as generated, not seen in data */
proto_item_set_generated(temp_ti);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_CONFIG)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_agent_config, NULL, 0, 0, true);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE)) {
/* Set as generated, not seen in data */
proto_item_set_generated(temp_ti);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_HEARTBEAT)) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_agent_hb, NULL, 0, 0, true);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PASSIVE)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_agent_passive, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "Agent is in passive mode");
proto_item_set_generated(temp_ti);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PROXY)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "This is a proxy connection");
proto_item_set_generated(temp_ti);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_SENDER)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_sender, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "This is a sender connection");
proto_item_set_generated(temp_ti);
}
if (oper_response & ZABBIX_RESPONSE_SUCCESS) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_success, NULL, 0, 0, true);
}
else if (oper_response & ZABBIX_RESPONSE_FAILED) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_failed, NULL, 0, 0, true);
}
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_AGENT)) {
if (agent_name) {
temp_ti = proto_tree_add_string(zabbix_tree, hf_zabbix_agent_name, NULL, 0, 0, agent_name);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE)) {
/* agent_name was populated from the conversation */
proto_item_set_generated(temp_ti);
proto_item_append_text(temp_ti, " (from the request)");
}
}
if (agent_hb_freq) {
proto_tree_add_int(zabbix_tree, hf_zabbix_agent_hb_freq, NULL, 0, 0, agent_hb_freq);
}
if (agent_hostmetadata) {
proto_tree_add_string(zabbix_tree, hf_zabbix_agent_hostmetadata, NULL, 0, 0, agent_hostmetadata);
}
if (agent_hostinterface) {
proto_tree_add_string(zabbix_tree, hf_zabbix_agent_hostinterface, NULL, 0, 0, agent_hostinterface);
}
if (agent_listenip) {
if (strstr(agent_listenip, ":") != NULL) {
ws_in6_addr addr6;
if (ws_inet_pton6(agent_listenip, &addr6)) {
proto_tree_add_ipv6(zabbix_tree, hf_zabbix_agent_listenipv6, NULL, 0, 0, &addr6);
}
}
else {
ws_in4_addr addr4;
if (ws_inet_pton4(agent_listenip, &addr4)) {
proto_tree_add_ipv4(zabbix_tree, hf_zabbix_agent_listenipv4, NULL, 0, 0, addr4);
}
}
}
if (agent_listenport) {
proto_tree_add_uint(zabbix_tree, hf_zabbix_agent_listenport, NULL, 0, 0, agent_listenport);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_PROXY)) {
if (proxy_name) {
temp_ti = proto_tree_add_string(zabbix_tree, hf_zabbix_proxy_name, NULL, 0, 0, proxy_name);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE)) {
/* proxy_name was populated from the conversation */
proto_item_set_generated(temp_ti);
proto_item_append_text(temp_ti, " (from the request)");
}
}
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_DATA)) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_data, NULL, 0, 0, true);
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_CONFIG)) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_config, NULL, 0, 0, true);
if (oper_response & ZABBIX_RESPONSE_FULLSYNC) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_fullsync, NULL, 0, 0, true);
}
else if (oper_response & ZABBIX_RESPONSE_INCREMENTAL) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_incr_config, NULL, 0, 0, true);
}
else if (oper_response & ZABBIX_RESPONSE_NOCHANGE) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_no_config_change, NULL, 0, 0, true);
}
}
else if (IS_ZABBIX_T_FLAGS(ZABBIX_T_HEARTBEAT)) {
proto_tree_add_boolean(zabbix_tree, hf_zabbix_proxy_hb, NULL, 0, 0, true);
}
}
else if (sender_name) {
temp_ti = proto_tree_add_string(zabbix_tree, hf_zabbix_sender_name, NULL, 0, 0, sender_name);
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_RESPONSE)) {
/* sender_name was populated from the conversation */
proto_item_set_generated(temp_ti);
proto_item_append_text(temp_ti, " (from the request)");
}
}
if (version) {
proto_tree_add_string(zabbix_tree, hf_zabbix_version, NULL, 0, 0, version);
}
if (config_revision > -1) {
proto_tree_add_int64(zabbix_tree, hf_zabbix_config_revision, NULL, 0, 0, config_revision);
}
if (session) {
proto_tree_add_string(zabbix_tree, hf_zabbix_session, NULL, 0, 0, session);
}
/* Show also the full JSON (or passive agent request/response) */
proto_tree_add_item(zabbix_tree, hf_zabbix_data, next_tvb, 0, (int)datalen, ENC_UTF_8);
final_outputs:
/* These are common for all cases, too large or not */
/* Check the ZABBIX_T_REQUEST flag (and not CONV_IS_ZABBIX_REQUEST macro) because
* heartbeats are not marked as requests */
if (IS_ZABBIX_T_FLAGS(ZABBIX_T_REQUEST)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_request, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "This is Zabbix request");
} else if (CONV_IS_ZABBIX_RESPONSE(zabbix_info, pinfo)) {
temp_ti = proto_tree_add_boolean(zabbix_tree, hf_zabbix_response, NULL, 0, 0, true);
proto_item_set_text(temp_ti, "This is Zabbix response");
if (!nstime_is_unset(&zabbix_info->req_timestamp)) {
nstime_t delta;
nstime_delta(&delta, &pinfo->abs_ts, &zabbix_info->req_timestamp);
pi = proto_tree_add_time(zabbix_tree, hf_zabbix_time, next_tvb, 0, 0, &delta);
proto_item_set_generated(pi);
}
}
/* Add length to the Zabbix tree text */
proto_item_append_text(ti, ", Len=%u", (unsigned)length);
/* Add/set Info column texts */
const gchar *info_text = col_get_text(pinfo->cinfo, COL_INFO);
if (!info_text || !strlen(info_text)) {
/* Info column is still empty, set the default text */
if (CONV_IS_ZABBIX_REQUEST(zabbix_info, pinfo)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Protocol request, Flags=0x%02x", flags);
} else if (CONV_IS_ZABBIX_RESPONSE(zabbix_info, pinfo)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Protocol response, Flags=0x%02x", flags);
} else {
col_add_fstr(pinfo->cinfo, COL_INFO, "Zabbix Protocol, Flags=0x%02x", flags);
}
}
col_append_fstr(pinfo->cinfo, COL_INFO, ", Len=%u (", (unsigned)length);
col_append_ports(pinfo->cinfo, COL_INFO, PT_TCP, pinfo->srcport, pinfo->destport);
col_append_str(pinfo->cinfo, COL_INFO, ")");
return tvb_reported_length(tvb);
}
/* Determine PDU length of Zabbix protocol */
static unsigned
get_zabbix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
uint8_t flags;
uint64_t length;
flags = tvb_get_guint8(tvb, offset+4);
if (flags & ZABBIX_FLAG_LARGEPACKET) {
/* 8-byte length field
* Note that ZABBIX_HDR_MIN_LEN check (in dissect_zabbix()) is still enough
* due to the header structure (there are reserved bytes)
*/
length = tvb_get_guint64(tvb, offset+5, ENC_LITTLE_ENDIAN) + ZABBIX_HDR_MAX_LEN;
} else {
/* 4-byte length */
length = tvb_get_guint32(tvb, offset+5, ENC_LITTLE_ENDIAN) + ZABBIX_HDR_MIN_LEN;
}
return (unsigned)length;
}
/* The main dissecting routine */
static int
dissect_zabbix(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
uint8_t flags;
if (tvb_captured_length(tvb) < ZABBIX_HDR_MIN_LEN) {
/* Not enough data */
return 0;
}
if (tvb_memeql(tvb, 0, ZABBIX_HDR_SIGNATURE, 4)) {
/* Encrypted or not Zabbix at all */
return 0;
}
flags = tvb_get_guint8(tvb, 4);
if (!(flags & ZABBIX_FLAG_ZABBIX_COMMUNICATIONS)) {
return 0;
}
/* This is unencrypted Zabbix protocol, continue with dissecting it */
tcp_dissect_pdus(tvb, pinfo, tree, zabbix_desegment, ZABBIX_HDR_MIN_LEN,
get_zabbix_pdu_len, dissect_zabbix_pdu, data);
return tvb_reported_length(tvb);
}
/* Register the protocol with Wireshark */
void
proto_register_zabbix(void)
{
static hf_register_info hf[] = {
{ &hf_zabbix_header,
{ "Header", "zabbix.header",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_flags,
{ "Flags", "zabbix.flags",
FT_UINT8, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_flag_zabbix_communications,
{ "Zabbix communications protocol", "zabbix.flags.zabbix",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), ZABBIX_FLAG_ZABBIX_COMMUNICATIONS,
NULL, HFILL }
},
{ &hf_zabbix_flag_compressed,
{ "Compressed", "zabbix.flags.compressed",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), ZABBIX_FLAG_COMPRESSED,
NULL, HFILL }
},
{ &hf_zabbix_flag_largepacket,
{ "Large packet", "zabbix.flags.large_packet",
FT_BOOLEAN, 8, TFS(&tfs_yes_no), ZABBIX_FLAG_LARGEPACKET,
NULL, HFILL }
},
{ &hf_zabbix_flag_reserved,
{ "Reserved bits", "zabbix.flags.reserved",
FT_UINT8, BASE_DEC, NULL, ZABBIX_FLAG_RESERVED,
NULL, HFILL }
},
{ &hf_zabbix_length,
{ "Length", "zabbix.len",
FT_UINT32, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_reserved,
{ "Reserved", "zabbix.reserved",
FT_UINT32, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_uncompressed_length,
{ "Uncompressed length", "zabbix.uncompressed_len",
FT_UINT32, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_large_length,
{ "Large length", "zabbix.large.len",
FT_UINT64, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_large_reserved,
{ "Large reserved", "zabbix.large.reserved",
FT_UINT64, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_large_uncompressed_length,
{ "Large uncompressed length", "zabbix.large.uncompressed_len",
FT_UINT64, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_data,
{ "Data", "zabbix.data",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_time,
{ "Response time", "zabbix.time",
FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_request,
{ "Zabbix protocol request", "zabbix.request",
FT_BOOLEAN, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_response,
{ "Zabbix protocol response", "zabbix.response",
FT_BOOLEAN, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_success,
{ "Success", "zabbix.success",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_failed,
{ "Failed", "zabbix.failed",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_agent,
{ "Zabbix agent connection", "zabbix.agent",
FT_BOOLEAN, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_config,
{ "Zabbix agent config", "zabbix.agent.config",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_data,
{ "Zabbix agent data", "zabbix.agent.data",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_passive,
{ "Passive agent", "zabbix.agent.passive",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_name,
{ "Agent name", "zabbix.agent.name",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_hb,
{ "Agent heartbeat", "zabbix.agent.heartbeat",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_hb_freq,
{ "Agent heartbeat frequency", "zabbix.agent.heartbeat_freq",
FT_INT32, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_hostmetadata,
{ "Agent host metadata", "zabbix.agent.host_metadata",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_hostinterface,
{ "Agent host interface", "zabbix.agent.host_interface",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_listenipv4,
{ "Agent listen IPv4", "zabbix.agent.listen_ipv4",
FT_IPv4, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_listenipv6,
{ "Agent listen IPv6", "zabbix.agent.listen_ipv6",
FT_IPv6, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_agent_listenport,
{ "Agent listen port", "zabbix.agent.listen_port",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy,
{ "Proxy connection", "zabbix.proxy",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_name,
{ "Proxy name", "zabbix.proxy.name",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_hb,
{ "Proxy heartbeat", "zabbix.proxy.heartbeat",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_data,
{ "Proxy data", "zabbix.proxy.data",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_config,
{ "Proxy config", "zabbix.proxy.config",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_fullsync,
{ "Proxy config full sync", "zabbix.proxy.full_sync",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_incr_config,
{ "Proxy incremental config", "zabbix.proxy.incremental_config",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_proxy_no_config_change,
{ "Proxy no config changes", "zabbix.proxy.no_config_changes",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_sender,
{ "Sender connection", "zabbix.sender",
FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0,
NULL, HFILL }
},
{ &hf_zabbix_sender_name,
{ "Sender name", "zabbix.sender.name",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_version,
{ "Version", "zabbix.version",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_session,
{ "Session", "zabbix.session",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_zabbix_config_revision,
{ "Config revision", "zabbix.config_revision",
FT_INT64, BASE_DEC, NULL, 0,
NULL, HFILL }
},
};
static ei_register_info ei[] = {
{
&ei_zabbix_packet_too_large,
{ "zabbix.packet_too_large", PI_UNDECODED, PI_WARN,
"Packet is too large for detailed dissection", EXPFILL }
},
{
&ei_zabbix_json_error,
{ "zabbix.json_error", PI_PROTOCOL, PI_ERROR,
"Cannot parse JSON", EXPFILL }
},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_zabbix,
};
module_t *zabbix_module;
expert_module_t *expert_zabbix;
/* Register the protocol name and description */
proto_zabbix = proto_register_protocol("Zabbix Protocol", "Zabbix", "zabbix");
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_zabbix, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
zabbix_module = prefs_register_protocol(proto_zabbix, NULL);
prefs_register_bool_preference(zabbix_module, "desegment",
"Reassemble Zabbix messages spanning multiple TCP segments",
"Whether the Zabbix protocol dissector should reassemble messages spanning multiple TCP segments."
" To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
&zabbix_desegment);
zabbix_handle = register_dissector("zabbix", dissect_zabbix, proto_zabbix);
expert_zabbix = expert_register_protocol(proto_zabbix);
expert_register_field_array(expert_zabbix, ei, array_length(ei));
}
void
proto_reg_handoff_zabbix(void)
{
dissector_add_uint_range_with_preference("tcp.port", ZABBIX_TCP_PORTS, zabbix_handle);
zabbix_port_range = prefs_get_range_value("Zabbix", "tcp.port");
dissector_add_uint_range("tls.port", zabbix_port_range, zabbix_handle);
}