Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-kt.c
Line
Count
Source
1
/* packet-kt.c
2
 *
3
 * Routines for Kyoto Tycoon Version 1 binary protocol dissection
4
 * Copyright 2013, Abhik Sarkar <sarkar.abhik@gmail.com>
5
 *
6
 * http://fallabs.com/kyototycoon/spex.html#protocol
7
 * (Section "Binary Protocol")
8
 *
9
 * Wireshark - Network traffic analyzer
10
 * By Gerald Combs <gerald@wireshark.org>
11
 * Copyright 1998 Gerald Combs
12
 *
13
 * Adapted from packet-bzr.c
14
 *
15
 * SPDX-License-Identifier: GPL-2.0-or-later
16
 */
17
18
#include "config.h"
19
20
#include <epan/packet.h>
21
#include <epan/prefs.h>
22
23
24
void proto_register_kt(void);
25
void proto_reg_handoff_kt(void);
26
27
static int proto_kt;
28
29
/*
30
 * A few notes before we get into the thick of things...
31
 *
32
 * Note 1 (Abhik):
33
 * ============================
34
 * While this is probably a very efficient protocol for the purpose
35
 * for which it has been written, the way it has been written makes
36
 * dissection a bit tricky. Requests and responses have the same
37
 * "magic" identifier, but there is no clear cut way to distinguish
38
 * between them. This means that a few dirty tricks have to be
39
 * employed for dissecting... and the dissector is based on sample
40
 * captures from two different clients working with the same version
41
 * of the server.
42
 * It is possible that the dissection will break under other conditions.
43
 * Hopefully, this can be fixed/improved with time.
44
 *
45
 * Note 2 (Abhik):
46
 * ============================
47
 * There are three fields which use 64-bit time stamps. Based on what
48
 * I can see from the sample traces I have, the value in each is
49
 * different. I don't know if this is something specific to the
50
 * version of the client and server I have, or this is how the
51
 * implementation is... however, the difference is not apparent
52
 * (at least to me) from the protocol specifications.
53
 * So, this note is to clarify what I have found:
54
 * - The timestamp (ts) in the replication requests is nanoseconds
55
 *   since epoch.
56
 * - The timestamp (xt) in the set_bulk records is the number of
57
 *   seconds the record must live.
58
 * - The timestamp (xt) in the get_bulk output records is the
59
 *   seconds since epoch.
60
 *
61
 * TODO: Support for reassembly of a request or response segmented over
62
 * multiple frames needs to be added.
63
 * A single frame containing multiple requests/responses seems unlikely
64
 * due to the fact that there is no identifier for matching a request
65
 * and a response. Tests suggest that the communication is synchronous.
66
*/
67
68
static dissector_handle_t kt_handle;
69
70
/* Sub-trees */
71
static int ett_kt;
72
static int ett_kt_rec;
73
74
/* Header fields */
75
static int hf_kt_magic;
76
static int hf_kt_type;
77
static int hf_kt_ts;
78
static int hf_kt_flags;
79
static int hf_kt_rnum;
80
static int hf_kt_dbidx;
81
static int hf_kt_sid;
82
static int hf_kt_xt;
83
static int hf_kt_xt_resp;
84
static int hf_kt_ksiz;
85
static int hf_kt_vsiz;
86
static int hf_kt_key;
87
static int hf_kt_val;
88
static int hf_kt_key_str;
89
static int hf_kt_val_str;
90
static int hf_kt_hits;
91
static int hf_kt_nsiz;
92
static int hf_kt_name;
93
static int hf_kt_size;
94
static int hf_kt_log;
95
static int hf_kt_rec;
96
97
/* Magic Values */
98
0
#define KT_MAGIC_REPL_WAIT      0xB0
99
0
#define KT_MAGIC_REPLICATION    0xB1
100
0
#define KT_MAGIC_PLAY_SCRIPT    0xB4
101
0
#define KT_MAGIC_SET_BULK       0xB8
102
0
#define KT_MAGIC_REMOVE_BULK    0xB9
103
0
#define KT_MAGIC_GET_BULK       0xBA
104
0
#define KT_MAGIC_ERROR          0xBF
105
106
static const value_string kt_magic_vals[] = {
107
    {KT_MAGIC_REPL_WAIT,   "replication - waiting for updates"},
108
    {KT_MAGIC_REPLICATION, "replication"},
109
    {KT_MAGIC_PLAY_SCRIPT, "play_script"},
110
    {KT_MAGIC_SET_BULK,    "set_bulk"   },
111
    {KT_MAGIC_REMOVE_BULK, "remove_bulk"},
112
    {KT_MAGIC_GET_BULK,    "get_bulk"   },
113
    {KT_MAGIC_ERROR,       "error"      },
114
    {0, NULL}
115
};
116
117
/* Operation type (determined/generated by the dissector) */
118
0
#define KT_OPER_REQUEST  0x00
119
0
#define KT_OPER_RESPONSE 0x01
120
121
static const value_string kt_oper_vals[] = {
122
    {KT_OPER_REQUEST,   "request"},
123
    {KT_OPER_RESPONSE,  "response"},
124
    {0, NULL}
125
};
126
127
/* Preferences */
128
/*
129
 * The default port numbers are not IANA registered but used by the
130
 * default configuration of the KT server all the same.
131
 */
132
16
#define DEFAULT_KT_PORT_RANGE "1978-1979"
133
static bool kt_present_key_val_as_ascii;
134
135
/* Dissection routines */
136
static int
137
dissect_kt_replication_wait(tvbuff_t *tvb, proto_tree *tree, int offset)
138
0
{
139
0
    int new_offset;
140
0
    uint64_t ts;
141
0
    nstime_t ns_ts;
142
143
0
    new_offset = offset;
144
145
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
146
0
    new_offset++;
147
148
0
    ts = tvb_get_ntoh64(tvb, new_offset);
149
0
    ns_ts.secs = (time_t)(ts/1000000000);
150
0
    ns_ts.nsecs = (int)(ts%1000000000);
151
0
    proto_tree_add_time(tree, hf_kt_ts, tvb, new_offset, 8, &ns_ts);
152
0
    new_offset += 8;
153
154
0
    return new_offset;
155
0
}
156
157
static int
158
dissect_kt_replication(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
159
0
{
160
0
    int new_offset;
161
0
    uint32_t next32, size;
162
0
    uint64_t ts;
163
0
    nstime_t ns_ts;
164
0
    proto_item *pi;
165
166
0
    new_offset = offset;
167
168
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
169
0
    new_offset++;
170
171
0
    if (tvb_reported_length_remaining(tvb, new_offset) > 0) {
172
0
        next32 = tvb_get_ntohl(tvb, new_offset);
173
0
        if (next32 <= 1) { /* This means request. the 32 bits are flags */
174
0
            proto_tree_add_item(tree, hf_kt_flags, tvb, new_offset, 4, ENC_BIG_ENDIAN);
175
0
            new_offset += 4;
176
177
0
            proto_tree_add_item(tree, hf_kt_ts, tvb, new_offset, 8, ENC_BIG_ENDIAN);
178
0
            new_offset += 8;
179
180
0
            proto_tree_add_item(tree, hf_kt_sid, tvb, new_offset, 2, ENC_BIG_ENDIAN);
181
0
            new_offset += 2;
182
0
        } else { /* This is a response. The 32 bits are the first half of the ts */
183
0
            ts = tvb_get_ntoh64(tvb, new_offset);
184
0
            ns_ts.secs = (time_t)(ts/1000000000);
185
0
            ns_ts.nsecs = (int)(ts%1000000000);
186
0
            proto_tree_add_time(tree, hf_kt_ts, tvb, new_offset, 8, &ns_ts);
187
0
            new_offset += 8;
188
189
0
            size = tvb_get_ntohl(tvb, new_offset);
190
0
            proto_tree_add_uint(tree, hf_kt_size, tvb, new_offset, 4, size);
191
0
            new_offset += 4;
192
193
            /* Throws if the length claimed in the packet is not there. */
194
0
            tvb_ensure_bytes_exist64(tvb, new_offset, size);
195
0
            proto_tree_add_item(tree, hf_kt_log, tvb, new_offset, size, ENC_NA);
196
0
            new_offset += size;
197
0
        }
198
0
    } else {
199
        /* This is an empty ack to the message with magic 0xB0. */
200
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
201
0
        proto_item_set_generated(pi);
202
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
203
0
    }
204
205
0
    return new_offset;
206
0
}
207
208
static int
209
dissect_kt_set_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
210
0
{
211
0
    uint32_t next32, rnum, ksiz, vsiz;
212
0
    int new_offset, rec_start_offset;
213
0
    proto_item *ti;
214
0
    proto_item *pi;
215
0
    proto_tree *rec_tree;
216
217
0
    new_offset = offset;
218
219
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
220
0
    new_offset++;
221
222
0
    next32 = tvb_get_ntohl(tvb, new_offset);
223
224
0
    if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) {
225
        /* There's more data after the 32 bits. This is a request */
226
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST);
227
0
        proto_item_set_generated(pi);
228
229
0
        proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32);
230
0
        new_offset += 4;
231
232
0
        rnum = tvb_get_ntohl(tvb, new_offset);
233
0
        proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum);
234
0
        new_offset += 4;
235
236
0
        while (rnum > 0) {
237
            /* Create a sub-tree for each record */
238
0
            ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
239
0
            rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
240
0
            rec_start_offset = new_offset;
241
242
0
            proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN);
243
0
            new_offset += 2;
244
245
0
            ksiz = tvb_get_ntohl(tvb, new_offset);
246
0
            proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
247
0
            new_offset += 4;
248
249
0
            vsiz = tvb_get_ntohl(tvb, new_offset);
250
0
            proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz);
251
0
            new_offset += 4;
252
253
0
            proto_tree_add_item(rec_tree, hf_kt_xt, tvb, new_offset, 8, ENC_BIG_ENDIAN);
254
0
            new_offset += 8;
255
256
            /* Throws if the length claimed in the packet is not there. */
257
0
            tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
258
0
            proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
259
0
            if (kt_present_key_val_as_ascii) {
260
0
                pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
261
0
                proto_item_set_generated(pi);
262
0
            }
263
0
            new_offset += ksiz;
264
265
            /* Throws if the length claimed in the packet is not there. */
266
0
            tvb_ensure_bytes_exist64(tvb, new_offset, vsiz);
267
0
            proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA);
268
0
            if (kt_present_key_val_as_ascii) {
269
0
                pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII);
270
0
                proto_item_set_generated(pi);
271
0
            }
272
0
            new_offset += vsiz;
273
274
0
            proto_item_set_len(ti, new_offset - rec_start_offset);
275
0
            rnum--;
276
0
        }
277
0
    } else {
278
        /* Nothing remaining after the 32 bits. This is a response. */
279
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
280
0
        proto_item_set_generated(pi);
281
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
282
283
0
        proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32);
284
0
        new_offset += 4;
285
0
    }
286
287
0
    return new_offset;
288
0
}
289
290
static int
291
dissect_kt_play_script(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
292
0
{
293
0
    uint32_t next32, rnum, ksiz, vsiz, nsiz;
294
0
    int new_offset, rec_start_offset;
295
0
    proto_item *ti;
296
0
    proto_item *pi;
297
0
    proto_tree *rec_tree;
298
299
0
    new_offset = offset;
300
301
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
302
0
    new_offset++;
303
304
0
    next32 = tvb_get_ntohl(tvb, new_offset);
305
306
0
    if (next32 == 0) {
307
0
        if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) {
308
            /* There's more data after the 32 bits. This is a request */
309
0
            pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST);
310
0
            proto_item_set_generated(pi);
311
312
0
            proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32);
313
0
            new_offset += 4;
314
315
0
            nsiz = tvb_get_ntohl(tvb, new_offset);
316
0
            proto_tree_add_uint(tree, hf_kt_nsiz, tvb, new_offset, 4, nsiz);
317
0
            new_offset += 4;
318
319
0
            rnum = tvb_get_ntohl(tvb, new_offset);
320
0
            proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum);
321
0
            new_offset += 4;
322
323
            /* Throws if the length claimed in the packet is not there. */
324
0
            tvb_ensure_bytes_exist64(tvb, new_offset, nsiz);
325
0
            proto_tree_add_item(tree, hf_kt_name, tvb, new_offset, nsiz, ENC_ASCII);
326
0
            new_offset += nsiz;
327
328
0
            while (rnum > 0) {
329
                /* Create a sub-tree for each record */
330
0
                ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
331
0
                rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
332
0
                rec_start_offset = new_offset;
333
334
0
                ksiz = tvb_get_ntohl(tvb, new_offset);
335
0
                proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
336
0
                new_offset += 4;
337
338
0
                vsiz = tvb_get_ntohl(tvb, new_offset);
339
0
                proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz);
340
0
                new_offset += 4;
341
342
                /* Throws if the length claimed in the packet is not there. */
343
0
                tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
344
0
                proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
345
0
                if (kt_present_key_val_as_ascii) {
346
0
                    pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
347
0
                    proto_item_set_generated(pi);
348
0
                }
349
0
                new_offset += ksiz;
350
351
                /* Throws if the length claimed in the packet is not there. */
352
0
                tvb_ensure_bytes_exist64(tvb, new_offset, vsiz);
353
0
                proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA);
354
0
                if (kt_present_key_val_as_ascii) {
355
0
                    pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII);
356
0
                    proto_item_set_generated(pi);
357
0
                }
358
0
                new_offset += vsiz;
359
360
0
                proto_item_set_len(ti, new_offset - rec_start_offset);
361
0
                rnum--;
362
0
            }
363
0
        } else {
364
            /* Nothing remaining after the 32 bits. This is a response with no records. */
365
0
            pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
366
0
            proto_item_set_generated(pi);
367
0
            col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
368
369
0
            proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, next32);
370
0
            new_offset += 4;
371
0
        }
372
0
    } else { /* response - one or more records */
373
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
374
0
        proto_item_set_generated(pi);
375
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
376
377
0
        rnum = tvb_get_ntohl(tvb, new_offset);
378
0
        proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, rnum);
379
0
        new_offset += 4;
380
381
0
        while (rnum > 0) {
382
            /* Create a sub-tree for each record */
383
0
            ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
384
0
            rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
385
0
            rec_start_offset = new_offset;
386
387
0
            ksiz = tvb_get_ntohl(tvb, new_offset);
388
0
            proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
389
0
            new_offset += 4;
390
391
0
            vsiz = tvb_get_ntohl(tvb, new_offset);
392
0
            proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz);
393
0
            new_offset += 4;
394
395
            /* Throws if the length claimed in the packet is not there. */
396
0
            tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
397
0
            proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
398
0
            if (kt_present_key_val_as_ascii) {
399
0
                pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
400
0
                proto_item_set_generated(pi);
401
0
            }
402
0
            new_offset += ksiz;
403
404
            /* Throws if the length claimed in the packet is not there. */
405
0
            tvb_ensure_bytes_exist64(tvb, new_offset, vsiz);
406
0
            proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA);
407
0
            if (kt_present_key_val_as_ascii) {
408
0
                pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII);
409
0
                proto_item_set_generated(pi);
410
0
            }
411
0
            new_offset += vsiz;
412
413
0
            proto_item_set_len(ti, new_offset - rec_start_offset);
414
0
            rnum--;
415
0
        }
416
0
    }
417
418
0
    return new_offset;
419
0
}
420
421
static int
422
dissect_kt_get_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
423
0
{
424
0
    uint32_t next32, rnum, ksiz, vsiz;
425
0
    uint64_t xt;
426
0
    nstime_t ts;
427
0
    int new_offset, rec_start_offset;
428
0
    proto_item *ti;
429
0
    proto_item *pi;
430
0
    proto_tree *rec_tree;
431
432
0
    new_offset = offset;
433
434
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
435
0
    new_offset++;
436
437
0
    next32 = tvb_get_ntohl(tvb, new_offset);
438
439
0
    if (next32 == 0) {
440
0
        if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* request */
441
0
            pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST);
442
0
            proto_item_set_generated(pi);
443
444
0
            proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32);
445
0
            new_offset += 4;
446
447
0
            rnum = tvb_get_ntohl(tvb, new_offset);
448
0
            proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum);
449
0
            new_offset += 4;
450
451
0
            while (rnum > 0) {
452
                /* Create a sub-tree for each record */
453
0
                ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
454
0
                rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
455
0
                rec_start_offset = new_offset;
456
457
0
                proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN);
458
0
                new_offset += 2;
459
460
0
                ksiz = tvb_get_ntohl(tvb, new_offset);
461
0
                proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
462
0
                new_offset += 4;
463
464
                /* Throws if the length claimed in the packet is not there. */
465
0
                tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
466
0
                proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
467
0
                if (kt_present_key_val_as_ascii) {
468
0
                    pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
469
0
                    proto_item_set_generated(pi);
470
0
                }
471
0
                new_offset += ksiz;
472
473
0
                proto_item_set_len(ti, new_offset - rec_start_offset);
474
0
                rnum--;
475
0
            }
476
0
        } else { /* response - no records */
477
0
            pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
478
0
            proto_item_set_generated(pi);
479
0
            col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
480
481
0
            proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32);
482
0
            new_offset += 4;
483
0
        }
484
0
    } else { /* response - one or more records */
485
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
486
0
        proto_item_set_generated(pi);
487
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
488
489
0
        rnum = tvb_get_ntohl(tvb, new_offset);
490
0
        proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, rnum);
491
0
        new_offset += 4;
492
493
0
        while (rnum > 0) {
494
            /* Create a sub-tree for each record */
495
0
            ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
496
0
            rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
497
0
            rec_start_offset = new_offset;
498
499
0
            proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN);
500
0
            new_offset += 2;
501
502
0
            ksiz = tvb_get_ntohl(tvb, new_offset);
503
0
            proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
504
0
            new_offset += 4;
505
506
0
            vsiz = tvb_get_ntohl(tvb, new_offset);
507
0
            proto_tree_add_uint(rec_tree, hf_kt_vsiz, tvb, new_offset, 4, vsiz);
508
0
            new_offset += 4;
509
510
0
            xt = tvb_get_ntoh64(tvb, new_offset);
511
0
            ts.secs = (time_t)(xt&0xFFFFFFFF);
512
0
            ts.nsecs = 0;
513
0
            proto_tree_add_time(rec_tree, hf_kt_xt_resp, tvb, new_offset, 8, &ts);
514
0
            new_offset += 8;
515
516
            /* Throws if the length claimed in the packet is not there. */
517
0
            tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
518
0
            proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
519
0
            if (kt_present_key_val_as_ascii) {
520
0
                pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
521
0
                proto_item_set_generated(pi);
522
0
            }
523
0
            new_offset += ksiz;
524
525
            /* Throws if the length claimed in the packet is not there. */
526
0
            tvb_ensure_bytes_exist64(tvb, new_offset, vsiz);
527
0
            proto_tree_add_item(rec_tree, hf_kt_val, tvb, new_offset, vsiz, ENC_NA);
528
0
            if (kt_present_key_val_as_ascii) {
529
0
                pi = proto_tree_add_item(rec_tree, hf_kt_val_str, tvb, new_offset, vsiz, ENC_ASCII);
530
0
                proto_item_set_generated(pi);
531
0
            }
532
0
            new_offset += vsiz;
533
534
0
            proto_item_set_len(ti, new_offset - rec_start_offset);
535
0
            rnum--;
536
0
        }
537
0
    }
538
539
0
    return new_offset;
540
0
}
541
542
static int
543
dissect_kt_remove_bulk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
544
0
{
545
0
    uint32_t next32, rnum, ksiz;
546
0
    int new_offset, rec_start_offset;
547
0
    proto_item *ti;
548
0
    proto_item *pi;
549
0
    proto_tree *rec_tree;
550
551
0
    new_offset = offset;
552
553
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
554
0
    new_offset++;
555
556
0
    next32 = tvb_get_ntohl(tvb, new_offset);
557
558
0
    if (tvb_reported_length_remaining(tvb, (new_offset + 4)) > 0) { /* request */
559
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_REQUEST);
560
0
        proto_item_set_generated(pi);
561
562
0
        proto_tree_add_uint(tree, hf_kt_flags, tvb, new_offset, 4, next32);
563
0
        new_offset += 4;
564
565
0
        rnum = tvb_get_ntohl(tvb, new_offset);
566
0
        proto_tree_add_uint(tree, hf_kt_rnum, tvb, new_offset, 4, rnum);
567
0
        new_offset += 4;
568
569
0
        while (rnum > 0) {
570
            /* Create a sub-tree for each record */
571
0
            ti = proto_tree_add_item(tree, hf_kt_rec, tvb, new_offset, -1, ENC_NA);
572
0
            rec_tree = proto_item_add_subtree(ti, ett_kt_rec);
573
0
            rec_start_offset = new_offset;
574
575
0
            proto_tree_add_item(rec_tree, hf_kt_dbidx, tvb, new_offset, 2, ENC_BIG_ENDIAN);
576
0
            new_offset += 2;
577
578
0
            ksiz = tvb_get_ntohl(tvb, new_offset);
579
0
            proto_tree_add_uint(rec_tree, hf_kt_ksiz, tvb, new_offset, 4, ksiz);
580
0
            new_offset += 4;
581
582
            /* Throws if the length claimed in the packet is not there. */
583
0
            tvb_ensure_bytes_exist64(tvb, new_offset, ksiz);
584
0
            proto_tree_add_item(rec_tree, hf_kt_key, tvb, new_offset, ksiz, ENC_NA);
585
0
            if (kt_present_key_val_as_ascii) {
586
0
                pi = proto_tree_add_item(rec_tree, hf_kt_key_str, tvb, new_offset, ksiz, ENC_ASCII);
587
0
                proto_item_set_generated(pi);
588
0
            }
589
0
            new_offset += ksiz;
590
591
0
            proto_item_set_len(ti, new_offset - rec_start_offset);
592
0
            rnum--;
593
0
        }
594
0
    } else { /* response */
595
0
        pi = proto_tree_add_uint(tree, hf_kt_type, tvb, offset, 1, KT_OPER_RESPONSE);
596
0
        proto_item_set_generated(pi);
597
0
        col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[response]");
598
599
0
        proto_tree_add_uint(tree, hf_kt_hits, tvb, new_offset, 4, next32);
600
0
        new_offset += 4;
601
0
    }
602
603
0
    return new_offset;
604
0
}
605
606
static int
607
dissect_kt_error(tvbuff_t *tvb, proto_tree *tree, int offset)
608
0
{
609
0
    int new_offset;
610
611
0
    new_offset = offset;
612
613
0
    proto_tree_add_item(tree, hf_kt_magic, tvb, new_offset, 1, ENC_BIG_ENDIAN);
614
0
    new_offset++;
615
616
0
    return new_offset;
617
0
}
618
619
static int
620
dissect_kt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
621
2
{
622
2
    int       magic;
623
2
    proto_item *ti;
624
2
    proto_tree *kt_tree;
625
2
    int offset, offset_start;
626
627
2
    offset = 0;
628
629
2
    while (tvb_reported_length_remaining(tvb, offset) > 0) {
630
2
        magic = tvb_get_uint8(tvb, offset);
631
632
        /* If the magic is not one of the known values, exit */
633
2
        if (try_val_to_str(magic, kt_magic_vals) == NULL)
634
2
            return offset;
635
636
        /* Otherwise, the magic value is known. Continue */
637
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "KT");
638
0
        col_set_str(pinfo->cinfo, COL_INFO, try_val_to_str(magic, kt_magic_vals));
639
640
0
        ti = proto_tree_add_item(tree, proto_kt, tvb, offset, -1, ENC_NA);
641
0
        kt_tree = proto_item_add_subtree(ti, ett_kt);
642
643
0
        offset_start=offset;
644
645
0
        switch (magic) {
646
0
            case KT_MAGIC_REPL_WAIT:
647
0
                offset = dissect_kt_replication_wait(tvb, kt_tree, offset);
648
0
                break;
649
0
            case KT_MAGIC_REPLICATION:
650
0
                offset = dissect_kt_replication(tvb, pinfo, kt_tree, offset);
651
0
                break;
652
0
            case KT_MAGIC_PLAY_SCRIPT:
653
0
                offset = dissect_kt_play_script(tvb, pinfo, kt_tree, offset);
654
0
                break;
655
0
            case KT_MAGIC_SET_BULK:
656
0
                offset = dissect_kt_set_bulk(tvb, pinfo, kt_tree, offset);
657
0
                break;
658
0
            case KT_MAGIC_REMOVE_BULK:
659
0
                offset = dissect_kt_remove_bulk(tvb, pinfo, kt_tree, offset);
660
0
                break;
661
0
            case KT_MAGIC_GET_BULK:
662
0
                offset = dissect_kt_get_bulk(tvb, pinfo, kt_tree, offset);
663
0
                break;
664
0
            case KT_MAGIC_ERROR:
665
0
                offset = dissect_kt_error(tvb, kt_tree, offset);
666
0
                break;
667
0
        }
668
669
0
        proto_item_set_len(ti, offset-offset_start);
670
0
    }
671
672
0
    return tvb_captured_length(tvb);
673
2
}
674
675
void
676
proto_register_kt(void)
677
16
{
678
16
    module_t *kt_module; /* preferences */
679
680
16
    static hf_register_info hf[] = {
681
16
        {   &hf_kt_magic,
682
16
            {   "magic", "kt.magic", FT_UINT8, BASE_HEX,
683
16
                VALS(kt_magic_vals), 0x0, "identifier", HFILL
684
16
            }
685
16
        },
686
16
        {   &hf_kt_type,
687
16
            {   "type", "kt.type", FT_UINT8, BASE_HEX,
688
16
                VALS(kt_oper_vals), 0x0, "request/response", HFILL
689
16
            }
690
16
        },
691
16
        {   &hf_kt_flags,
692
16
            {   "flags", "kt.flags", FT_UINT32, BASE_HEX,
693
16
                NULL, 0x0, "flags of bitwise-or", HFILL
694
16
            }
695
16
        },
696
16
        {   &hf_kt_rnum,
697
16
            {   "rnum", "kt.rnum", FT_UINT32, BASE_DEC, NULL, 0x0,
698
16
                "the number of records", HFILL
699
16
            }
700
16
        },
701
16
        {   &hf_kt_dbidx,
702
16
            {   "dbidx", "kt.dbidx", FT_UINT16,
703
16
                BASE_DEC, NULL, 0x0, "the index of the target database", HFILL
704
16
            }
705
16
        },
706
16
        {   &hf_kt_sid,
707
16
            {   "sid", "kt.sid", FT_UINT16, BASE_DEC,
708
16
                NULL, 0x0, "the server ID number", HFILL
709
16
            }
710
16
        },
711
16
        {   &hf_kt_ts,
712
16
            {   "ts", "kt.ts", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
713
16
                NULL, 0x0, "the timestamp of the log", HFILL
714
16
            }
715
16
        },
716
16
        {   &hf_kt_xt,
717
16
            {   "xt", "kt.xt", FT_UINT64, BASE_DEC,
718
16
                NULL, 0x0, "the expiration time in seconds", HFILL
719
16
            }
720
16
        },
721
16
        {   &hf_kt_xt_resp,
722
16
            {   "xt", "kt.xt_resp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
723
16
                NULL, 0x0, "the expiration time", HFILL
724
16
            }
725
16
        },
726
16
        {   &hf_kt_ksiz,
727
16
            {   "ksiz", "kt.ksiz", FT_UINT32, BASE_DEC,
728
16
                NULL, 0x0, "the size of the key",HFILL
729
16
            }
730
16
        },
731
16
        {   &hf_kt_vsiz,
732
16
            {   "vsiz", "kt.vsiz", FT_UINT32, BASE_DEC,
733
16
                NULL, 0x0, "the size of the value", HFILL
734
16
            }
735
16
        },
736
16
        {   &hf_kt_key,
737
16
            {   "key", "kt.key", FT_BYTES, BASE_NONE,
738
16
                NULL, 0x0, "the key", HFILL
739
16
            }
740
16
        },
741
16
        {   &hf_kt_val,
742
16
            {   "value", "kt.value", FT_BYTES, BASE_NONE,
743
16
                NULL, 0x0, "the value", HFILL
744
16
            }
745
16
        },
746
16
        {   &hf_kt_key_str,
747
16
            {   "key", "kt.key_str", FT_STRING, BASE_NONE,
748
16
                NULL, 0x0, "ASCII representation of the key", HFILL
749
16
            }
750
16
        },
751
16
        {   &hf_kt_val_str,
752
16
            {   "value", "kt.value_str", FT_STRING, BASE_NONE,
753
16
                NULL, 0x0, "ASCII representation of the value", HFILL
754
16
            }
755
16
        },
756
16
        {   &hf_kt_hits,
757
16
            {   "hits", "kt.hits", FT_UINT32, BASE_DEC,
758
16
                NULL, 0x0, "the number of records", HFILL
759
16
            }
760
16
        },
761
16
        {   &hf_kt_size,
762
16
            {   "size", "kt.size", FT_UINT32, BASE_DEC,
763
16
                NULL, 0x0, "the size of the replication log", HFILL
764
16
            }
765
16
        },
766
16
        {   &hf_kt_log,
767
16
            {   "log", "kt.log", FT_BYTES, BASE_NONE,
768
16
                NULL, 0x0, "the replication log", HFILL
769
16
            }
770
16
        },
771
16
        {   &hf_kt_nsiz,
772
16
            {   "nsiz", "kt.nsiz", FT_UINT32, BASE_DEC,
773
16
                NULL, 0x0, "the size of the procedure name", HFILL
774
16
            }
775
16
        },
776
16
        {   &hf_kt_name,
777
16
            {   "name", "kt.name", FT_STRING, BASE_NONE,
778
16
                NULL, 0x0, "the procedure name", HFILL
779
16
            }
780
16
        },
781
16
        {   &hf_kt_rec,
782
16
            {   "record", "kt.record", FT_NONE, BASE_NONE,
783
16
                NULL, 0x0, "a record", HFILL
784
16
            }
785
16
        }
786
16
    };
787
788
16
    static int *ett[] = {
789
16
        &ett_kt,
790
16
        &ett_kt_rec
791
16
    };
792
793
16
    proto_kt = proto_register_protocol("Kyoto Tycoon Protocol", "Kyoto Tycoon", "kt");
794
16
    kt_handle = register_dissector("kt", dissect_kt, proto_kt);
795
16
    proto_register_field_array(proto_kt, hf, array_length(hf));
796
16
    proto_register_subtree_array(ett, array_length(ett));
797
798
    /* Preferences */
799
16
    kt_module = prefs_register_protocol(proto_kt, NULL);
800
801
16
    prefs_register_bool_preference(kt_module, "present_key_val_as_ascii",
802
16
                                   "Attempt to also show ASCII string representation of keys and values",
803
16
                                   "KT allows binary values in keys and values. Attempt to show an ASCII representation anyway (which might be prematurely terminated by a NULL!",
804
16
                                   &kt_present_key_val_as_ascii);
805
16
}
806
807
void
808
proto_reg_handoff_kt(void)
809
16
{
810
16
    dissector_add_uint_range_with_preference("tcp.port", DEFAULT_KT_PORT_RANGE, kt_handle);
811
16
}
812
813
/*
814
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
815
 *
816
 * Local variables:
817
 * c-basic-offset: 4
818
 * tab-width: 8
819
 * indent-tabs-mode: nil
820
 * End:
821
 *
822
 * vi: set shiftwidth=4 tabstop=8 expandtab:
823
 * :indentSize=4:tabSize=8:noTabs=true:
824
 */