/* packet-kt.c * * Routines for Kyoto Tycoon Version 1 binary protocol dissection * Copyright 2013, Abhik Sarkar * * http://fallabs.com/kyototycoon/spex.html#protocol * (Section "Binary Protocol") * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Adapted from packet-bzr.c * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include void proto_register_kt(void); void proto_reg_handoff_kt(void); static int proto_kt; /* * A few notes before we get into the thick of things... * * Note 1 (Abhik): * ============================ * While this is probably a very efficient protocol for the purpose * for which it has been written, the way it has been written makes * dissection a bit tricky. Requests and responses have the same * "magic" identifier, but there is no clear cut way to distinguish * between them. This means that a few dirty tricks have to be * employed for dissecting... and the dissector is based on sample * captures from two different clients working with the same version * of the server. * It is possible that the dissection will break under other conditions. * Hopefully, this can be fixed/improved with time. * * Note 2 (Abhik): * ============================ * There are three fields which use 64-bit time stamps. Based on what * I can see from the sample traces I have, the value in each is * different. I don't know if this is something specific to the * version of the client and server I have, or this is how the * implementation is... however, the difference is not apparent * (at least to me) from the protocol specifications. * So, this note is to clarify what I have found: * - The timestamp (ts) in the replication requests is nanoseconds * since epoch. * - The timestamp (xt) in the set_bulk records is the number of * seconds the record must live. * - The timestamp (xt) in the get_bulk output records is the * seconds since epoch. * * TODO: Support for reassembly of a request or response segmented over * multiple frames needs to be added. * A single frame containing multiple requests/responses seems unlikely * due to the fact that there is no identifier for matching a request * and a response. Tests suggest that the communication is synchronous. */ static dissector_handle_t kt_handle; /* Sub-trees */ static int ett_kt; static int ett_kt_rec; /* Header fields */ static int hf_kt_magic; static int hf_kt_type; static int hf_kt_ts; static int hf_kt_flags; static int hf_kt_rnum; static int hf_kt_dbidx; static int hf_kt_sid; static int hf_kt_xt; static int hf_kt_xt_resp; static int hf_kt_ksiz; static int hf_kt_vsiz; static int hf_kt_key; static int hf_kt_val; static int hf_kt_key_str; static int hf_kt_val_str; static int hf_kt_hits; static int hf_kt_nsiz; static int hf_kt_name; static int hf_kt_size; static int hf_kt_log; static int hf_kt_rec; /* Magic Values */ #define KT_MAGIC_REPL_WAIT 0xB0 #define KT_MAGIC_REPLICATION 0xB1 #define KT_MAGIC_PLAY_SCRIPT 0xB4 #define KT_MAGIC_SET_BULK 0xB8 #define KT_MAGIC_REMOVE_BULK 0xB9 #define KT_MAGIC_GET_BULK 0xBA #define KT_MAGIC_ERROR 0xBF static const value_string kt_magic_vals[] = { {KT_MAGIC_REPL_WAIT, "replication - waiting for updates"}, {KT_MAGIC_REPLICATION, "replication"}, {KT_MAGIC_PLAY_SCRIPT, "play_script"}, {KT_MAGIC_SET_BULK, "set_bulk" }, {KT_MAGIC_REMOVE_BULK, "remove_bulk"}, {KT_MAGIC_GET_BULK, "get_bulk" }, {KT_MAGIC_ERROR, "error" }, {0, NULL} }; /* Operation type (determined/generated by the dissector) */ #define KT_OPER_REQUEST 0x00 #define KT_OPER_RESPONSE 0x01 static const value_string kt_oper_vals[] = { {KT_OPER_REQUEST, "request"}, {KT_OPER_RESPONSE, "response"}, {0, NULL} }; /* Preferences */ /* * The default port numbers are not IANA registered but used by the * default configuration of the KT server all the same. */ #define DEFAULT_KT_PORT_RANGE "1978-1979" static bool kt_present_key_val_as_ascii; /* Dissection routines */ static int dissect_kt_replication_wait(tvbuff_t *tvb, proto_tree *tree, int offset) { int new_offset; uint64_t ts; nstime_t ns_ts; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; ts = tvb_get_ntoh64(tvb, new_offset); ns_ts.secs = (time_t)(ts/1000000000); ns_ts.nsecs = (int)(ts%1000000000); proto_tree_add_time(tree, hf_kt_ts, tvb, new_offset, 8, &ns_ts); new_offset += 8; return new_offset; } static int dissect_kt_replication(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { int new_offset; uint32_t next32, size; uint64_t ts; nstime_t ns_ts; proto_item *pi; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; if (tvb_reported_length_remaining(tvb, new_offset) > 0) { next32 = tvb_get_ntohl(tvb, new_offset); if (next32 <= 1) { /* This means request. the 32 bits are flags */ proto_tree_add_item(tree, hf_kt_flags, tvb, new_offset, 4, ENC_BIG_ENDIAN); new_offset += 4; proto_tree_add_item(tree, hf_kt_ts, tvb, new_offset, 8, ENC_BIG_ENDIAN); new_offset += 8; proto_tree_add_item(tree, hf_kt_sid, tvb, new_offset, 2, ENC_BIG_ENDIAN); new_offset += 2; } else { /* This is a response. The 32 bits are the first half of the ts */ ts = tvb_get_ntoh64(tvb, new_offset); ns_ts.secs = (time_t)(ts/1000000000); ns_ts.nsecs = (int)(ts%1000000000); proto_tree_add_time(tree, hf_kt_ts, tvb, new_offset, 8, &ns_ts); new_offset += 8; size = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_size, tvb, new_offset, 4, size); new_offset += 4; proto_tree_add_item(tree, hf_kt_log, tvb, new_offset, size, ENC_NA); new_offset += size; } } else { /* This is an empty ack to the message with magic 0xB0. */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); } return new_offset; } static int dissect_kt_set_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { uint32_t next32, rnum, ksiz, vsiz; int new_offset, rec_start_offset; proto_item *ti; proto_item *pi; proto_tree *rec_tree; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; next32 = tvb_get_ntohl(tvb, new_offset); if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* There's more data after the 32 bits. This is a request */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST); proto_item_set_generated(pi); proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32); new_offset += 4; rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum); new_offset += 4; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN); new_offset += 2; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; vsiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz); new_offset += 4; proto_tree_add_item(rec_tree, hf_kt_xt, tvb, new_offset, 8, ENC_BIG_ENDIAN); new_offset += 8; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += vsiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } else { /* Nothing remaining after the 32 bits. This is a response. */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32); new_offset += 4; } return new_offset; } static int dissect_kt_play_script(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { uint32_t next32, rnum, ksiz, vsiz, nsiz; int new_offset, rec_start_offset; proto_item *ti; proto_item *pi; proto_tree *rec_tree; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; next32 = tvb_get_ntohl(tvb, new_offset); if (next32 == 0) { if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* There's more data after the 32 bits. This is a request */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST); proto_item_set_generated(pi); proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32); new_offset += 4; nsiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_nsiz, tvb, new_offset, 4, nsiz); new_offset += 4; rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum); new_offset += 4; proto_tree_add_item(tree, hf_kt_name, tvb, new_offset, nsiz, ENC_ASCII); new_offset += nsiz; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; vsiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz); new_offset += 4; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += vsiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } else { /* Nothing remaining after the 32 bits. This is a response with no records. */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, next32); new_offset += 4; } } else { /* response - one or more records */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, rnum); new_offset += 4; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; vsiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz); new_offset += 4; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += vsiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } return new_offset; } static int dissect_kt_get_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { uint32_t next32, rnum, ksiz, vsiz; uint64_t xt; nstime_t ts; int new_offset, rec_start_offset; proto_item *ti; proto_item *pi; proto_tree *rec_tree; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; next32 = tvb_get_ntohl(tvb, new_offset); if (next32 == 0) { if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* request */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST); proto_item_set_generated(pi); proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32); new_offset += 4; rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum); new_offset += 4; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN); new_offset += 2; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } else { /* response - no records */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32); new_offset += 4; } } else { /* response - one or more records */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, rnum); new_offset += 4; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN); new_offset += 2; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; vsiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz); new_offset += 4; xt = tvb_get_ntoh64(tvb, new_offset); ts.secs = (time_t)(xt&0xFFFFFFFF); ts.nsecs = 0; proto_tree_add_time(rec_tree, hf_kt_xt_resp, tvb, new_offset, 8, &ts); new_offset += 8; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += vsiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } return new_offset; } static int dissect_kt_remove_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { uint32_t next32, rnum, ksiz; int new_offset, rec_start_offset; proto_item *ti; proto_item *pi; proto_tree *rec_tree; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; next32 = tvb_get_ntohl(tvb, new_offset); if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* request */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST); proto_item_set_generated(pi); proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32); new_offset += 4; rnum = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum); new_offset += 4; while (rnum > 0) { /* Create a sub-tree for each record */ ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA); rec_tree = proto_item_add_subtree(ti, ett_kt_rec); rec_start_offset = new_offset; proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN); new_offset += 2; ksiz = tvb_get_ntohl(tvb, new_offset); proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz); new_offset += 4; proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA); if (kt_present_key_val_as_ascii) { pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII); proto_item_set_generated(pi); } new_offset += ksiz; proto_item_set_len(ti, new_offset - rec_start_offset); rnum--; } } else { /* response */ pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE); proto_item_set_generated(pi); col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]"); proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32); new_offset += 4; } return new_offset; } static int dissect_kt_error(tvbuff_t *tvb, proto_tree *tree, int offset) { int new_offset; new_offset = offset; proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN); new_offset++; return new_offset; } static int dissect_kt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { int magic; proto_item *ti; proto_tree *kt_tree; int offset, offset_start; offset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { magic = tvb_get_uint8(tvb, offset); /* If the magic is not one of the known values, exit */ if (try_val_to_str(magic, kt_magic_vals) == NULL) return offset; /* Otherwise, the magic value is known. Continue */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "KT"); col_set_str(pinfo->cinfo, COL_INFO, try_val_to_str(magic, kt_magic_vals)); ti = proto_tree_add_item(tree, proto_kt, tvb, offset, -1, ENC_NA); kt_tree = proto_item_add_subtree(ti, ett_kt); offset_start=offset; switch (magic) { case KT_MAGIC_REPL_WAIT: offset = dissect_kt_replication_wait(tvb, kt_tree, offset); break; case KT_MAGIC_REPLICATION: offset = dissect_kt_replication(tvb, pinfo, kt_tree, offset); break; case KT_MAGIC_PLAY_SCRIPT: offset = dissect_kt_play_script(tvb, pinfo, kt_tree, offset); break; case KT_MAGIC_SET_BULK: offset = dissect_kt_set_bulk(tvb, pinfo, kt_tree, offset); break; case KT_MAGIC_REMOVE_BULK: offset = dissect_kt_remove_bulk(tvb, pinfo, kt_tree, offset); break; case KT_MAGIC_GET_BULK: offset = dissect_kt_get_bulk(tvb, pinfo, kt_tree, offset); break; case KT_MAGIC_ERROR: offset = dissect_kt_error(tvb, kt_tree, offset); break; } proto_item_set_len(ti, offset-offset_start); } return tvb_captured_length(tvb); } void proto_register_kt(void) { module_t *kt_module; /* preferences */ static hf_register_info hf[] = { { &hf_kt_magic, { "magic", "kt.magic", FT_UINT8, BASE_HEX, VALS(kt_magic_vals), 0x0, "identifier", HFILL } }, { &hf_kt_type, { "type", "kt.type", FT_UINT8, BASE_HEX, VALS(kt_oper_vals), 0x0, "request/response", HFILL } }, { &hf_kt_flags, { "flags", "kt.flags", FT_UINT32, BASE_HEX, NULL, 0x0, "flags of bitwise-or", HFILL } }, { &hf_kt_rnum, { "rnum", "kt.rnum", FT_UINT32, BASE_DEC, NULL, 0x0, "the number of records", HFILL } }, { &hf_kt_dbidx, { "dbidx", "kt.dbidx", FT_UINT16, BASE_DEC, NULL, 0x0, "the index of the target database", HFILL } }, { &hf_kt_sid, { "sid", "kt.sid", FT_UINT16, BASE_DEC, NULL, 0x0, "the server ID number", HFILL } }, { &hf_kt_ts, { "ts", "kt.ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, "the timestamp of the log", HFILL } }, { &hf_kt_xt, { "xt", "kt.xt", FT_UINT64, BASE_DEC, NULL, 0x0, "the expiration time in seconds", HFILL } }, { &hf_kt_xt_resp, { "xt", "kt.xt_resp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, "the expiration time", HFILL } }, { &hf_kt_ksiz, { "ksiz", "kt.ksiz", FT_UINT32, BASE_DEC, NULL, 0x0, "the size of the key",HFILL } }, { &hf_kt_vsiz, { "vsiz", "kt.vsiz", FT_UINT32, BASE_DEC, NULL, 0x0, "the size of the value", HFILL } }, { &hf_kt_key, { "key", "kt.key", FT_BYTES, BASE_NONE, NULL, 0x0, "the key", HFILL } }, { &hf_kt_val, { "value", "kt.value", FT_BYTES, BASE_NONE, NULL, 0x0, "the value", HFILL } }, { &hf_kt_key_str, { "key", "kt.key_str", FT_STRING, BASE_NONE, NULL, 0x0, "ASCII representation of the key", HFILL } }, { &hf_kt_val_str, { "value", "kt.value_str", FT_STRING, BASE_NONE, NULL, 0x0, "ASCII representation of the value", HFILL } }, { &hf_kt_hits, { "hits", "kt.hits", FT_UINT32, BASE_DEC, NULL, 0x0, "the number of records", HFILL } }, { &hf_kt_size, { "size", "kt.size", FT_UINT32, BASE_DEC, NULL, 0x0, "the size of the replication log", HFILL } }, { &hf_kt_log, { "log", "kt.log", FT_BYTES, BASE_NONE, NULL, 0x0, "the replication log", HFILL } }, { &hf_kt_nsiz, { "nsiz", "kt.nsiz", FT_UINT32, BASE_DEC, NULL, 0x0, "the size of the procedure name", HFILL } }, { &hf_kt_name, { "name", "kt.name", FT_STRING, BASE_NONE, NULL, 0x0, "the procedure name", HFILL } }, { &hf_kt_rec, { "record", "kt.record", FT_NONE, BASE_NONE, NULL, 0x0, "a record", HFILL } } }; static int *ett[] = { &ett_kt, &ett_kt_rec }; proto_kt = proto_register_protocol("Kyoto Tycoon Protocol", "Kyoto Tycoon", "kt"); kt_handle = register_dissector("kt", dissect_kt, proto_kt); proto_register_field_array(proto_kt, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* Preferences */ kt_module = prefs_register_protocol(proto_kt, NULL); prefs_register_bool_preference(kt_module, "present_key_val_as_ascii", "Attempt to also show ASCII string representation of keys and values", "KT allows binary values in keys and values. Attempt to show an ASCII representation anyway (which might be prematurely terminated by a NULL!", &kt_present_key_val_as_ascii); } void proto_reg_handoff_kt(void) { dissector_add_uint_range_with_preference("tcp.port", DEFAULT_KT_PORT_RANGE, kt_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: */