Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-mcpe.c
Line
Count
Source
1
/*
2
 * packet-mcpe.c
3
 *
4
 * Routines for Minecraft Pocket Edition protocol packet disassembly.
5
 *
6
 * Nick Carter <ncarter100@gmail.com>
7
 * Copyright 2014 Nick Carter
8
 *
9
 * Using info found at:
10
 *   http://wiki.vg/Pocket_Minecraft_Protocol#Packet_Encapsulation
11
 *
12
 * Wireshark - Network traffic analyzer
13
 * By Gerald Combs <gerald@wireshark.org>
14
 * Copyright 1998 Gerald Combs
15
 *
16
 * SPDX-License-Identifier: GPL-2.0-or-later
17
 */
18
#include "config.h"
19
20
#include <epan/conversation.h>
21
#include <epan/expert.h>
22
#include <epan/packet.h>
23
#include <epan/prefs.h>
24
25
#include <wsutil/array.h>
26
27
#include "packet-raknet.h"
28
29
/* Minecraft Pocket Edition Protocol
30
 *
31
 * See also:
32
 * http://wiki.vg/Pocket_Edition_Protocol_Documentation
33
 */
34
35
#define MCPE_UDP_PORT_DEFAULT 19132 /* Not IANA registered */
36
static unsigned mcpe_udp_port_requested = MCPE_UDP_PORT_DEFAULT;
37
38
static int proto_mcpe;
39
static int ett_mcpe; /* Should this node be expanded */
40
static int ett_mcpe_batch;
41
static int ett_mcpe_batch_record;
42
static int ett_mcpe_login;
43
static int ett_mcpe_string;
44
45
/*
46
 * Dissectors
47
 */
48
static dissector_handle_t mcpe_handle;
49
static dissector_table_t mcpe_packet_dissectors;
50
51
/*
52
 * Expert fields
53
 */
54
static expert_field ei_mcpe_unknown_packet_id;
55
static expert_field ei_mcpe_decompression_failed;
56
static expert_field ei_mcpe_encrypted_packet;
57
58
/*
59
 * Common Header fields
60
 */
61
static int hf_mcpe_message_id;
62
static int hf_mcpe_packet_id;
63
static int hf_mcpe_string_length;
64
static int hf_mcpe_UTF8_string;
65
static int hf_mcpe_byte_string;
66
67
/*
68
 * Fields specific to a packet ID
69
 */
70
static int hf_mcpe_protocol_version;
71
static int hf_mcpe_login_data_length;
72
static int hf_mcpe_login_data;
73
static int hf_mcpe_login;
74
static int hf_mcpe_chain_JSON;
75
static int hf_mcpe_client_data_JWT;
76
static int hf_mcpe_public_key;
77
static int hf_mcpe_server_token;
78
79
static int hf_mcpe_batch_length;
80
static int hf_mcpe_batch_body;
81
static int hf_mcpe_batch_records;
82
static int hf_mcpe_batch_record_length;
83
static int hf_mcpe_batch_record;
84
85
/*
86
 * RakNet Message ID
87
 */
88
static const value_string mcpe_message_names[] = {
89
    { 0xFE, "Wrapper" },
90
    { 0, NULL }
91
};
92
93
/*
94
 * Forward declarations
95
 */
96
void proto_register_mcpe(void);
97
void proto_reg_handoff_mcpe(void);
98
static int mcpe_dissect_login(tvbuff_t*, packet_info*, proto_tree*, void*);
99
static int mcpe_dissect_server_to_client_handshake(tvbuff_t*, packet_info*, proto_tree*, void*);
100
static int mcpe_dissect_batch(tvbuff_t*, packet_info*, proto_tree*, void*);
101
102
/*
103
 * Protocol definition and handlers.
104
 */
105
struct mcpe_handler_entry {
106
    value_string vs;
107
    dissector_t dissector_fp;
108
};
109
110
static const struct mcpe_handler_entry mcpe_packet_handlers[] = {
111
    { { 0x01, "Login" },
112
      mcpe_dissect_login },
113
    { { 0x03, "Server to Client Handshake" },
114
      mcpe_dissect_server_to_client_handshake },
115
    { { 0x06, "Batch" },
116
      mcpe_dissect_batch },
117
};
118
119
/*
120
 * Look up table from packet ID to name
121
 */
122
static value_string mcpe_packet_names[array_length(mcpe_packet_handlers)+1];
123
124
/*
125
 * Session state
126
 */
127
typedef struct mcpe_session_state {
128
    bool encrypted;
129
    uint32_t encryption_starts_after; /* Frame number */
130
} mcpe_session_state_t;
131
132
static mcpe_session_state_t*
133
2
mcpe_get_session_state(packet_info *pinfo) {
134
2
    conversation_t* conversation;
135
2
    mcpe_session_state_t* state;
136
137
2
    conversation = find_or_create_conversation(pinfo);
138
2
    state = (mcpe_session_state_t*)conversation_get_proto_data(conversation, proto_mcpe);
139
140
2
    if (state == NULL) {
141
1
        state = wmem_new(wmem_file_scope(), mcpe_session_state_t);
142
1
        state->encrypted = false;
143
1
        state->encryption_starts_after = 0;
144
145
1
        conversation_add_proto_data(conversation, proto_mcpe, state);
146
1
    }
147
148
2
    return state;
149
2
}
150
151
/*
152
 * Packet dissectors
153
 */
154
static void
155
0
mcpe_dissect_string(packet_info *pinfo, proto_tree *tree, int hf, tvbuff_t *tvb, int *offset, unsigned encoding) {
156
0
    proto_item *ti;
157
0
    proto_tree *string_tree;
158
0
    uint32_t length;
159
0
    uint32_t length_width;
160
161
0
    if (encoding & ENC_LITTLE_ENDIAN) {
162
        /*
163
         * Yes it's crazy. Lengths of string come with two flavors:
164
         * big-endian uint16 and little-endian uint32.
165
         */
166
0
        length = tvb_get_letohl(tvb, *offset);
167
0
        length_width = 4;
168
0
    }
169
0
    else {
170
0
        length = tvb_get_ntohs(tvb, *offset);
171
0
        length_width = 2;
172
0
    }
173
174
0
    if (encoding & ENC_UTF_8) {
175
0
        const char *string;
176
177
0
        string = (char*)tvb_get_string_enc(pinfo->pool, tvb, *offset + length_width, length, ENC_UTF_8);
178
179
0
        ti = proto_tree_add_string(tree, hf, tvb, *offset, length + length_width, string);
180
0
        string_tree = proto_item_add_subtree(ti, ett_mcpe_string);
181
182
0
        proto_tree_add_item(string_tree, hf_mcpe_string_length, tvb,
183
0
                            *offset, length_width, encoding);
184
0
        *offset += length_width;
185
186
0
        proto_tree_add_item(string_tree, hf_mcpe_UTF8_string, tvb,
187
0
                            *offset, length, ENC_UTF_8);
188
0
        *offset += length;
189
0
    }
190
0
    else {
191
0
        uint8_t *bytes;
192
193
0
        bytes = (uint8_t*)tvb_memdup(pinfo->pool, tvb, *offset + length_width, length);
194
195
0
        ti = proto_tree_add_bytes_with_length(tree, hf, tvb, *offset, length + length_width, bytes, length);
196
0
        string_tree = proto_item_add_subtree(ti, ett_mcpe_string);
197
198
0
        proto_tree_add_item(string_tree, hf_mcpe_string_length, tvb,
199
0
                            *offset, length_width, encoding);
200
0
        *offset += length_width;
201
202
0
        proto_tree_add_item(string_tree, hf_mcpe_byte_string, tvb,
203
0
                            *offset, length, ENC_NA);
204
0
        *offset += length;
205
0
    }
206
0
}
207
208
static int
209
mcpe_dissect_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
210
0
{
211
0
    if (tree) {
212
0
        int item_size;
213
0
        int offset = 1;
214
0
        uint32_t comp_length;
215
0
        proto_item *ti;
216
0
        tvbuff_t *login_tvb;
217
218
0
        item_size = 4;
219
0
        proto_tree_add_item(tree, hf_mcpe_protocol_version, tvb,
220
0
                            offset, item_size, ENC_BIG_ENDIAN);
221
0
        offset += item_size;
222
223
0
        item_size = 4;
224
0
        proto_tree_add_item_ret_uint(tree, hf_mcpe_login_data_length, tvb,
225
0
                                     offset, item_size, ENC_BIG_ENDIAN, &comp_length);
226
0
        offset += item_size;
227
228
0
        item_size = comp_length;
229
0
        ti = proto_tree_add_item(tree, hf_mcpe_login_data, tvb,
230
0
                                 offset, item_size, ENC_NA);
231
232
0
        login_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, comp_length);
233
0
        if (login_tvb) {
234
0
            uint32_t decomp_length;
235
0
            proto_tree *login_tree;
236
237
0
            add_new_data_source(pinfo, login_tvb, "MCPE Decompressed login data");
238
0
            decomp_length = tvb_captured_length(login_tvb);
239
240
0
            offset = 0;
241
0
            item_size = decomp_length;
242
0
            ti = proto_tree_add_item(tree, hf_mcpe_login, login_tvb,
243
0
                                     offset, item_size, ENC_NA);
244
0
            login_tree = proto_item_add_subtree(ti, ett_mcpe_login);
245
0
            proto_item_append_text(ti, " (%u octets)", decomp_length);
246
0
            proto_item_set_generated(ti);
247
248
0
            mcpe_dissect_string(pinfo, login_tree, hf_mcpe_chain_JSON     , login_tvb, &offset, ENC_LITTLE_ENDIAN | ENC_UTF_8);
249
0
            mcpe_dissect_string(pinfo, login_tree, hf_mcpe_client_data_JWT, login_tvb, &offset, ENC_LITTLE_ENDIAN | ENC_UTF_8);
250
0
        }
251
0
        else {
252
0
            expert_add_info(pinfo, ti, &ei_mcpe_decompression_failed);
253
0
        }
254
0
    }
255
0
    return tvb_reported_length(tvb);
256
0
}
257
258
static int
259
mcpe_dissect_server_to_client_handshake(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
260
0
{
261
0
    if (tree) {
262
0
        int offset = 1;
263
0
        mcpe_session_state_t *state;
264
265
0
        mcpe_dissect_string(pinfo, tree, hf_mcpe_public_key, tvb, &offset, ENC_BIG_ENDIAN | ENC_UTF_8);
266
0
        mcpe_dissect_string(pinfo, tree, hf_mcpe_server_token, tvb, &offset, ENC_BIG_ENDIAN);
267
268
        /*
269
         * Everything will be encrypted once the server sends this.
270
         */
271
0
        state = mcpe_get_session_state(pinfo);
272
0
        state->encrypted = true;
273
0
        state->encryption_starts_after = pinfo->num;
274
0
    }
275
0
    return tvb_reported_length(tvb);
276
0
}
277
278
static int
279
mcpe_dissect_batch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
280
0
{
281
0
    if (tree) {
282
0
        uint32_t item_size;
283
0
        uint32_t offset = 1;
284
0
        proto_item *ti;
285
0
        uint32_t comp_length;
286
0
        tvbuff_t *batch_tvb;
287
288
0
        item_size = 4;
289
0
        proto_tree_add_item_ret_uint(tree, hf_mcpe_batch_length, tvb,
290
0
                                     offset, item_size, ENC_BIG_ENDIAN, &comp_length);
291
0
        offset += item_size;
292
293
0
        item_size = comp_length;
294
0
        ti = proto_tree_add_item(tree, hf_mcpe_batch_body, tvb,
295
0
                                 offset, item_size, ENC_NA);
296
297
0
        batch_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, comp_length);
298
0
        if (batch_tvb) {
299
0
            uint32_t decomp_length;
300
0
            proto_tree *batch_tree;
301
302
0
            add_new_data_source(pinfo, batch_tvb, "MCPE Decompressed batch");
303
0
            decomp_length = tvb_captured_length(batch_tvb);
304
305
0
            offset = 0;
306
0
            item_size = decomp_length;
307
0
            ti = proto_tree_add_item(tree, hf_mcpe_batch_records, batch_tvb,
308
0
                                     offset, item_size, ENC_NA);
309
0
            batch_tree = proto_item_add_subtree(ti, ett_mcpe_batch);
310
0
            proto_item_append_text(ti, " (%u octets)", decomp_length);
311
0
            proto_item_set_generated(ti);
312
313
0
            col_append_str(pinfo->cinfo, COL_INFO, " [");
314
315
0
            while (true) {
316
0
                uint32_t record_length;
317
0
                tvbuff_t *record_tvb;
318
0
                proto_tree *record_tree;
319
0
                uint32_t packet_id;
320
0
                int dissected;
321
322
0
                item_size = 4;
323
0
                proto_tree_add_item_ret_uint(batch_tree, hf_mcpe_batch_record_length, batch_tvb,
324
0
                                             offset, item_size, ENC_BIG_ENDIAN, &record_length);
325
0
                offset += item_size;
326
327
0
                record_tvb = tvb_new_subset_length(batch_tvb, offset, record_length);
328
0
                offset += record_length;
329
330
                /*
331
                 * Take the whole buffer as a single MCPE packet.
332
                 */
333
0
                ti = proto_tree_add_item(batch_tree, hf_mcpe_batch_record, record_tvb,
334
0
                                         0, -1, ENC_NA);
335
0
                record_tree = proto_item_add_subtree(ti, ett_mcpe_batch_record);
336
337
                /*
338
                 * The first octet is the packet ID.
339
                 */
340
0
                proto_tree_add_item_ret_uint(record_tree, hf_mcpe_packet_id,
341
0
                                             record_tvb, 0, 1, ENC_NA, &packet_id);
342
343
0
                proto_item_append_text(ti, " (%s)",
344
0
                                       val_to_str(pinfo->pool, packet_id, mcpe_packet_names, "Unknown ID: %#x"));
345
0
                col_append_str(pinfo->cinfo, COL_INFO,
346
0
                               val_to_str(pinfo->pool, packet_id, mcpe_packet_names, "Unknown packet ID: %#x"));
347
348
0
                dissected =
349
0
                    dissector_try_uint_with_data(mcpe_packet_dissectors, packet_id,
350
0
                                           record_tvb, pinfo, record_tree, true, data);
351
0
                if (!dissected) {
352
0
                    expert_add_info(pinfo, ti, &ei_mcpe_unknown_packet_id);
353
0
                }
354
355
0
                if (offset < decomp_length) {
356
0
                    col_append_str(pinfo->cinfo, COL_INFO, ", ");
357
0
                }
358
0
                else {
359
0
                    break;
360
0
                }
361
0
            }
362
363
0
            col_append_str(pinfo->cinfo, COL_INFO, "]");
364
0
        }
365
0
        else {
366
0
            expert_add_info(pinfo, ti, &ei_mcpe_decompression_failed);
367
0
        }
368
0
    }
369
0
    return tvb_reported_length(tvb);
370
0
}
371
372
static void
373
mcpe_init_message_names(void)
374
15
{
375
15
    unsigned int i;
376
377
60
    for (i = 0; i < array_length(mcpe_packet_handlers); i++) {
378
45
        mcpe_packet_names[i].value  = mcpe_packet_handlers[i].vs.value;
379
45
        mcpe_packet_names[i].strptr = mcpe_packet_handlers[i].vs.strptr;
380
45
    }
381
15
    mcpe_packet_names[array_length(mcpe_packet_handlers)].value  = 0;
382
15
    mcpe_packet_names[array_length(mcpe_packet_handlers)].strptr = NULL;
383
15
}
384
385
static bool
386
test_mcpe_heur(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void* data)
387
25
{
388
    /*
389
     * 0xFE "Wrapper" is the only message ID that MCPE uses. The sole
390
     * purpose of Wrapper message is to make a RakNet message out of a
391
     * game packet.
392
     */
393
25
    if (tvb_strneql(tvb, 0, "\xFE", 1) == 0) {
394
        /*
395
         * Does the message have a packet ID?
396
         */
397
2
        if (tvb_captured_length(tvb) >= 2) {
398
            /*
399
             * Inspect the packet ID. If it's known to us the message
400
             * can be considered to be an MCPE packet.
401
             */
402
2
            int8_t packet_id = tvb_get_uint8(tvb, 1);
403
404
2
            *(dissector_handle_t*)data =
405
2
                dissector_get_uint_handle(mcpe_packet_dissectors, packet_id);
406
407
2
            if (*(dissector_handle_t*)data) {
408
0
                return true;
409
0
            }
410
2
        }
411
2
    }
412
25
    return false;
413
25
}
414
415
static bool
416
dissect_mcpe_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
417
25
{
418
25
    dissector_handle_t handle;
419
420
25
    if (test_mcpe_heur(tvb, pinfo, tree, &handle)) {
421
0
        proto_item *ti;
422
0
        proto_tree *mcpe_tree;
423
0
        uint32_t message_id;
424
0
        uint32_t packet_id;
425
0
        tvbuff_t *packet_tvb;
426
427
0
        raknet_conversation_set_dissector(pinfo, mcpe_handle);
428
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "MCPE");
429
0
        col_clear(pinfo->cinfo, COL_INFO);
430
431
        /*
432
         * Take the whole buffer as a single MCPE packet.
433
         */
434
0
        ti = proto_tree_add_item(tree, proto_mcpe, tvb, 0, -1, ENC_NA);
435
0
        mcpe_tree = proto_item_add_subtree(ti, ett_mcpe);
436
437
        /*
438
         * The first octet is always 0xFE (Wrapper). We intentionally
439
         * use DISSECTOR_ASSERT() here because test_mcpe_heur() has
440
         * already tested it.
441
         */
442
0
        proto_tree_add_item_ret_uint(mcpe_tree, hf_mcpe_message_id,
443
0
                                     tvb, 0, 1, ENC_NA, &message_id);
444
0
        DISSECTOR_ASSERT(message_id == 0xFE);
445
446
        /*
447
         * The next octet is the packet ID.
448
         */
449
0
        proto_tree_add_item_ret_uint(mcpe_tree, hf_mcpe_packet_id,
450
0
                                     tvb, 1, 1, ENC_NA, &packet_id);
451
452
0
        proto_item_append_text(ti, " (%s)",
453
0
                               val_to_str(pinfo->pool, packet_id, mcpe_packet_names, "Unknown ID: %#x"));
454
0
        col_add_str(pinfo->cinfo, COL_INFO,
455
0
                    val_to_str(pinfo->pool, packet_id, mcpe_packet_names, "Unknown packet ID: %#x"));
456
457
0
        packet_tvb = tvb_new_subset_remaining(tvb, 1);
458
0
        return call_dissector_only(handle, packet_tvb, pinfo, mcpe_tree, data) > 0;
459
0
    }
460
25
    else {
461
25
        return false;
462
25
    }
463
25
}
464
465
static int
466
dissect_mcpe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
467
2
{
468
2
    mcpe_session_state_t *state;
469
470
2
    state = mcpe_get_session_state(pinfo);
471
2
    if (state->encrypted && pinfo->num > state->encryption_starts_after) {
472
        /*
473
         * Encrypted packets don't even have any headers indicating
474
         * they are encrypted. And we don't support the cipher they
475
         * use.
476
         */
477
0
        proto_item *ti;
478
0
        int packet_size;
479
480
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "MCPE");
481
0
        col_set_str(pinfo->cinfo, COL_INFO, "Encrypted packet");
482
483
0
        packet_size = tvb_reported_length(tvb);
484
0
        ti = proto_tree_add_item(tree, proto_mcpe, tvb, 0, packet_size, ENC_NA);
485
0
        proto_item_append_text(ti, ", Encrypted packet (%d octets)", packet_size);
486
0
        expert_add_info(pinfo, ti, &ei_mcpe_encrypted_packet);
487
488
0
        return tvb_captured_length(tvb);
489
0
    }
490
2
    else {
491
        /*
492
         * We reuse our heuristic dissector here because we have no reason
493
         * to implement almost the same dissector twice.
494
         */
495
2
        if (dissect_mcpe_heur(tvb, pinfo, tree, data)) {
496
0
            return tvb_captured_length(tvb);
497
0
        }
498
2
        else {
499
2
            return 0;
500
2
        }
501
2
    }
502
2
}
503
504
void
505
proto_register_mcpe(void)
506
15
{
507
15
    static hf_register_info hf[] = {
508
        /*
509
         * Common Header fields
510
         */
511
15
        { &hf_mcpe_message_id,
512
15
            { "MCPE Message ID", "mcpe.message.id",
513
15
                FT_UINT8, BASE_HEX,
514
15
                VALS(mcpe_message_names), 0x0,
515
15
                NULL, HFILL }
516
15
        },
517
15
        { &hf_mcpe_packet_id,
518
15
            { "MCPE Packet ID", "mcpe.packet.id",
519
15
                FT_UINT8, BASE_HEX,
520
15
                VALS(mcpe_packet_names), 0x0,
521
15
                NULL, HFILL }
522
15
        },
523
15
        { &hf_mcpe_string_length,
524
15
            { "MCPE String length", "mcpe.string.length",
525
15
                FT_UINT32, BASE_DEC,
526
15
                NULL, 0x0,
527
15
                NULL, HFILL }
528
15
        },
529
15
        { &hf_mcpe_UTF8_string,
530
15
            { "MCPE UTF-8 String", "mcpe.string.UTF8",
531
15
                FT_STRING, BASE_NONE,
532
15
                NULL, 0x0,
533
15
                NULL, HFILL }
534
15
        },
535
15
        { &hf_mcpe_byte_string,
536
15
            { "MCPE Byte string", "mcpe.string.bytes",
537
15
                FT_BYTES, BASE_NONE,
538
15
                NULL, 0x0,
539
15
                NULL, HFILL }
540
15
        },
541
        /*
542
         * Fields specific to a packet ID
543
         */
544
15
        { &hf_mcpe_protocol_version,
545
15
            { "MCPE Protocol version", "mcpe.protocol.version",
546
15
                FT_UINT32, BASE_DEC,
547
15
                NULL, 0x0,
548
15
                NULL, HFILL }
549
15
        },
550
15
        { &hf_mcpe_login_data_length,
551
15
            { "MCPE Compressed login data length", "mcpe.login.data.length",
552
15
                FT_UINT32, BASE_DEC,
553
15
                NULL, 0x0,
554
15
                NULL, HFILL }
555
15
        },
556
15
        { &hf_mcpe_login_data,
557
15
            { "MCPE Compressed login data", "mcpe.login.data",
558
15
                FT_NONE, BASE_NONE,
559
15
                NULL, 0x0,
560
15
                NULL, HFILL }
561
15
        },
562
15
        { &hf_mcpe_login,
563
15
            { "MCPE Decompressed login data", "mcpe.login",
564
15
                FT_NONE, BASE_NONE,
565
15
                NULL, 0x0,
566
15
                NULL, HFILL }
567
15
        },
568
15
        { &hf_mcpe_chain_JSON,
569
15
            { "MCPE Chain JSON", "mcpe.chain.JSON",
570
15
                FT_STRING, BASE_NONE,
571
15
                NULL, 0x0,
572
15
                NULL, HFILL }
573
15
        },
574
15
        { &hf_mcpe_client_data_JWT,
575
15
            { "MCPE Client data JWT", "mcpe.client.data.JWT",
576
15
                FT_STRING, BASE_NONE,
577
15
                NULL, 0x0,
578
15
                NULL, HFILL }
579
15
        },
580
15
        { &hf_mcpe_public_key,
581
15
            { "MCPE Public key", "mcpe.public.key",
582
15
                FT_STRING, BASE_NONE,
583
15
                NULL, 0x0,
584
15
                NULL, HFILL }
585
15
        },
586
15
        { &hf_mcpe_server_token,
587
15
            { "MCPE Server token", "mcpe.server.token",
588
15
                FT_BYTES, BASE_NONE,
589
15
                NULL, 0x0,
590
15
                NULL, HFILL }
591
15
        },
592
15
        { &hf_mcpe_batch_length,
593
15
            { "MCPE Compressed batch length", "mcpe.batch.length",
594
15
                FT_UINT32, BASE_DEC,
595
15
                NULL, 0x0,
596
15
                NULL, HFILL }
597
15
        },
598
15
        { &hf_mcpe_batch_body,
599
15
            { "MCPE Compressed batch body", "mcpe.batch.body",
600
15
                FT_NONE, BASE_NONE,
601
15
                NULL, 0x0,
602
15
                NULL, HFILL }
603
15
        },
604
15
        { &hf_mcpe_batch_records,
605
15
            { "MCPE Decompressed batch records", "mcpe.batch.records",
606
15
                FT_NONE, BASE_NONE,
607
15
                NULL, 0x0,
608
15
                NULL, HFILL }
609
15
        },
610
15
        { &hf_mcpe_batch_record_length,
611
15
            { "MCPE Batch record length", "mcpe.batch.record.length",
612
15
                FT_UINT32, BASE_DEC,
613
15
                NULL, 0x0,
614
15
                NULL, HFILL }
615
15
        },
616
15
        { &hf_mcpe_batch_record,
617
15
            { "MCPE Batch record", "mcpe.batch.record",
618
15
                FT_NONE, BASE_NONE,
619
15
                NULL, 0x0,
620
15
                NULL, HFILL }
621
15
        },
622
15
    };
623
624
    /*
625
     * Setup protocol subtree array
626
     */
627
15
    static int *ett[] = {
628
15
        &ett_mcpe,
629
15
        &ett_mcpe_batch,
630
15
        &ett_mcpe_batch_record,
631
15
        &ett_mcpe_login,
632
15
        &ett_mcpe_string,
633
15
    };
634
15
    module_t *mcpe_module;
635
636
    /*
637
     * Set up expert info.
638
     */
639
15
    static ei_register_info ei[] = {
640
15
        { &ei_mcpe_unknown_packet_id,
641
15
          { "mcpe.unknown.id", PI_UNDECODED, PI_WARN,
642
15
            "MCPE unknown packet ID",
643
15
            EXPFILL }
644
15
        },
645
15
        { &ei_mcpe_decompression_failed,
646
15
          { "mcpe.decompression.failed", PI_MALFORMED, PI_ERROR,
647
15
            "MCPE packet decompression failed",
648
15
            EXPFILL }
649
15
        },
650
15
        { &ei_mcpe_encrypted_packet,
651
15
          { "mcpe.encrypted", PI_DECRYPTION, PI_NOTE,
652
15
            "MCPE encrypted packet",
653
15
            EXPFILL }
654
15
        },
655
15
    };
656
15
    expert_module_t *expert_mcpe;
657
658
    /*
659
     * Init data structs.
660
     */
661
15
    mcpe_init_message_names();
662
663
    /*
664
     * Register the protocol with wireshark.
665
     */
666
15
    proto_mcpe = proto_register_protocol ("Minecraft Pocket Edition", "MCPE", "mcpe");
667
668
    /*
669
     * Register expert support.
670
     */
671
15
    expert_mcpe = expert_register_protocol(proto_mcpe);
672
15
    expert_register_field_array(expert_mcpe, ei, array_length(ei));
673
674
    /*
675
     * Register detailed dissection arrays.
676
     */
677
15
    proto_register_field_array(proto_mcpe, hf, array_length(hf));
678
15
    proto_register_subtree_array(ett, array_length(ett));
679
680
    /*
681
     * Register dissectors.
682
     */
683
15
    mcpe_handle =
684
15
        register_dissector("mcpe", dissect_mcpe, proto_mcpe);
685
686
15
    mcpe_packet_dissectors =
687
15
        register_dissector_table("mcpe.packet.id", "MCPE packets",
688
15
                                 proto_mcpe, FT_UINT8, BASE_HEX);
689
690
    /* Register a configuration option for UDP port */
691
15
    mcpe_module =
692
15
        prefs_register_protocol(proto_mcpe, proto_reg_handoff_mcpe);
693
694
15
    prefs_register_uint_preference(mcpe_module, "udp.port",
695
15
            "MCPE Server UDP Port",
696
15
            "Set the UDP port for the MCPE Server",
697
15
            10, &mcpe_udp_port_requested);
698
15
}
699
700
void
701
proto_reg_handoff_mcpe(void)
702
15
{
703
15
    static unsigned last_server_port;
704
15
    static bool init_done = false;
705
706
15
    if (init_done) {
707
0
        raknet_delete_udp_dissector(last_server_port, mcpe_handle);
708
0
    }
709
15
    else {
710
15
        unsigned int i;
711
712
60
        for (i = 0; i < array_length(mcpe_packet_handlers); i++) {
713
45
            dissector_add_uint(
714
45
                "mcpe.packet.id",
715
45
                mcpe_packet_handlers[i].vs.value,
716
45
                create_dissector_handle(
717
45
                    mcpe_packet_handlers[i].dissector_fp, proto_mcpe));
718
45
        }
719
720
15
        heur_dissector_add("raknet", dissect_mcpe_heur,
721
15
                           "MCPE over RakNet", "mcpe_raknet", proto_mcpe, HEURISTIC_ENABLE);
722
15
    }
723
724
15
    last_server_port = mcpe_udp_port_requested;
725
15
    init_done = true;
726
727
    /* MCPE is a protocol that carries RakNet packets over UDP */
728
15
    raknet_add_udp_dissector(mcpe_udp_port_requested, mcpe_handle);
729
15
}
730
731
/*
732
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
733
 *
734
 * Local variables:
735
 * c-basic-offset: 4
736
 * tab-width: 8
737
 * indent-tabs-mode: nil
738
 * End:
739
 *
740
 * vi: set shiftwidth=4 tabstop=8 expandtab:
741
 * :indentSize=4:tabSize=8:noTabs=true:
742
 */