diff options
Diffstat (limited to 'epan/dissectors/packet-scylla.c')
-rw-r--r-- | epan/dissectors/packet-scylla.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/epan/dissectors/packet-scylla.c b/epan/dissectors/packet-scylla.c new file mode 100644 index 00000000..c5254f7a --- /dev/null +++ b/epan/dissectors/packet-scylla.c @@ -0,0 +1,553 @@ +/* packet-scylla.c + * Routines for Scylla RPC dissection + * Copyright 2020 ScyllaDB, Piotr Sarna <sarna@scylladb.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * ScyllaDB RPC protocol is used for inter-node communication + * in the ScyllaDB database - reading/sending data, exchanging + * cluster information through gossip, updating schemas, etc. + * + * Protocol references: + * https://github.com/scylladb/seastar/blob/master/doc/rpc.md + * https://github.com/scylladb/scylla/blob/master/message/messaging_service.hh + * + */ + +#include <config.h> + +#include <epan/expert.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include "packet-tcp.h" + +void proto_reg_handoff_scylla(void); +void proto_register_scylla(void); + +static dissector_handle_t scylla_handle; + +#define SCYLLA_PORT 0 /* Not IANA registered, 7000 is the expected value */ + +#define SCYLLA_HEADER_SIZE 28 +#define SCYLLA_HEADER_VERB_OFFSET 8 +#define SCYLLA_HEADER_MSG_ID_OFFSET 16 +#define SCYLLA_HEADER_LEN_OFFSET 24 + +#define SCYLLA_RESPONSE_SIZE 12 +#define SCYLLA_RESPONSE_MSG_ID_OFFSET 0 +#define SCYLLA_RESPONSE_LEN_OFFSET 8 + +#define SCYLLA_NEGOTIATION_SIZE 12 +#define SCYLLA_NEGOTIATION_LEN_OFFSET 8 + +static int proto_scylla = -1; + +static int hf_scylla_request = -1; +static int hf_scylla_request_response_frame = -1; +static int hf_scylla_timeout = -1; +static int hf_scylla_verb = -1; +static int hf_scylla_msg_id = -1; +static int hf_scylla_len = -1; +static int hf_scylla_response = -1; +static int hf_scylla_response_size = -1; +static int hf_scylla_response_request_frame = -1; +static int hf_scylla_negotiation_magic = -1; +static int hf_scylla_negotiation_size = -1; +static int hf_scylla_payload = -1; // TODO: dissect everything, so that generic "payload" is not needed + +// Mutation +static int hf_scylla_mut_size1 = -1; +static int hf_scylla_mut_size2 = -1; +static int hf_scylla_mut_table_id = -1; +static int hf_scylla_mut_schema_id = -1; +static int hf_scylla_mut_len_pkeys = -1; +static int hf_scylla_mut_num_pkeys = -1; +static int hf_scylla_mut_len_pkey = -1; +static int hf_scylla_mut_pkey = -1; + +// Read data +static int hf_scylla_read_data_timeout = -1; +static int hf_scylla_read_data_table_id = -1; +static int hf_scylla_read_data_schema_version = -1; + +static gint ett_scylla = -1; +static gint ett_scylla_header = -1; +static gint ett_scylla_response = -1; +static gint ett_scylla_negotiation = -1; +static gint ett_scylla_mut = -1; +static gint ett_scylla_mut_pkey = -1; +static gint ett_scylla_read_data = -1; + +static gboolean scylla_desegment = TRUE; + +static expert_field ei_scylla_response_missing = EI_INIT; + +enum scylla_packets { + CLIENT_ID = 0, + MUTATION = 1, + MUTATION_DONE = 2, + READ_DATA = 3, + READ_MUTATION_DATA = 4, + READ_DIGEST = 5, + // Used by gossip + GOSSIP_DIGEST_SYN = 6, + GOSSIP_DIGEST_ACK = 7, + GOSSIP_DIGEST_ACK2 = 8, + GOSSIP_ECHO = 9, + GOSSIP_SHUTDOWN = 10, + // end of gossip verb + DEFINITIONS_UPDATE = 11, + TRUNCATE = 12, + REPLICATION_FINISHED = 13, + MIGRATION_REQUEST = 14, + // Used by streaming + PREPARE_MESSAGE = 15, + PREPARE_DONE_MESSAGE = 16, + STREAM_MUTATION = 17, + STREAM_MUTATION_DONE = 18, + COMPLETE_MESSAGE = 19, + // end of streaming verbs + REPAIR_CHECKSUM_RANGE = 20, + GET_SCHEMA_VERSION = 21, + SCHEMA_CHECK = 22, + COUNTER_MUTATION = 23, + MUTATION_FAILED = 24, + STREAM_MUTATION_FRAGMENTS = 25, + REPAIR_ROW_LEVEL_START = 26, + REPAIR_ROW_LEVEL_STOP = 27, + REPAIR_GET_FULL_ROW_HASHES = 28, + REPAIR_GET_COMBINED_ROW_HASH = 29, + REPAIR_GET_SYNC_BOUNDARY = 30, + REPAIR_GET_ROW_DIFF = 31, + REPAIR_PUT_ROW_DIFF = 32, + REPAIR_GET_ESTIMATED_PARTITIONS = 33, + REPAIR_SET_ESTIMATED_PARTITIONS = 34, + REPAIR_GET_DIFF_ALGORITHMS = 35, + REPAIR_GET_ROW_DIFF_WITH_RPC_STREAM = 36, + REPAIR_PUT_ROW_DIFF_WITH_RPC_STREAM = 37, + REPAIR_GET_FULL_ROW_HASHES_WITH_RPC_STREAM = 38, + PAXOS_PREPARE = 39, + PAXOS_ACCEPT = 40, + PAXOS_LEARN = 41, + HINT_MUTATION = 42, + PAXOS_PRUNE = 43, + LAST = 44, +}; + +static const val64_string packettypenames[] = { + {CLIENT_ID, "CLIENT_ID"}, + {MUTATION, "MUTATION"}, + {MUTATION_DONE, "MUTATION_DONE"}, + {READ_DATA, "READ_DATA"}, + {READ_MUTATION_DATA, "READ_MUTATION_DATA"}, + {READ_DIGEST, "READ_DIGEST"}, + {GOSSIP_DIGEST_SYN, "GOSSIP_DIGEST_SYN"}, + {GOSSIP_DIGEST_ACK, "GOSSIP_DIGEST_ACK"}, + {GOSSIP_DIGEST_ACK2, "GOSSIP_DIGEST_ACK2"}, + {GOSSIP_ECHO, "GOSSIP_ECHO"}, + {GOSSIP_SHUTDOWN, "GOSSIP_SHUTDOWN"}, + {DEFINITIONS_UPDATE, "DEFINITIONS_UPDATE"}, + {TRUNCATE, "TRUNCATE"}, + {REPLICATION_FINISHED, "REPLICATION_FINISHED"}, + {MIGRATION_REQUEST, "MIGRATION_REQUEST"}, + {PREPARE_MESSAGE, "PREPARE_MESSAGE"}, + {PREPARE_DONE_MESSAGE, "PREPARE_DONE_MESSAGE"}, + {STREAM_MUTATION, "STREAM_MUTATION"}, + {STREAM_MUTATION_DONE, "STREAM_MUTATION_DONE"}, + {COMPLETE_MESSAGE, "COMPLETE_MESSAGE"}, + {REPAIR_CHECKSUM_RANGE, "REPAIR_CHECKSUM_RANGE"}, + {GET_SCHEMA_VERSION, "GET_SCHEMA_VERSION"}, + {SCHEMA_CHECK, "SCHEMA_CHECK"}, + {COUNTER_MUTATION, "COUNTER_MUTATION"}, + {MUTATION_FAILED, "MUTATION_FAILED"}, + {STREAM_MUTATION_FRAGMENTS, "STREAM_MUTATION_FRAGMENTS"}, + {REPAIR_ROW_LEVEL_START, "REPAIR_ROW_LEVEL_START"}, + {REPAIR_ROW_LEVEL_STOP, "REPAIR_ROW_LEVEL_STOP"}, + {REPAIR_GET_FULL_ROW_HASHES, "REPAIR_GET_FULL_ROW_HASHES"}, + {REPAIR_GET_COMBINED_ROW_HASH, "REPAIR_GET_COMBINED_ROW_HASH"}, + {REPAIR_GET_SYNC_BOUNDARY, "REPAIR_GET_SYNC_BOUNDARY"}, + {REPAIR_GET_ROW_DIFF, "REPAIR_GET_ROW_DIFF"}, + {REPAIR_PUT_ROW_DIFF, "REPAIR_PUT_ROW_DIFF"}, + {REPAIR_GET_ESTIMATED_PARTITIONS, "REPAIR_GET_ESTIMATED_PARTITIONS"}, + {REPAIR_SET_ESTIMATED_PARTITIONS, "REPAIR_SET_ESTIMATED_PARTITIONS"}, + {REPAIR_GET_DIFF_ALGORITHMS, "REPAIR_GET_DIFF_ALGORITHMS"}, + {REPAIR_GET_ROW_DIFF_WITH_RPC_STREAM, "REPAIR_GET_ROW_DIFF_WITH_RPC_STREAM"}, + {REPAIR_PUT_ROW_DIFF_WITH_RPC_STREAM, "REPAIR_PUT_ROW_DIFF_WITH_RPC_STREAM"}, + {REPAIR_GET_FULL_ROW_HASHES_WITH_RPC_STREAM, "REPAIR_GET_FULL_ROW_HASHES_WITH_RPC_STREAM"}, + {PAXOS_PREPARE, "PAXOS_PREPARE"}, + {PAXOS_ACCEPT, "PAXOS_ACCEPT"}, + {PAXOS_LEARN, "PAXOS_LEARN"}, + {HINT_MUTATION, "HINT_MUTATION"}, + {PAXOS_PRUNE, "PAXOS_PRUNE"}, + {0, NULL} +}; + +static gboolean +looks_like_rpc_negotiation(tvbuff_t *tvb, const gint offset) { + return tvb_memeql(tvb, offset, (const guint8 *)"SSTARRPC", 8) == 0; +} + +static gboolean +looks_like_response(guint64 verb_type, guint32 len) { + return verb_type >= LAST || len > 64*1024*1024; +} + +typedef struct { + guint64 verb_type; + guint32 request_frame_num; + guint32 response_frame_num; +} request_response_t; + +static guint +get_scylla_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) +{ + guint64 verb_type = LAST; + guint32 plen = 0; + if (looks_like_rpc_negotiation(tvb, offset)) { + return tvb_get_letohl(tvb, offset + SCYLLA_NEGOTIATION_LEN_OFFSET) + SCYLLA_NEGOTIATION_SIZE; + } + if (tvb_reported_length(tvb) >= SCYLLA_HEADER_SIZE) { + plen = tvb_get_letohl(tvb, offset + SCYLLA_HEADER_LEN_OFFSET); + verb_type = tvb_get_letoh64(tvb, offset + SCYLLA_HEADER_VERB_OFFSET); + } + + if (looks_like_response(verb_type, plen)) { + return tvb_get_letohl(tvb, offset + SCYLLA_RESPONSE_LEN_OFFSET) + SCYLLA_RESPONSE_SIZE; + } + return plen + SCYLLA_HEADER_SIZE; +} + +static int +dissect_scylla_negotiation_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *scylla_tree) +{ + gint offset = 0; + guint32 len = tvb_get_letohl(tvb, offset + SCYLLA_NEGOTIATION_LEN_OFFSET) + SCYLLA_NEGOTIATION_SIZE; + + proto_tree *scylla_negotiation_tree = proto_tree_add_subtree(scylla_tree, tvb, offset, + len, ett_scylla_negotiation, NULL, "Protocol negotiation"); + proto_tree_add_item(scylla_negotiation_tree, hf_scylla_negotiation_magic, tvb, offset, 8, ENC_ASCII); + gint negotiation_offset = 8; + proto_tree_add_item(scylla_negotiation_tree, hf_scylla_negotiation_size, tvb, offset + negotiation_offset, 4, ENC_LITTLE_ENDIAN); + negotiation_offset += 4; + proto_tree_add_item(scylla_negotiation_tree, hf_scylla_payload, tvb, offset + negotiation_offset, len - negotiation_offset, ENC_NA); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Scylla"); + col_set_str(pinfo->cinfo, COL_INFO, "Protocol negotiation"); + return tvb_reported_length(tvb); +} + +static int +dissect_scylla_response_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *scylla_tree, request_response_t *req_resp) +{ + gint offset = 0; + guint32 len = tvb_get_letohl(tvb, offset + SCYLLA_RESPONSE_LEN_OFFSET) + SCYLLA_RESPONSE_SIZE; + + /* Add response subtree */ + proto_item *response_ti = proto_tree_add_string_format(scylla_tree, hf_scylla_response, + tvb, offset, len, "", "Response"); + proto_tree *scylla_response_tree = proto_item_add_subtree(response_ti, ett_scylla_response); + + gint resp_offset = 0; + + guint64 msg_id; + proto_tree_add_item_ret_uint64(scylla_response_tree, hf_scylla_msg_id, tvb, offset + resp_offset, 8, ENC_LITTLE_ENDIAN, &msg_id); + resp_offset += 8; + proto_tree_add_item(scylla_response_tree, hf_scylla_response_size, tvb, offset + resp_offset, 4, ENC_LITTLE_ENDIAN); + resp_offset += 4; + proto_tree_add_item(scylla_response_tree, hf_scylla_payload, tvb, offset + resp_offset, len - resp_offset, ENC_NA); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Scylla"); + if (req_resp) { + /* Fill in the response frame */ + req_resp->response_frame_num = pinfo->num; + + proto_item *verb_item = proto_tree_add_uint64(scylla_response_tree, hf_scylla_verb, tvb, offset + len, 8, req_resp->verb_type); + proto_item_set_generated(verb_item); + proto_item *req = proto_tree_add_uint(scylla_tree, hf_scylla_response_request_frame, tvb, 0, 0, req_resp->request_frame_num); + proto_item_set_generated(req); + + proto_item_append_text(response_ti, " (msg_id=%" PRIu64 ", %s)", + msg_id, val64_to_str(req_resp->verb_type, packettypenames, "Unknown (0x%02x)")); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "Response for %s", + val64_to_str(req_resp->verb_type, packettypenames, "Unknown (0x%02x)")); + } else { + col_set_str(pinfo->cinfo, COL_INFO, "Response for unknown packet"); + } + return tvb_reported_length(tvb); +} + +static int +dissect_scylla_msg_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *scylla_tree, proto_item *ti, guint64 verb_type, guint32 len, request_response_t *req_resp) +{ + gint offset = 0; + + /* Add request subtree */ + proto_item *request_ti = proto_tree_add_string_format(scylla_tree, hf_scylla_request, + tvb, offset, SCYLLA_HEADER_SIZE, + "", "Header for %s", + val64_to_str(verb_type, packettypenames, "Unknown (0x%02x)")); + proto_tree *scylla_header_tree = proto_item_add_subtree(request_ti, ett_scylla_response); + + proto_tree_add_item(scylla_header_tree, hf_scylla_timeout, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + proto_item_append_text(ti, ", Type %s", val64_to_str(verb_type, packettypenames, "Unknown (0x%02x)")); + proto_tree_add_item(scylla_header_tree, hf_scylla_verb, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + guint64 msg_id; + proto_tree_add_item_ret_uint64(scylla_header_tree, hf_scylla_msg_id, tvb, offset, 8, ENC_LITTLE_ENDIAN, &msg_id); + offset += 8; + proto_tree_add_item(scylla_header_tree, hf_scylla_len, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_item_append_text(request_ti, " (msg_id=%" PRIu64 ")", msg_id); + + switch (verb_type) { + case MUTATION: { + proto_tree* scylla_mut_tree = proto_tree_add_subtree(scylla_tree, tvb, offset, + len, ett_scylla_mut, NULL, "Mutation"); + gint mut_offset = 0; + guint32 len_keys; + guint32 num_keys; + proto_tree_add_item(scylla_mut_tree, hf_scylla_mut_size1, tvb, offset + mut_offset, 4, ENC_LITTLE_ENDIAN); + mut_offset += 4; + proto_tree_add_item(scylla_mut_tree, hf_scylla_mut_size2, tvb, offset + mut_offset, 4, ENC_LITTLE_ENDIAN); + mut_offset += 4; + proto_tree_add_item(scylla_mut_tree, hf_scylla_mut_table_id, tvb, offset + mut_offset, 16, ENC_NA); + mut_offset += 16; + proto_tree_add_item(scylla_mut_tree, hf_scylla_mut_schema_id, tvb, offset + mut_offset, 16, ENC_NA); + mut_offset += 16; + proto_tree_add_item_ret_uint(scylla_mut_tree, hf_scylla_mut_len_pkeys, tvb, offset + mut_offset, 4, ENC_LITTLE_ENDIAN, &len_keys); + mut_offset += 4; + proto_tree* scylla_mut_pkey_tree = proto_tree_add_subtree(scylla_mut_tree, tvb, offset + mut_offset, + len - mut_offset, ett_scylla_mut_pkey, NULL, "Partition key"); + proto_tree_add_item_ret_uint(scylla_mut_pkey_tree, hf_scylla_mut_num_pkeys, tvb, offset + mut_offset, 4, ENC_LITTLE_ENDIAN, &num_keys); + mut_offset += 4; + guint i; + for (i = 0; i < num_keys; ++i) { + guint32 len_pkey = tvb_get_letohl(tvb, offset + mut_offset); + proto_tree_add_item(scylla_mut_pkey_tree, hf_scylla_mut_len_pkey, tvb, offset + mut_offset, 4, ENC_LITTLE_ENDIAN); + mut_offset += 4; + proto_tree_add_item(scylla_mut_pkey_tree, hf_scylla_mut_pkey, tvb, offset + mut_offset, len_pkey, ENC_NA); + mut_offset += len_pkey; + } + // TODO: dissect further + proto_tree_add_item(scylla_mut_tree, hf_scylla_payload, tvb, offset + mut_offset, len - mut_offset, ENC_NA); + } + break; + case READ_DATA: { + proto_tree* scylla_read_tree = proto_tree_add_subtree(scylla_tree, tvb, offset, + len, ett_scylla_read_data, NULL, "Read data"); + gint rd_offset = 0; + + proto_tree_add_item(scylla_read_tree, hf_scylla_read_data_timeout, tvb, offset + rd_offset, 4, ENC_LITTLE_ENDIAN); + rd_offset += 4; + proto_tree_add_item(scylla_read_tree, hf_scylla_read_data_table_id, tvb, offset + rd_offset, 16, ENC_NA); + rd_offset += 16; + proto_tree_add_item(scylla_read_tree, hf_scylla_read_data_schema_version, tvb, offset + rd_offset, 16, ENC_NA); + rd_offset += 16; + //TODO: dissect further + proto_tree_add_item(scylla_read_tree, hf_scylla_payload, tvb, offset + rd_offset, len - rd_offset, ENC_NA); + } + break; + default: + // Generic payload. TODO: dissect + proto_tree_add_item(scylla_tree, hf_scylla_payload, tvb, offset, len, ENC_NA); + break; + } + + /* req_resp will only be set if fd was already visited (PINFO_FD_VISITED(pinfo)) */ + if (req_resp) { + if (req_resp->response_frame_num > 0) { + proto_item *rep = proto_tree_add_uint(scylla_tree, hf_scylla_request_response_frame, tvb, 0, 0, req_resp->response_frame_num); + proto_item_set_generated(rep); + } else { + expert_add_info(pinfo, request_ti, &ei_scylla_response_missing); + } + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Scylla"); + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "Request %s", + val64_to_str(verb_type, packettypenames, "Unknown (0x%02x)")); + return tvb_reported_length(tvb); +} + +static gboolean +response_expected(guint64 verb_type) +{ + switch (verb_type) { + case GOSSIP_DIGEST_SYN: + case GOSSIP_DIGEST_ACK: + case GOSSIP_DIGEST_ACK2: + case GOSSIP_SHUTDOWN: + case DEFINITIONS_UPDATE: + case MUTATION: + case MUTATION_DONE: + case MUTATION_FAILED: + case HINT_MUTATION: + case PAXOS_LEARN: + case PAXOS_PRUNE: + return FALSE; + default: + return TRUE; + } +} + + +static int +dissect_scylla_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + gint offset = 0; + conversation_t *conversation; + wmem_map_t *conv_map; + + proto_item *ti = proto_tree_add_item(tree, proto_scylla, tvb, 0, -1, ENC_NA); + proto_tree *scylla_tree = proto_item_add_subtree(ti, ett_scylla); + + guint64 verb_type = LAST; + guint32 len = 0; + + if (looks_like_rpc_negotiation(tvb, offset)) { + return dissect_scylla_negotiation_pdu(tvb, pinfo, scylla_tree); + } + + if (tvb_reported_length(tvb) >= SCYLLA_HEADER_SIZE) { + verb_type = tvb_get_letoh64(tvb, offset + SCYLLA_HEADER_VERB_OFFSET); + len = tvb_get_letohl(tvb, offset + SCYLLA_HEADER_LEN_OFFSET); + } + + conversation = find_or_create_conversation(pinfo); + conv_map = (wmem_map_t *)conversation_get_proto_data(conversation, proto_scylla); + if (conv_map == NULL) { + conv_map = wmem_map_new(wmem_file_scope(), wmem_int64_hash, g_int64_equal); + conversation_add_proto_data(conversation, proto_scylla, conv_map); + } + + if (looks_like_response(verb_type, len)) { + void *req_resp; + guint64 msg_id; + msg_id = tvb_get_letoh64(tvb, offset + SCYLLA_RESPONSE_MSG_ID_OFFSET); + req_resp = wmem_map_lookup(conv_map, &msg_id); + return dissect_scylla_response_pdu(tvb, pinfo, scylla_tree, (request_response_t *)req_resp); + } + + guint64 msg_id = tvb_get_letoh64(tvb, offset + SCYLLA_HEADER_MSG_ID_OFFSET); + void *req_resp = NULL; + + if (response_expected(verb_type)) { + if (!PINFO_FD_VISITED(pinfo)) { + guint64 *key = wmem_new(wmem_file_scope(), guint64); + request_response_t *val = wmem_new(wmem_file_scope(), request_response_t); + *key = msg_id; + val->verb_type = verb_type; + val->request_frame_num = pinfo->num; + wmem_map_insert(conv_map, key, val); + } else { + req_resp = wmem_map_lookup(conv_map, &msg_id); + } + } + + return dissect_scylla_msg_pdu(tvb, pinfo, scylla_tree, ti, verb_type, len, (request_response_t *)req_resp); +} + +static int +dissect_scylla(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +{ + tcp_dissect_pdus(tvb, pinfo, tree, scylla_desegment, SCYLLA_NEGOTIATION_SIZE, + get_scylla_pdu_len, dissect_scylla_pdu, data); + return tvb_reported_length(tvb); +} + +void +proto_register_scylla(void) +{ + static hf_register_info hf[] = { + // RPC header + { &hf_scylla_request, { "request", "scylla.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_request_response_frame, { "Response frame", "scylla.request.response", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, NULL, HFILL } }, + { &hf_scylla_timeout, { "RPC timeout", "scylla.timeout", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_verb, { "verb", "scylla.verb", FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(packettypenames), 0x0, NULL, HFILL } }, + { &hf_scylla_msg_id, { "msg id", "scylla.msg_id", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_len, { "packet length", "scylla.len", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_payload, { "payload", "scylla.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_response, { "response", "scylla.response", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_response_size, { "response size", "scylla.response.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_response_request_frame, { "Request frame", "scylla.response.request", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, NULL, HFILL } }, + { &hf_scylla_negotiation_magic, { "negotiation magic sequence", "scylla.negotiation.magic", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_negotiation_size, { "negotiation size", "scylla.negotiation.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + // mutation verb + { &hf_scylla_mut_size1, { "mutation size 1", "scylla.mut.size1", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_size2, { "mutation size 2", "scylla.mut.size2", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_table_id, { "mutation table id", "scylla.mut.table_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_schema_id, { "mutation schema id", "scylla.mut.schema_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_len_pkeys, { "size of partition keys payload", "scylla.mut.len_pkeys", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_num_pkeys, { "number of partition keys", "scylla.mut.num_pkeys", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_len_pkey, { "length of a partition key", "scylla.mut.len_pkey", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_mut_pkey, { "partition key", "scylla.mut.pkey", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + // read_data verb + { &hf_scylla_read_data_timeout, { "timeout", "scylla.read_data.timeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_read_data_table_id, { "table ID", "scylla.read_data.table_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_scylla_read_data_schema_version, { "Schema version", "scylla.read_data.schema_version", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + + }; + + static ei_register_info ei[] = { + { &ei_scylla_response_missing, + { "scylla.ei_scylla_response_missing", + PI_COMMENTS_GROUP, PI_NOTE, "Response has not arrived yet", EXPFILL }}, + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_scylla, + &ett_scylla_header, + &ett_scylla_response, + &ett_scylla_negotiation, + &ett_scylla_mut, + &ett_scylla_mut_pkey, + &ett_scylla_read_data, + }; + + expert_module_t* expert_scylla; + + proto_scylla = proto_register_protocol("Scylla RPC protocol", "Scylla", "scylla"); + module_t* scylla_module = prefs_register_protocol(proto_scylla, NULL); + prefs_register_bool_preference(scylla_module, "desegment", + "Desegment all Scylla messages spanning multiple TCP segments", + "Whether Scylla dissector should desegment all messages spanning multiple TCP segments", + &scylla_desegment); + + proto_register_field_array(proto_scylla, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + expert_scylla = expert_register_protocol(proto_scylla); + expert_register_field_array(expert_scylla, ei, array_length(ei)); + + scylla_handle = register_dissector("scylla", dissect_scylla, proto_scylla); +} + +void +proto_reg_handoff_scylla(void) +{ + dissector_add_uint_with_preference("tcp.port", SCYLLA_PORT, scylla_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: + */ |