Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-tibia.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-tibia.c
2
 * Routines for Tibia/OTServ login and game protocol dissection
3
 *
4
 * Copyright 2017, Ahmad Fatoum <ahmad[AT]a3f.at>
5
 *
6
 * A dissector for:
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
15
/* Tibia (https://tibia.com) is a Massively Multiplayer Online Role-Playing
16
 * Game (MMORPG) by Cipsoft GmbH.
17
 *
18
 * Three official clients exist: The current Qt-based 11.0+ client,
19
 * the old C++ client used from Tibia 7.0 till 10.99 and the Flash client.
20
 * The latter two are being phased out. They use the same protocol,
21
 * except that the session key for the Flash client is transported alongside
22
 * the character list over HTTPS. It's possible this is done in the same manner
23
 * as in the native client from 10.74 up. We don't support the Flash client.
24
 *
25
 * The dissector supports Tibia versions from 7.0 (2001) till
26
 * 11.00 (2016-10-12). Tibia has an active open source server emulator
27
 * community (OTServ) that still makes use of older versions and surpasses
28
 * the official servers in popularity, therefore compatibility with older
29
 * protocol iterations should be maintained.
30
 *
31
 * Transport is over TCP, with recent versions encrypting player interaction
32
 * with XTEA. Authentication and key exchange is done with a hard-coded
33
 * RSA public key in the client.
34
 *
35
 * Two protocols are dissected: The Tibia login protocol and the Tibia game
36
 * protocol. Traditionally, login servers were stateless and only responsible
37
 * for providing the addresses of the game servers alongside the character
38
 * list upon successful authentication. Then a new authentication request
39
 * (this time with character selection) is sent to the game server.
40
 * That way, a client who knows the game server address can very well skip
41
 * the login server entirely. Starting with 10.61, this is no longer possible,
42
 * as the login server provides a session key that needs to be sent to the
43
 * game server.
44
 *
45
 * Starting with Tibia 7.61, login server requests can't be reliably
46
 * differentiated from game server requests. Therefore we apply some heuristics
47
 * to classify packets.
48
 *
49
 * Starting with Tibia 11.01, a web service takes the role of the login server.
50
 * Starting with Tibia 11.11, the Adler32 checksum was replaced by a 32-bit
51
 * sequence number. The most significant bit indicates whether the packet was
52
 * DEFLATE-compressed. These features are not yet supported.
53
 *
54
 * Packets from and to the game server contain commands. Commands are
55
 * identified by the first octet and are variable in length. The dissector has
56
 * most command names hard-coded. However, a complete implementation of the
57
 * game protocol is unlikely.
58
 *
59
 * The RSA private key usually used by OTServ is hard-coded in. Server
60
 * administrators may add their own private key in PEM or PKCS#12 format over
61
 * an UAT. For servers where the private key is indeed private (like
62
 * for official servers), the symmetric XTEA key (retrievable by memory
63
 * peeking or MitM) may be provided to the dissector via UAT.
64
 *
65
 * Unsurprisingly, no official specification of the protocol exist, following
66
 * resources have been written by the community:
67
 *
68
 * - OTServ: Community effort to replicate a Tibia Server.
69
 * - Outcast: A Tibia client implementation of the game protocol as of 2006.
70
 *            Comes with a PDF spec written by Khaos
71
 * - TibiaAPI: Bot framework, containing a listing of commands as of 2009
72
 * - TFS: OTServ-Fork which is kept up-to-date with most of the official protocol
73
 * - otclient: Open Source implementation of an up-to-date Tibia client
74
 *
75
 * An official slide set by Cipsoft detailing the architecture of Tibia
76
 * from Game Developers Conference Europe 2011 is also available:
77
 * http://www.gdcvault.com/play/1014908/Inside-Tibia-The-Technical-Infrastructure
78
 *
79
 * The login protocol, as implemented here, has been inferred from network
80
 * footage and game client execution traces and was written from scratch.
81
 * The listing of game protocol commands were taken from TibiaAPI and Khaos' spec
82
 * No code of Cipsoft GmbH was used.
83
 *
84
 * Tibia is a registered trademark of Cipsoft GmbH.
85
 */
86
87
#include "config.h"
88
#include <epan/packet.h>
89
#include "packet-tcp.h"
90
#include <wsutil/adler32.h>
91
#include <epan/address.h>
92
#include <epan/prefs.h>
93
#include <epan/uat.h>
94
#include <epan/conversation.h>
95
#include <epan/value_string.h>
96
#include <epan/expert.h>
97
#include <epan/tfs.h>
98
#include <epan/unit_strings.h>
99
100
#include <wsutil/array.h>
101
#include <wsutil/file_util.h>
102
#include <wsutil/wsgcrypt.h>
103
#include <wsutil/report_message.h>
104
#include <wsutil/xtea.h>
105
#include <wsutil/strtoi.h>
106
#include <wsutil/rsa.h>
107
#include <errno.h>
108
#include <epan/ptvcursor.h>
109
110
void proto_register_tibia(void);
111
void proto_reg_handoff_tibia(void);
112
static int dissect_tibia_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
113
114
static dissector_handle_t tibia_handle;
115
116
/* preferences */
117
static bool try_otserv_key          = true,
118
                show_char_name          = true,
119
                show_acc_info           = true,
120
                show_xtea_key           = false,
121
                dissect_game_commands   = false,
122
                reassemble_tcp_segments = true;
123
124
/* User Access Tables */
125
#if HAVE_LIBGNUTLS
126
struct rsakey {
127
    address addr;
128
    uint16_t port;
129
130
    gcry_sexp_t privkey;
131
};
132
GHashTable *rsakeys;
133
134
struct rsakeys_assoc {
135
    char *ipaddr;
136
    char *port;
137
138
    char *keyfile;
139
    char *password;
140
};
141
142
UAT_CSTRING_CB_DEF(rsakeylist_uats,  ipaddr,   struct rsakeys_assoc)
143
UAT_CSTRING_CB_DEF(rsakeylist_uats,  port,     struct rsakeys_assoc)
144
UAT_FILENAME_CB_DEF(rsakeylist_uats, keyfile,  struct rsakeys_assoc)
145
UAT_CSTRING_CB_DEF(rsakeylist_uats,  password, struct rsakeys_assoc)
146
147
static void rsakey_free(void *_rsakey);
148
149
static uat_t *rsakeys_uat;
150
static struct rsakeys_assoc  *rsakeylist_uats;
151
static unsigned nrsakeys;
152
#endif
153
154
0
#define XTEA_KEY_LEN 16
155
156
struct xteakeys_assoc {
157
    uint32_t framenum;
158
159
    char *key;
160
};
161
GHashTable *xteakeys;
162
163
static void *xteakeys_copy_cb(void *, const void *, size_t);
164
static void xteakeys_free_cb(void *);
165
static void xtea_parse_uat(void);
166
static bool xteakeys_uat_fld_key_chk_cb(void *, const char *, unsigned, const void *, const void *, char **);
167
168
UAT_DEC_CB_DEF(xteakeylist_uats, framenum, struct xteakeys_assoc)
169
UAT_CSTRING_CB_DEF(xteakeylist_uats, key, struct xteakeys_assoc)
170
171
static uat_t *xteakeys_uat;
172
static struct xteakeys_assoc *xteakeylist_uats;
173
static unsigned nxteakeys;
174
175
14
#define COND_POISONED     0x00000001
176
14
#define COND_BURNING      0x00000002
177
14
#define COND_ELECTROCUTED 0x00000004
178
14
#define COND_DRUNK        0x00000008
179
14
#define COND_MANASHIELD   0x00000010
180
14
#define COND_PARALYZED    0x00000020
181
14
#define COND_HASTE        0x00000040
182
14
#define COND_BATTLE       0x00000080
183
14
#define COND_DROWNING     0x00000100
184
14
#define COND_FREEZING     0x00000200
185
14
#define COND_DAZZLED      0x00000400
186
14
#define COND_CURSED       0x00000800
187
14
#define COND_BUFF         0x00001000
188
14
#define COND_PZBLOCK      0x00002000
189
14
#define COND_PZ           0x00004000
190
14
#define COND_BLEEDING     0x00008000
191
14
#define COND_HUNGRY       0x00010000
192
193
/* The login server has been traditionally on 7171,
194
 * For OTServ, the game server often listens on the same IP/port,
195
 * but occasionally on 7172. Official Tibia doesn't host login and
196
 * game servers on the same IP address
197
 */
198
199
14
#define TIBIA_DEFAULT_TCP_PORT_RANGE "7171,7172"
200
201
static int proto_tibia;
202
203
static int hf_tibia_len;
204
static int hf_tibia_nonce;
205
static int hf_tibia_adler32;
206
static int hf_tibia_adler32_status;
207
static int hf_tibia_os;
208
static int hf_tibia_proto_version;
209
static int hf_tibia_client_version;
210
static int hf_tibia_file_versions;
211
static int hf_tibia_file_version_spr;
212
static int hf_tibia_file_version_dat;
213
static int hf_tibia_file_version_pic;
214
static int hf_tibia_game_preview_state;
215
static int hf_tibia_content_revision;
216
static int hf_tibia_undecoded_rsa_data;
217
static int hf_tibia_undecoded_xtea_data;
218
static int hf_tibia_unknown;
219
static int hf_tibia_xtea_key;
220
static int hf_tibia_loginflags_gm;
221
static int hf_tibia_acc_name;
222
static int hf_tibia_acc_number;
223
static int hf_tibia_session_key;
224
static int hf_tibia_char_name;
225
static int hf_tibia_acc_pass;
226
static int hf_tibia_char_name_convo;
227
static int hf_tibia_acc_name_convo;
228
static int hf_tibia_acc_pass_convo;
229
static int hf_tibia_session_key_convo;
230
231
static int hf_tibia_client_info;
232
static int hf_tibia_client_locale;
233
static int hf_tibia_client_locale_id;
234
static int hf_tibia_client_locale_name;
235
static int hf_tibia_client_ram;
236
static int hf_tibia_client_cpu;
237
static int hf_tibia_client_cpu_name;
238
static int hf_tibia_client_clock;
239
static int hf_tibia_client_clock2;
240
static int hf_tibia_client_gpu;
241
static int hf_tibia_client_vram;
242
static int hf_tibia_client_resolution;
243
static int hf_tibia_client_resolution_x;
244
static int hf_tibia_client_resolution_y;
245
static int hf_tibia_client_resolution_hz;
246
247
static int hf_tibia_payload_len;
248
static int hf_tibia_loginserv_command;
249
static int hf_tibia_gameserv_command;
250
static int hf_tibia_client_command;
251
252
static int hf_tibia_motd;
253
static int hf_tibia_dlg_error;
254
static int hf_tibia_dlg_info;
255
256
static int hf_tibia_charlist;
257
static int hf_tibia_charlist_length;
258
static int hf_tibia_charlist_entry_name;
259
static int hf_tibia_charlist_entry_world;
260
static int hf_tibia_charlist_entry_ip;
261
static int hf_tibia_charlist_entry_port;
262
263
static int hf_tibia_worldlist;
264
static int hf_tibia_worldlist_length;
265
static int hf_tibia_worldlist_entry_name;
266
static int hf_tibia_worldlist_entry_ip;
267
static int hf_tibia_worldlist_entry_port;
268
static int hf_tibia_worldlist_entry_preview;
269
static int hf_tibia_worldlist_entry_id;
270
static int hf_tibia_pacc_days;
271
272
static int hf_tibia_channel_id;
273
static int hf_tibia_channel_name;
274
275
static int hf_tibia_char_cond;
276
static int hf_tibia_char_cond_poisoned;
277
static int hf_tibia_char_cond_burning;
278
static int hf_tibia_char_cond_electrocuted;
279
static int hf_tibia_char_cond_drunk;
280
static int hf_tibia_char_cond_manashield;
281
static int hf_tibia_char_cond_paralyzed;
282
static int hf_tibia_char_cond_haste;
283
static int hf_tibia_char_cond_battle;
284
static int hf_tibia_char_cond_drowning;
285
static int hf_tibia_char_cond_freezing;
286
static int hf_tibia_char_cond_dazzled;
287
static int hf_tibia_char_cond_cursed;
288
static int hf_tibia_char_cond_buff;
289
static int hf_tibia_char_cond_pzblock;
290
static int hf_tibia_char_cond_pz;
291
static int hf_tibia_char_cond_bleeding;
292
static int hf_tibia_char_cond_hungry;
293
294
static int * const char_conds[] = {
295
    &hf_tibia_char_cond_poisoned,
296
    &hf_tibia_char_cond_burning,
297
    &hf_tibia_char_cond_electrocuted,
298
    &hf_tibia_char_cond_drunk,
299
    &hf_tibia_char_cond_manashield,
300
    &hf_tibia_char_cond_paralyzed,
301
    &hf_tibia_char_cond_haste,
302
    &hf_tibia_char_cond_battle,
303
    &hf_tibia_char_cond_drowning,
304
    &hf_tibia_char_cond_freezing,
305
    &hf_tibia_char_cond_dazzled,
306
    &hf_tibia_char_cond_cursed,
307
    &hf_tibia_char_cond_buff,
308
    &hf_tibia_char_cond_pzblock,
309
    &hf_tibia_char_cond_pz,
310
    &hf_tibia_char_cond_bleeding,
311
    &hf_tibia_char_cond_hungry,
312
    NULL
313
};
314
315
static int hf_tibia_chat_msg;
316
static int hf_tibia_speech_type;
317
318
static int hf_tibia_coords_x;
319
static int hf_tibia_coords_y;
320
static int hf_tibia_coords_z;
321
static int hf_tibia_coords;
322
static int hf_tibia_stackpos;
323
324
#if 0
325
static int hf_tibia_item;
326
#endif
327
static int hf_tibia_container;
328
static int hf_tibia_container_icon;
329
static int hf_tibia_container_slot;
330
static int hf_tibia_container_slots;
331
static int hf_tibia_inventory;
332
static int hf_tibia_vip;
333
static int hf_tibia_vip_online;
334
static int hf_tibia_player;
335
static int hf_tibia_creature;
336
static int hf_tibia_creature_health;
337
static int hf_tibia_window;
338
static int hf_tibia_window_icon;
339
static int hf_tibia_window_textlen;
340
static int hf_tibia_window_text;
341
342
static int hf_tibia_light_level;
343
static int hf_tibia_light_color;
344
static int hf_tibia_magic_effect_id;
345
static int hf_tibia_animated_text_color;
346
static int hf_tibia_animated_text;
347
static int hf_tibia_projectile;
348
static int hf_tibia_squarecolor;
349
static int hf_tibia_textmsg_class;
350
static int hf_tibia_textmsg;
351
static int hf_tibia_walk_dir;
352
353
354
static int ett_tibia;
355
static int ett_command;
356
static int ett_file_versions;
357
static int ett_client_info;
358
static int ett_locale;
359
static int ett_cpu;
360
static int ett_resolution;
361
static int ett_charlist;
362
static int ett_worldlist;
363
static int ett_char;
364
static int ett_world;
365
static int ett_coords;
366
static int ett_char_cond;
367
368
369
static expert_field ei_xtea_len_toobig;
370
static expert_field ei_adler32_checksum_bad;
371
static expert_field ei_rsa_plaintext_no_leading_zero;
372
static expert_field ei_rsa_ciphertext_too_short;
373
static expert_field ei_rsa_decrypt_failed;
374
375
376
struct proto_traits {
377
    uint32_t adler32:1, rsa:1, compression:1, xtea:1, login_webservice:1, acc_name:1, nonce:1,
378
            extra_gpu_info:1, gmbyte:1, hwinfo:1;
379
    uint32_t outfit_addons:1, stamina:1, lvl_on_msg:1;
380
    uint32_t ping:1, client_version:1, game_preview:1, auth_token:1, session_key:1;
381
    uint32_t game_content_revision:1, worldlist_in_charlist:1;
382
    unsigned string_enc;
383
};
384
385
struct tibia_convo {
386
    uint32_t xtea_key[XTEA_KEY_LEN / sizeof (uint32_t)];
387
    uint32_t xtea_framenum;
388
    const uint8_t *acc, *pass, *char_name, *session_key;
389
    struct proto_traits has;
390
391
    uint16_t proto_version;
392
    uint8_t loginserv_is_peer :1;
393
    uint16_t clientport;
394
    uint16_t servport;
395
396
    gcry_sexp_t privkey;
397
};
398
399
static struct proto_traits
400
get_version_traits(uint16_t version)
401
21
{
402
21
    struct proto_traits has;
403
21
    memset(&has, 0, sizeof has);
404
21
    has.gmbyte = true; /* Not sure when the GM byte first appeared */
405
21
    has.string_enc = ENC_ISO_8859_1;
406
407
21
    if (version >= 761) /* 761 was a test client. 770 was the first release */
408
8
        has.xtea = has.rsa = true;
409
21
    if (version >= 780)
410
8
        has.outfit_addons = has.stamina = has.lvl_on_msg = true;
411
21
    if (version >= 830)
412
8
        has.adler32 = has.acc_name = true;
413
21
    if (version >= 841)
414
8
        has.hwinfo = has.nonce = true;
415
21
    if (version >= 953)
416
8
        has.ping = true;
417
21
    if (version >= 980)
418
8
        has.client_version = has.game_preview = true;
419
21
    if (version >= 1010)
420
8
        has.worldlist_in_charlist = true;
421
21
    if (version >= 1061)
422
8
        has.extra_gpu_info = true;
423
21
    if (version >= 1071)
424
8
        has.game_content_revision = true;
425
21
    if (version >= 1072)
426
8
        has.auth_token = true;
427
21
    if (version >= 1074)
428
8
        has.session_key = true;
429
21
    if (version >= 1101)
430
8
        has.login_webservice = true;
431
21
    if (version >= 1111) {
432
8
        has.compression = true; /* with DEFLATE */
433
8
        has.adler32 = false;
434
8
    }
435
#if 0 /* With the legacy client being phased out, maybe Unicode support incoming? */
436
    if (version >= 11xy)
437
        has.string_enc = ENC_UTF_8;
438
#endif
439
440
21
    return has;
441
21
}
442
443
static uint16_t
444
get_version_get_charlist_packet_size(struct proto_traits *has)
445
1
{
446
1
    uint16_t size = 2;
447
1
    if (has->adler32 || has->compression)
448
1
        size += 4;
449
1
    size += 17;
450
1
    if (has->extra_gpu_info)
451
1
        size += 222;
452
1
    if (has->rsa)
453
1
        size += 128;
454
455
1
    return size;
456
1
}
457
static uint16_t
458
get_version_char_login_packet_size(struct proto_traits *has)
459
0
{
460
0
    uint16_t size = 2;
461
0
    if (has->adler32 || has->compression)
462
0
        size += 4;
463
0
    size += 5;
464
0
    if (has->client_version)
465
0
        size += 4;
466
0
    if (has->game_content_revision)
467
0
        size += 2;
468
0
    if (has->game_preview)
469
0
        size += 1;
470
0
    if (has->rsa)
471
0
        size += 128;
472
473
0
    return size;
474
0
}
475
476
477
0
#define XTEA_FROM_UAT 0
478
181
#define XTEA_UNKNOWN  0xFFFFFFFF
479
480
static struct tibia_convo *
481
tibia_get_convo(packet_info *pinfo)
482
177
{
483
177
    conversation_t *epan_conversation = find_or_create_conversation(pinfo);
484
485
177
    struct tibia_convo *convo = (struct tibia_convo*)conversation_get_proto_data(epan_conversation, proto_tibia);
486
487
177
    if (!convo) {
488
4
        address *servaddr;
489
4
        convo = wmem_new0(wmem_file_scope(), struct tibia_convo);
490
491
        /* FIXME there gotta be a cleaner way... */
492
4
        if (pinfo->srcport >= 0xC000) {
493
0
            convo->clientport = pinfo->srcport;
494
495
0
            convo->servport = pinfo->destport;
496
0
            servaddr = &pinfo->dst;
497
4
        } else {
498
4
            convo->clientport = pinfo->destport;
499
500
4
            convo->servport = pinfo->srcport;
501
4
            servaddr = &pinfo->src;
502
4
        }
503
4
        (void)servaddr;
504
#ifdef HAVE_LIBGNUTLS
505
        struct rsakey rsa_key;
506
        rsa_key.port = convo->servport;
507
        rsa_key.addr = *servaddr;
508
        convo->privkey = (gcry_sexp_t)g_hash_table_lookup(rsakeys, &rsa_key);
509
#endif
510
4
        convo->xtea_framenum = XTEA_UNKNOWN;
511
512
4
        conversation_add_proto_data(epan_conversation, proto_tibia, (void *)convo);
513
4
    }
514
515
177
    if (convo->xtea_framenum == XTEA_UNKNOWN) {
516
177
        uint8_t *xtea_key = (uint8_t*)g_hash_table_lookup(xteakeys, GUINT_TO_POINTER(pinfo->num));
517
177
        if (xtea_key) {
518
0
            memcpy(convo->xtea_key, xtea_key, XTEA_KEY_LEN);
519
0
            convo->xtea_framenum = XTEA_FROM_UAT;
520
0
        }
521
177
    }
522
523
177
    return convo;
524
177
}
525
526
static uint32_t
527
ipv4tonl(const char *str)
528
0
{
529
0
        uint32_t ipaddr = 0;
530
0
        for (int octet = 0; octet < 4; octet++) {
531
0
            ws_strtou8(str, &str, &((uint8_t*)&ipaddr)[octet]);
532
0
            str++;
533
0
        }
534
0
        return ipaddr;
535
0
}
536
537
static void
538
register_gameserv_addr(struct tibia_convo *convo, uint32_t ipaddr, uint16_t port)
539
0
{
540
0
    (void)convo; (void)ipaddr; (void)port;
541
#if HAVE_LIBGNUTLS
542
    /* Game servers in the list inherit the same RSA key as the login server */
543
    if (convo->has.rsa) {
544
        struct rsakey *entry = g_new(struct rsakey, 1);
545
        alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr);
546
        entry->port = port;
547
        entry->privkey = NULL;
548
        if (g_hash_table_lookup(rsakeys, entry) == NULL) {
549
            entry->privkey = convo->privkey;
550
            g_hash_table_insert(rsakeys, entry, entry->privkey);
551
        } else {
552
            rsakey_free(entry);
553
        }
554
    }
555
556
    /* TODO Mark all communication with the IP/Port pair above
557
     * as Tibia communication. How?
558
     */
559
#endif
560
0
}
561
562
static gcry_sexp_t otserv_key;
563
static gcry_sexp_t
564
convo_get_privkey(struct tibia_convo *convo)
565
0
{
566
0
    return convo->privkey ? convo->privkey
567
0
         : try_otserv_key ? otserv_key
568
0
         : NULL;
569
0
}
570
571
enum client_cmd {
572
    /* from TibiaAPI */
573
    C_GET_CHARLIST          = 0x01,
574
    C_LOGIN_CHAR            = 0x0A,
575
    C_LOGOUT                = 0x14, /* I think this is a 7.7+ thing */
576
    C_PONG                  = 0x1E,
577
578
    C_AUTO_WALK             = 0x64,
579
    C_GO_NORTH              = 0x65,
580
    C_GO_EAST               = 0x66,
581
    C_GO_SOUTH              = 0x67,
582
    C_GO_WEST               = 0x68,
583
    C_AUTO_WALK_CANCEL      = 0x69,
584
    C_GO_NE                 = 0x6A,
585
    C_GO_SE                 = 0x6B,
586
    C_GO_SW                 = 0x6C,
587
    C_GO_NW                 = 0x6D,
588
    C_TURN_NORTH            = 0x6F,
589
    C_TURN_EAST             = 0x70,
590
    C_TURN_SOUTH            = 0x71,
591
    C_TURN_WEST             = 0x72,
592
    C_MOVE_ITEM             = 0x78,
593
    C_SHOP_BUY              = 0x7A,
594
    C_SHOP_SELL             = 0x7B,
595
    C_SHOP_CLOSE            = 0x7C,
596
    C_ITEM_USE              = 0x82,
597
    C_ITEM_USE_ON           = 0x83,
598
    C_ITEM_USE_BATTLELIST   = 0x84,
599
    C_ITEM_ROTATE           = 0x85,
600
    C_CONTAINER_CLOSE       = 0x87,
601
    C_CONTAINER_OPEN_PARENT = 0x88,
602
    C_LOOK_AT               = 0x8C,
603
    C_PLAYER_SPEECH         = 0x96,
604
    C_CHANNEL_LIST          = 0x97,
605
    C_CHANNEL_OPEN          = 0x98,
606
    C_CHANNEL_CLOSE         = 0x99,
607
    C_PRIVATE_CHANNEL_OPEN  = 0x9A,
608
    C_NPC_CHANNEL_CLOSE     = 0x9E,
609
    C_FIGHT_MODES           = 0xA0,
610
    C_ATTACK                = 0xA1,
611
    C_FOLLOW                = 0xA2,
612
    C_CANCEL_GO             = 0xBE,
613
    C_TILE_UPDATE           = 0xC9,
614
    C_CONTAINER_UPDATE      = 0xCA,
615
    C_SET_OUTFIT            = 0xD3,
616
    C_VIP_ADD               = 0xDC,
617
    C_VIP_REMOVE            = 0xDD
618
 };
619
620
static const value_string from_client_packet_types[] = {
621
    { C_GET_CHARLIST,     "Charlist request" },
622
    { C_LOGIN_CHAR,       "Character login" },
623
624
    { C_LOGOUT,           "Logout" },
625
    { C_PONG,             "Pong" },
626
627
    { C_AUTO_WALK,        "Map walk" },
628
    { C_GO_NORTH,         "Go north"},
629
    { C_GO_EAST,          "Go east"},
630
    { C_GO_SOUTH,         "Go south"},
631
    { C_GO_WEST,          "Go west"},
632
    { C_AUTO_WALK_CANCEL, "Map walk cancel" },
633
    { C_GO_NE,            "Go north-east"},
634
    { C_GO_SE,            "Go south-east"},
635
    { C_GO_SW,            "Go south-west"},
636
    { C_GO_NW,            "Go north-west"},
637
638
    { C_TURN_NORTH,      "Turn north" },
639
    { C_TURN_EAST,       "Turn east" },
640
    { C_TURN_SOUTH,      "Turn south" },
641
    { C_TURN_WEST,       "Turn west" },
642
    { C_MOVE_ITEM,       "Move item" },
643
    { C_SHOP_BUY,        "Buy in shop" },
644
    { C_SHOP_SELL,       "Sell in shop" },
645
    { C_SHOP_CLOSE,      "Close shop" },
646
    { C_ITEM_USE,        "Use item" },
647
    { C_ITEM_USE_ON,     "Use item on" },
648
    { C_ITEM_USE_BATTLELIST,   "Use item on battle list" },
649
    { C_ITEM_ROTATE,           "Rotate item" },
650
651
    { C_CONTAINER_CLOSE,       "Close container" },
652
    { C_CONTAINER_OPEN_PARENT, "Open parent container" },
653
    { C_LOOK_AT,               "Look at" },
654
    { C_PLAYER_SPEECH,         "Speech" },
655
    { C_CHANNEL_LIST,          "List channels" },
656
    { C_CHANNEL_OPEN,          "Open public channel" },
657
    { C_CHANNEL_CLOSE,         "close channel" },
658
    { C_PRIVATE_CHANNEL_OPEN,  "Open private channel" },
659
    { C_NPC_CHANNEL_CLOSE,     "Open NPC channel" },
660
    { C_FIGHT_MODES,           "Set fight modes" },
661
    { C_ATTACK,                "Attack" },
662
    { C_FOLLOW,                "Follow" },
663
    { C_CANCEL_GO,             "Cancel go" },
664
    { C_TILE_UPDATE,           "Update tile" },
665
    { C_CONTAINER_UPDATE,      "Update container" },
666
    { C_SET_OUTFIT,            "Set outfit" },
667
    { C_VIP_ADD,               "Add VIP" },
668
    { C_VIP_REMOVE,            "Remove VIP" },
669
670
    { 0, NULL }
671
};
672
673
static value_string_ext from_client_packet_types_ext = VALUE_STRING_EXT_INIT(from_client_packet_types);
674
675
enum loginserv_cmd {
676
    LOGINSERV_DLG_ERROR    = 0x0A,
677
    LOGINSERV_DLG_ERROR2   = 0x0B,
678
    LOGINSERV_DLG_MOTD     = 0x14,
679
    LOGINSERV_SESSION_KEY  = 0x28,
680
    LOGINSERV_DLG_CHARLIST = 0x64
681
};
682
683
static const value_string from_loginserv_packet_types[] = {
684
    { LOGINSERV_DLG_ERROR,    "Error" },
685
    { LOGINSERV_DLG_ERROR2,   "Error" },
686
    { LOGINSERV_DLG_MOTD,     "MOTD" },
687
    { LOGINSERV_SESSION_KEY,  "Session key" },
688
    { LOGINSERV_DLG_CHARLIST, "Charlist" },
689
690
    { 0, NULL }
691
};
692
693
enum gameserv_cmd {
694
    /* Credit to Khaos (OBJECT Networks). Values and comments extracted from PDF table */
695
    S_MAPINIT =                0x0A, /* Long playerCreatureId Int unknownU16 (Byte reportBugs?) */
696
    S_GMACTIONS =              0x0B, /* Used to be 32 unknown bytes, but with GMs removed it                                      might not be in use anymore */
697
    S_DLG_ERROR =              0x14, /* String errorMessage */
698
    S_DLG_INFO =               0x15,
699
    S_DLG_TOOMANYPLAYERS =     0x16,
700
    S_PING =                   0x1E,
701
    S_NONCE =                  0x1F,
702
    S_PLAYERLOC =              0x64, /* Coord pos */
703
    S_GO_NORTH =               0x65, /* MapDescription (18,1) */
704
    S_GO_EAST =                0x66, /* MapDescription (1,14) */
705
    S_GO_SOUTH =               0x67, /* MapDescription (18,1) */
706
    S_GO_WEST =                0x68, /* MapDescription (1,14) */
707
    S_TILEUPDATE =             0x69, /* Coord pos TileDescription td */
708
    S_ADDITEM =                0x6a, /* Coord pos ThingDescription thing */
709
    S_REPLACEITEM =            0x6b, /* Coord pos Byte stackpos ThingDescription thing */
710
    S_REMOVEITEM =             0x6c, /* Coord pos Byte stackpos */
711
    S_MOVE_THING =             0x6d,
712
    S_CONTAINER =              0x6e, /* Byte index Short containerIcon Byte slotCount ThingDescription item */
713
    S_CONTAINERCLOSE =         0x6f, /* Byte index */
714
    S_ADDITEMCONTAINER =       0x70, /* Byte index ThingDescription itm */
715
    S_TRANSFORMITEMCONTAINER = 0x71, /* Byte index Byte slot */
716
    S_REMOVEITEMCONTAINER =    0x72, /* Byte index Byte slot */
717
    S_INVENTORYEMPTY =         0x78, /* Byte invSlot */
718
    S_INVENTORYITEM =          0x79, /* Byte invSlot ThingDescription itm */
719
    S_TRADEREQ =               0x7d, /* String otherperson Byte slotCount ThingDescription itm */
720
    S_TRADEACK =               0x7e, /* String otherperson Byte slotCount ThingDescription itm */
721
    S_TRADECLOSE =             0x7f,
722
    S_LIGHTLEVEL =             0x82, /* Byte lightlevel Byte lightcolor */
723
    S_MAGIC_EFFECT =           0x83,
724
    S_ANIMATEDTEXT =           0x84, /* Coord pos Byte color String message */
725
    S_DISTANCESHOT =           0x85, /* Coord pos1 Byte stackposition Coord pos2 */
726
    S_CREATURESQUARE =         0x86, /* Long creatureid Byte squarecolor */
727
    S_CREATURE_HEALTH =        0x8C,
728
    S_CREATURELIGHT =          0x8d, /* Long creatureid Byte ? Byte ? */
729
    S_SETOUTFIT =              0x8e, /* Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */
730
    S_CREATURESPEED =          0x8f, /* YIKES! I didn't handle this! */
731
    S_TEXTWINDOW =             0x96, /* Long windowId Byte icon Byte maxlength String message */
732
    S_STATUSMSG =              0xA0, /* Status status */
733
    S_SKILLS =                 0xA1, /* Skills skills */
734
    S_PLAYER_CONDITION =       0xA2,
735
    S_CANCELATTACK =           0xA3,
736
    S_SPEAK =                  0xAA,
737
    S_CHANNELSDIALOG =         0xAB, /* Byte channelCount (Int channelId String channelName) */
738
    S_CHANNEL_OPEN =           0xAC,
739
    S_OPENPRIV =               0xAD, /* String playerName */
740
    S_TEXTMESSAGE =            0xB4, /* Byte msgClass String string */
741
    S_CANCELWALK =             0xB5, /* Byte direction */
742
    S_FLOORUP =                0xBE, /* Advanced topic; read separate text */
743
    S_FLOORDOWN =              0xBF, /* Advanced topic; read separate text */
744
    S_OUTFITLIST =             0xC8, /* Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */
745
    S_VIPADD =                 0xD2, /* long guid string name byte isonline */
746
    S_VIPLOGIN =               0xD3, /* long guid */
747
    S_VIPLOGOUT =              0xD4  /* long guid*/
748
};
749
static const value_string from_gameserv_packet_types[] = {
750
751
    { S_MAPINIT,            "Initialize map" },
752
    { S_GMACTIONS,          "GM actions" },
753
    { S_DLG_ERROR,          "Error" },
754
    { S_DLG_INFO,           "Info" },
755
    { S_DLG_TOOMANYPLAYERS, "Too many players" },
756
    { S_PING,               "Ping" },
757
    { S_NONCE,              "Nonce" },
758
    { S_PLAYERLOC,      "Set player location" },
759
    { S_GO_NORTH,       "Go north" },
760
    { S_GO_EAST,        "Go east" },
761
    { S_GO_SOUTH,       "Go south" },
762
    { S_GO_WEST,        "Go west" },
763
    { S_TILEUPDATE,     "Update tile" },
764
    { S_ADDITEM,        "Add item" },
765
    { S_REPLACEITEM,    "Replace item" },
766
    { S_REMOVEITEM,     "Remove item" },
767
    { S_MOVE_THING,     "Move thing" },
768
    { S_CONTAINER,      "Open container" },
769
    { S_CONTAINERCLOSE, "Close container" },
770
771
    { S_ADDITEMCONTAINER,       "Add item in container" },
772
    { S_TRANSFORMITEMCONTAINER, "Transform item in container" },
773
    { S_REMOVEITEMCONTAINER,    "Remove item in container" },
774
775
    { S_INVENTORYEMPTY,   "Inventory empty" },
776
    { S_INVENTORYITEM,    "Inventory item" },
777
    { S_TRADEREQ,         "Trade request" },
778
    { S_TRADEACK,         "Trade acknowledge" },
779
    { S_TRADECLOSE,       "Trade over" },
780
    { S_LIGHTLEVEL,       "Light level" },
781
    { S_MAGIC_EFFECT,     "Magic effect" },
782
    { S_ANIMATEDTEXT,     "Animated text" },
783
    { S_DISTANCESHOT,     "Distance shot" },
784
    { S_CREATURESQUARE,   "Creature square" },
785
    { S_CREATURE_HEALTH,  "Creature health" },
786
    { S_CREATURELIGHT,    "Creature light" },
787
    { S_SETOUTFIT,        "Set outfit" },
788
    { S_CREATURESPEED,    "Set creature speed" },
789
    { S_TEXTWINDOW,       "Text window" },
790
    { S_STATUSMSG,        "Status message" },
791
    { S_SKILLS,           "Skills" },
792
    { S_PLAYER_CONDITION, "Player condition" },
793
    { S_CANCELATTACK,     "Cancel attack" },
794
    { S_SPEAK,            "Creature speech" },
795
    { S_CHANNELSDIALOG,   "Channels dialog" },
796
    { S_CHANNEL_OPEN,     "Channel open" },
797
    { S_OPENPRIV,         "Private channel open" },
798
    { S_TEXTMESSAGE,      "Text message" },
799
    { S_CANCELWALK,       "Cancel walk" },
800
    { S_FLOORUP,          "Floor +1" },
801
    { S_FLOORDOWN,        "Floor -1" },
802
    { S_OUTFITLIST,       "Outfit list" },
803
    { S_VIPADD,           "Add VIP" },
804
    { S_VIPLOGIN,         "VIP login" },
805
    { S_VIPLOGOUT,        "VIP logout" },
806
807
    { 0, NULL }
808
};
809
810
static value_string_ext from_gameserv_packet_types_ext = VALUE_STRING_EXT_INIT(from_gameserv_packet_types);
811
812
static const unit_name_string mb_unit = {"MB", NULL};
813
814
static int
815
dissect_loginserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, bool first_fragment )
816
0
{
817
0
    ptvcursor_t *ptvc = ptvcursor_new(pinfo->pool, tree, tvb, offset);
818
819
0
    col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
820
0
    len += offset;
821
822
0
    if (ptvcursor_current_offset(ptvc) < len) {
823
0
        for (;;) {
824
0
            int cmd = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
825
0
            ptvcursor_add_with_subtree(ptvc, hf_tibia_loginserv_command, 1, ENC_NA, ett_command);
826
0
            ptvcursor_advance(ptvc, 1);
827
828
0
            switch ((enum loginserv_cmd)cmd) {
829
0
                case LOGINSERV_DLG_ERROR:
830
0
                case LOGINSERV_DLG_ERROR2:
831
0
                    ptvcursor_add(ptvc, hf_tibia_dlg_error, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
832
0
                    break;
833
0
                case LOGINSERV_DLG_MOTD:
834
0
                    ptvcursor_add(ptvc, hf_tibia_motd, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
835
0
                    break;
836
0
                case LOGINSERV_SESSION_KEY:
837
0
                    ptvcursor_add(ptvc, hf_tibia_session_key, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
838
0
                    break;
839
0
                case LOGINSERV_DLG_CHARLIST:
840
0
                    if (convo->has.worldlist_in_charlist) {
841
0
                        uint8_t world_count = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
842
0
                        ptvcursor_add(ptvc, hf_tibia_worldlist_length, 1, ENC_NA);
843
                        /* Empty character list? */
844
0
                        if (world_count) {
845
0
                            ptvcursor_add_with_subtree(ptvc, hf_tibia_worldlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_worldlist);
846
0
                            while (world_count--) {
847
0
                                proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA);
848
0
                                ptvcursor_push_subtree(ptvc, it, ett_world);
849
850
0
                                ptvcursor_add(ptvc, hf_tibia_worldlist_entry_name, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
851
0
                                unsigned ipv4addr_len = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
852
0
                                char *ipv4addr_str = (char*)tvb_get_string_enc(pinfo->pool, tvb, ptvcursor_current_offset(ptvc) + 2, ipv4addr_len, ENC_LITTLE_ENDIAN | convo->has.string_enc);
853
0
                                uint32_t ipv4addr = ipv4tonl(ipv4addr_str);
854
0
                                ptvcursor_add(ptvc, hf_tibia_worldlist_entry_ip, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
855
0
                                uint16_t port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
856
0
                                ptvcursor_add(ptvc, hf_tibia_worldlist_entry_port, 2, ENC_LITTLE_ENDIAN);
857
0
                                ptvcursor_add(ptvc, hf_tibia_worldlist_entry_preview, 1, ENC_NA);
858
859
0
                                ptvcursor_pop_subtree(ptvc);
860
861
0
                                register_gameserv_addr(convo, ipv4addr, port);
862
0
                            }
863
0
                            ptvcursor_pop_subtree(ptvc);
864
0
                        }
865
866
0
                        uint8_t char_count = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
867
0
                        ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA);
868
0
                        if (char_count) {
869
0
                            ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist);
870
0
                            while (char_count--) {
871
0
                                proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA);
872
0
                                ptvcursor_push_subtree(ptvc, it, ett_char);
873
0
                                ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
874
875
876
0
                                ptvcursor_pop_subtree(ptvc);
877
0
                            }
878
0
                            ptvcursor_pop_subtree(ptvc);
879
0
                        }
880
0
                    } else {
881
0
                        uint8_t char_count = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
882
0
                        ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA);
883
0
                        if (char_count) {
884
0
                            ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist);
885
886
0
                            while (char_count--) {
887
0
                                proto_item *it = ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
888
0
                                ptvcursor_push_subtree(ptvc, it, ett_char);
889
890
0
                                ptvcursor_add(ptvc, hf_tibia_charlist_entry_world, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
891
892
0
                                uint32_t ipv4addr = tvb_get_ipv4(tvb, ptvcursor_current_offset(ptvc));
893
0
                                ptvcursor_add(ptvc, hf_tibia_charlist_entry_ip, 4, ENC_BIG_ENDIAN);
894
895
0
                                uint16_t port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc));
896
0
                                ptvcursor_add(ptvc, hf_tibia_charlist_entry_port, 2, ENC_BIG_ENDIAN);
897
898
899
0
                                ptvcursor_pop_subtree(ptvc);
900
901
0
                                register_gameserv_addr(convo, ipv4addr, port);
902
0
                            }
903
904
0
                            ptvcursor_pop_subtree(ptvc);
905
0
                        }
906
907
0
                        ptvcursor_add(ptvc, hf_tibia_pacc_days, 2, ENC_LITTLE_ENDIAN);
908
0
                    }
909
0
                    break;
910
0
                default:
911
0
                    offset = ptvcursor_current_offset(ptvc);
912
0
                    call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
913
0
                    ptvcursor_advance(ptvc, len - offset);
914
0
            }
915
916
0
            ptvcursor_pop_subtree(ptvc);
917
918
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
919
0
                    val_to_str_const(cmd, from_loginserv_packet_types, "Unknown"), cmd);
920
921
0
            if (ptvcursor_current_offset(ptvc) >= len)
922
0
                break;
923
924
0
            col_append_str(pinfo->cinfo, COL_INFO, ",");
925
0
        }
926
0
    }
927
928
0
    offset = ptvcursor_current_offset(ptvc);
929
0
    ptvcursor_free(ptvc);
930
931
0
    return offset;
932
0
}
933
934
static void
935
dissect_coord(ptvcursor_t *ptvc, bool with_stackpos)
936
0
{
937
0
    tvbuff_t *tvb;
938
0
    proto_tree *tree;
939
0
    int offset;
940
941
0
    uint32_t x, y, z, stackpos;
942
0
    proto_item *coords_tuple = ptvcursor_add_with_subtree(ptvc, hf_tibia_coords, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_coords);
943
0
    {
944
0
        tvb = ptvcursor_tvbuff(ptvc);
945
0
        tree = ptvcursor_tree(ptvc);
946
0
        offset = ptvcursor_current_offset(ptvc);
947
948
0
        proto_tree_add_item_ret_uint(tree, hf_tibia_coords_x, tvb, offset, 2, ENC_LITTLE_ENDIAN, &x);
949
0
        offset += 2;
950
0
        proto_tree_add_item_ret_uint(tree, hf_tibia_coords_y, tvb, offset, 2, ENC_LITTLE_ENDIAN, &y);
951
0
        offset += 2;
952
0
        proto_tree_add_item_ret_uint(tree, hf_tibia_coords_z, tvb, offset, 1, ENC_NA, &z);
953
0
        offset += 1;
954
955
0
        ptvcursor_advance(ptvc, 5);
956
0
    }
957
0
    if (with_stackpos) {
958
0
        proto_tree_add_item_ret_uint(tree, hf_tibia_stackpos, tvb, offset, 1, ENC_NA, &stackpos);
959
0
        proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)[%u]", x, y, z, stackpos);
960
0
        ptvcursor_advance(ptvc, 1);
961
0
    } else {
962
0
        proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)", x, y, z);
963
0
    }
964
965
0
    ptvcursor_pop_subtree(ptvc);
966
0
}
967
968
969
static int
970
dissect_gameserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, bool first_fragment)
971
0
{
972
0
    ptvcursor_t *ptvc = ptvcursor_new(pinfo->pool, tree, tvb, offset);
973
974
0
    col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
975
0
    len += offset;
976
977
0
    if (ptvcursor_current_offset(ptvc) < len) {
978
0
        for (;;) {
979
0
            int cmd = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
980
0
            ptvcursor_add_with_subtree(ptvc, hf_tibia_gameserv_command, 1, ENC_NA, ett_command);
981
0
            ptvcursor_advance(ptvc, 1);
982
983
0
            switch ((enum gameserv_cmd)cmd) {
984
0
                case S_DLG_INFO:
985
0
                case S_DLG_ERROR:
986
0
                case S_DLG_TOOMANYPLAYERS:
987
0
                    ptvcursor_add(ptvc, cmd == S_DLG_ERROR ? hf_tibia_dlg_error : hf_tibia_dlg_info, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
988
0
                    break;
989
0
                case S_GMACTIONS: /* 0x0B, Used to be 32 unknown bytes, but with GMs removed it                                     might not be in use anymore */
990
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, 32, ENC_NA);
991
0
                    break;
992
0
                case S_PLAYERLOC: /* 0x64,Coord pos */
993
0
                    dissect_coord(ptvc, false);
994
0
                    break;
995
0
                case S_TILEUPDATE: /* 0x69,Coord pos TileDescription td */
996
0
                    dissect_coord(ptvc, false);
997
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
998
0
                    break;
999
0
                case S_ADDITEM: /* 0x6a,Coord pos ThingDescription thing */
1000
0
                    dissect_coord(ptvc, false);
1001
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1002
0
                    break;
1003
0
                case S_REPLACEITEM: /* 0x6b,Coord pos Byte stackpos ThingDescription thing */
1004
0
                    dissect_coord(ptvc, true);
1005
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1006
0
                    break;
1007
0
                case S_REMOVEITEM: /* 0x6c,Coord pos Byte stackpos */
1008
0
                    dissect_coord(ptvc, true);
1009
0
                    break;
1010
0
                case S_MOVE_THING: /* 0x6d, */
1011
0
                    dissect_coord(ptvc, true);
1012
0
                    dissect_coord(ptvc, false);
1013
0
                    break;
1014
0
                case S_CONTAINER: /* 0x6e,Byte index Short containerIcon Byte slotCount ThingDescription item */
1015
0
                    ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1016
0
                    ptvcursor_add(ptvc, hf_tibia_container_icon, 2, ENC_LITTLE_ENDIAN);
1017
0
                    ptvcursor_add(ptvc, hf_tibia_container_slots, 2, ENC_LITTLE_ENDIAN);
1018
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1019
0
                    break;
1020
0
                case S_CONTAINERCLOSE: /* 0x6f,Byte index */
1021
0
                    ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1022
0
                    break;
1023
0
                case S_ADDITEMCONTAINER: /* 0x70,Byte index ThingDescription itm */
1024
0
                    ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1025
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1026
0
                    break;
1027
0
                case S_TRANSFORMITEMCONTAINER:/* 0x71,Byte index Byte slot */
1028
0
                    ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1029
0
                    ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA);
1030
0
                    break;
1031
0
                case S_REMOVEITEMCONTAINER: /* 0x72,Byte index Byte slot */
1032
0
                    ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA);
1033
0
                    ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA);
1034
0
                    break;
1035
0
                case S_INVENTORYEMPTY: /* 0x78,Byte invSlot */
1036
0
                    ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1037
0
                    break;
1038
0
                case S_INVENTORYITEM: /* 0x79,Byte invSlot ThingDescription itm */
1039
0
                    ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1040
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1041
0
                    break;
1042
0
                case S_TRADEREQ: /* 0x7d,String otherperson Byte slotCount ThingDescription itm */
1043
0
                    ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1044
0
                    ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1045
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1046
0
                    break;
1047
0
                case S_TRADEACK: /* 0x7e,String otherperson Byte slotCount ThingDescription itm */
1048
0
                    ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1049
0
                    ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA);
1050
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1051
0
                    break;
1052
1053
0
                case S_TRADECLOSE: /* 0x7f, */
1054
0
                    break;
1055
0
                case S_LIGHTLEVEL: /* 0x82,Byte lightlevel Byte lightcolor */
1056
0
                    ptvcursor_add(ptvc, hf_tibia_light_level, 1, ENC_NA);
1057
0
                    ptvcursor_add(ptvc, hf_tibia_light_color, 1, ENC_NA);
1058
0
                    break;
1059
0
                case S_MAGIC_EFFECT: /* 0x83, */
1060
0
                    dissect_coord(ptvc, false);
1061
0
                    ptvcursor_add(ptvc, hf_tibia_magic_effect_id, 1, ENC_NA);
1062
0
                    break;
1063
0
                case S_ANIMATEDTEXT: /* 0x84,Coord pos Byte color String message */
1064
0
                    dissect_coord(ptvc, false);
1065
0
                    ptvcursor_add(ptvc, hf_tibia_animated_text_color, 1, ENC_NA);
1066
0
                    ptvcursor_add(ptvc, hf_tibia_animated_text, 2, ENC_LITTLE_ENDIAN);
1067
0
                    break;
1068
0
                case S_DISTANCESHOT: /* 0x85,Coord pos1 Byte stackposition Coord pos2 */
1069
0
                    dissect_coord(ptvc, false);
1070
0
                    ptvcursor_add(ptvc, hf_tibia_projectile, 4, ENC_LITTLE_ENDIAN);
1071
0
                    dissect_coord(ptvc, false);
1072
0
                    break;
1073
0
                case S_CREATURESQUARE: /* 0x86,Long creatureid Byte squarecolor */
1074
0
                    ptvcursor_add(ptvc, hf_tibia_creature, 4, ENC_LITTLE_ENDIAN);
1075
0
                    ptvcursor_add(ptvc, hf_tibia_squarecolor, 1, ENC_NA);
1076
0
                    break;
1077
0
                case S_CREATURE_HEALTH: /* 0x8C, */
1078
0
                    ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1079
0
                    ptvcursor_add(ptvc, hf_tibia_creature_health, 1, ENC_NA);
1080
0
                    break;
1081
0
                case S_CREATURELIGHT: /* 0x8d,Long creatureid Byte ? Byte ? */
1082
0
                    ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1083
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, 2, ENC_NA);
1084
0
                    break;
1085
0
                case S_SETOUTFIT: /* 0x8e,Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */
1086
0
                    ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN);
1087
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA);
1088
0
                    break;
1089
0
                case S_TEXTWINDOW: /* 0x96,Long windowId Byte icon Byte maxlength String message */
1090
0
                    ptvcursor_add(ptvc, hf_tibia_window, 4, ENC_LITTLE_ENDIAN);
1091
0
                    ptvcursor_add(ptvc, hf_tibia_window_icon, 1, ENC_NA);
1092
0
                    ptvcursor_add(ptvc, hf_tibia_window_textlen, 1, ENC_NA);
1093
0
                    ptvcursor_add(ptvc, hf_tibia_window_text, 1, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1094
0
                    break;
1095
0
                case S_PLAYER_CONDITION: /* 0xA2, */
1096
0
                    proto_tree_add_bitmask(ptvcursor_tree(ptvc), ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), hf_tibia_char_cond, ett_char_cond, char_conds, ENC_LITTLE_ENDIAN);
1097
0
                    ptvcursor_advance(ptvc, 4);
1098
0
                    break;
1099
0
                case S_CANCELATTACK: /* 0xA3, */
1100
0
                    break;
1101
0
                case S_CHANNEL_OPEN:
1102
0
                    ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN);
1103
0
                    ptvcursor_add(ptvc, hf_tibia_channel_name, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc);
1104
0
                    ptvcursor_add(ptvc, hf_tibia_unknown, 4, ENC_NA);
1105
0
                    break;
1106
0
                case S_OPENPRIV: /* 0xAD,String playerName */
1107
0
                    ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1108
0
                    break;
1109
0
                case S_TEXTMESSAGE: /* 0xB4,Byte msgClass String string */
1110
0
                    ptvcursor_add(ptvc, hf_tibia_textmsg_class, 1, ENC_NA);
1111
0
                    ptvcursor_add(ptvc, hf_tibia_textmsg, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1112
0
                    break;
1113
0
                case S_CANCELWALK: /* 0xB5,Byte direction */
1114
0
                    ptvcursor_add(ptvc, hf_tibia_walk_dir, 1, ENC_NA);
1115
0
                    break;
1116
0
                case S_VIPADD: /* 0xd2,long guid string name byte isonline */
1117
0
                    ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1118
0
                    ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc);
1119
0
                    ptvcursor_add(ptvc, hf_tibia_vip_online, 1, ENC_NA);
1120
0
                    break;
1121
0
                case S_VIPLOGIN: /* 0xd3,long guid */
1122
0
                    ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1123
0
                    break;
1124
0
                case S_VIPLOGOUT: /* 0xd4long guid*/
1125
0
                    ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN);
1126
0
                    break;
1127
0
                case S_PING:
1128
0
                    break;
1129
0
                case S_NONCE: /* 0x1F, */
1130
0
                    ptvcursor_add(ptvc, hf_tibia_nonce, 5, ENC_NA);
1131
0
                    break;
1132
1133
0
                case S_MAPINIT: /* 0x0A, Long playerCreatureId Int unknownU16 (Byte reportBugs?) */
1134
0
                case S_OUTFITLIST: /* 0xC8,Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */
1135
                    /* TODO This changed with mounts and outfit */
1136
0
                case S_FLOORUP: /* 0xBE,Advanced topic; read separate text */
1137
0
                case S_FLOORDOWN: /* 0xBF,Advanced topic; read separate text */
1138
0
                case S_SPEAK: /* 0xAA, */
1139
0
                case S_CHANNELSDIALOG: /* 0xAB,Byte channelCount (Int channelId String channelName) */
1140
0
                case S_STATUSMSG: /* 0xA0,Status status */
1141
0
                case S_SKILLS: /* 0xA1,Skills skills */
1142
0
                case S_CREATURESPEED: /* 0x8f,YIKES! I didn't handle this! */
1143
0
                case S_GO_NORTH: /* 0x65,MapDescription (18,1) */
1144
0
                case S_GO_EAST: /* 0x66,MapDescription (1,14) */
1145
0
                case S_GO_SOUTH: /* 0x67,MapDescription (18,1) */
1146
0
                case S_GO_WEST: /* 0x68,MapDescription (1,14) */
1147
0
                default:
1148
0
                    offset = ptvcursor_current_offset(ptvc);
1149
0
                    call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
1150
0
                    ptvcursor_advance(ptvc, len - offset);
1151
0
            }
1152
1153
1154
0
            ptvcursor_pop_subtree(ptvc);
1155
1156
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
1157
0
                    val_to_str_const(cmd, from_gameserv_packet_types, "Unknown"), cmd);
1158
1159
0
            if (ptvcursor_current_offset(ptvc) >= len)
1160
0
                break;
1161
1162
0
            col_append_str(pinfo->cinfo, COL_INFO, ",");
1163
0
        }
1164
0
    }
1165
1166
0
    offset = ptvcursor_current_offset(ptvc);
1167
0
    ptvcursor_free(ptvc);
1168
1169
0
    return offset;
1170
0
}
1171
1172
static int
1173
dissect_client_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, bool first_fragment)
1174
0
{
1175
0
    ptvcursor_t *ptvc = ptvcursor_new(pinfo->pool, tree, tvb, offset);
1176
1177
0
    col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ",");
1178
0
    len += offset;
1179
1180
0
    if (ptvcursor_current_offset(ptvc) < len) {
1181
0
        for (;;) {
1182
0
            int cmd = tvb_get_uint8(tvb, ptvcursor_current_offset(ptvc));
1183
0
            ptvcursor_add_with_subtree(ptvc, hf_tibia_client_command, 1, ENC_NA, ett_command);
1184
0
            ptvcursor_advance(ptvc, 1);
1185
1186
0
            switch ((enum client_cmd)cmd) {
1187
0
                case C_PLAYER_SPEECH: {
1188
0
                    uint8_t type = tvb_get_uint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc));
1189
1190
0
                    ptvcursor_add(ptvc, hf_tibia_speech_type, 1, ENC_NA);
1191
0
                    if (type == 0x7)
1192
0
                        ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN);
1193
0
                    ptvcursor_add(ptvc, hf_tibia_chat_msg, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc);
1194
0
                    }
1195
0
                    break;
1196
0
                case C_PONG:
1197
0
                    break;
1198
0
                default:
1199
0
                    offset = ptvcursor_current_offset(ptvc);
1200
0
                    call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc));
1201
0
                    ptvcursor_advance(ptvc, len - offset);
1202
0
            }
1203
1204
0
            ptvcursor_pop_subtree(ptvc);
1205
1206
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)",
1207
0
                    val_to_str_const(cmd, from_client_packet_types, "Unknown"), cmd);
1208
1209
0
            if (ptvcursor_current_offset(ptvc) >= len)
1210
0
                break;
1211
1212
0
            col_append_str(pinfo->cinfo, COL_INFO, ",");
1213
0
        }
1214
0
    }
1215
1216
0
    offset = ptvcursor_current_offset(ptvc);
1217
0
    ptvcursor_free(ptvc);
1218
1219
0
    return offset;
1220
0
}
1221
1222
static int
1223
dissect_game_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, bool is_xtea_encrypted, bool first_fragment)
1224
21
{
1225
21
    proto_item *ti = NULL;
1226
21
    int len = tvb_captured_length_remaining(tvb, offset);
1227
1228
21
    if (show_acc_info) {
1229
21
        if (convo->has.session_key) {
1230
0
            if (convo->session_key) {
1231
0
                ti = proto_tree_add_string(tree, hf_tibia_session_key_convo, tvb, offset, 0, (const char*)convo->session_key);
1232
0
                proto_item_set_generated(ti);
1233
0
            }
1234
21
        } else {
1235
21
            if (convo->acc) {
1236
0
                ti = proto_tree_add_string(tree, hf_tibia_acc_name_convo, tvb, offset, 0, (const char*)convo->acc);
1237
0
                proto_item_set_generated(ti);
1238
0
            }
1239
1240
21
            if (convo->pass) {
1241
0
                ti = proto_tree_add_string(tree, hf_tibia_acc_pass_convo, tvb, offset, 0, (const char*)convo->pass);
1242
0
                proto_item_set_generated(ti);
1243
0
            }
1244
21
        }
1245
21
    }
1246
1247
21
    if (show_char_name && convo->char_name) {
1248
0
        ti = proto_tree_add_string(tree, hf_tibia_char_name_convo, tvb, offset, 0, (const char*)convo->char_name);
1249
0
        proto_item_set_generated(ti);
1250
0
    }
1251
1252
21
    if (is_xtea_encrypted) {
1253
0
        if (pinfo->num > convo->xtea_framenum) {
1254
0
            if (show_xtea_key && convo->has.xtea) {
1255
0
                ti = proto_tree_add_bytes_with_length(tree, hf_tibia_xtea_key, tvb, 0, 0, (uint8_t*)convo->xtea_key, XTEA_KEY_LEN);
1256
0
                proto_item_set_generated(ti);
1257
0
            }
1258
1259
0
            int end = offset + len;
1260
1261
0
            if (len % 8 != 0)
1262
0
                return -1;
1263
1264
0
            uint8_t *decrypted_buffer = (uint8_t*)wmem_alloc(pinfo->pool, len);
1265
1266
0
            for (uint8_t *dstblock = decrypted_buffer; offset < end; offset += 8) {
1267
0
                decrypt_xtea_le_ecb(dstblock, tvb_get_ptr(tvb, offset, 8), convo->xtea_key, 32);
1268
0
                dstblock += 8;
1269
0
            }
1270
1271
0
            tvb = tvb_new_child_real_data(tvb, decrypted_buffer, len, len);
1272
0
            add_new_data_source(pinfo, tvb, "Decrypted Game Data");
1273
1274
0
            offset = 0;
1275
0
        } else {
1276
0
            proto_tree_add_item(tree, hf_tibia_undecoded_xtea_data, tvb, offset, len, ENC_NA);
1277
0
            return offset;
1278
0
        }
1279
0
    }
1280
21
    if (convo->has.xtea) {
1281
0
        len = tvb_get_letohs(tvb, offset);
1282
0
        ti = proto_tree_add_item(tree, hf_tibia_payload_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1283
0
        offset += 2;
1284
0
        if (len > tvb_captured_length_remaining(tvb, offset)) {
1285
0
            expert_add_info(pinfo, ti, &ei_xtea_len_toobig);
1286
0
            return offset;
1287
0
        }
1288
0
    }
1289
1290
1291
21
    if (pinfo->srcport == convo->servport && convo->loginserv_is_peer)
1292
0
        return dissect_loginserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1293
1294
21
    if (!dissect_game_commands) {
1295
21
        call_data_dissector(tvb_new_subset_length(tvb, offset, len), pinfo, tree);
1296
21
        return offset + len;
1297
21
    }
1298
1299
0
    if (pinfo->srcport == convo->servport)
1300
0
        return dissect_gameserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1301
0
    else
1302
0
        return dissect_client_packet(convo, tvb, offset, len, pinfo, tree, first_fragment);
1303
0
}
1304
1305
static int
1306
dissect_tibia(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *fragment_num)
1307
178
{
1308
178
    tvbuff_t *tvb_decrypted = tvb;
1309
178
    bool is_xtea_encrypted = false;
1310
178
    enum { TIBIA_GAMESERV, TIBIA_LOGINSERV } serv = TIBIA_GAMESERV;
1311
178
    uint16_t plen = tvb_get_letohs(tvb, 0) + 2;
1312
1313
    /* if announced length != real length it's not a tibia packet */
1314
178
    if (tvb_reported_length_remaining(tvb, 0) != plen)
1315
1
        return 0;
1316
1317
177
    struct tibia_convo *convo = tibia_get_convo(pinfo);
1318
1319
177
    int offset = 2;
1320
177
    int a32len = tvb_reported_length_remaining(tvb, offset + 4);
1321
177
    uint32_t packet_cksum = tvb_get_letohl(tvb, offset);
1322
177
    uint32_t computed_cksum = GUINT32_TO_LE(adler32_bytes(tvb_get_ptr(tvb, offset + 4, a32len), a32len));
1323
177
    convo->has.adler32 = packet_cksum == computed_cksum;
1324
177
    if (convo->has.adler32)
1325
0
        offset += 4;
1326
1327
    /* FIXME Tibia >=11.11 has a sequence number instead, this is yet unhandled */
1328
1329
    /* Is it a nonce? */
1330
177
    if (tvb_get_letohs(tvb, offset) == plen - offset - 2
1331
177
            && tvb_get_uint8(tvb, offset+2) == S_NONCE) {
1332
        /* Don't do anything. We'll handle it as unencrypted game command later */
1333
177
    } else {
1334
177
        uint8_t cmd;
1335
177
        uint16_t version;
1336
177
        struct proto_traits version_has;
1337
177
        cmd = tvb_get_uint8(tvb, offset);
1338
177
        offset += 1;
1339
177
        offset += 2; /* OS */
1340
177
        version = tvb_get_letohs(tvb, offset);
1341
177
        version_has = get_version_traits(version);
1342
1343
177
        switch(cmd) {
1344
1
            case C_GET_CHARLIST:
1345
1
                if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54)
1346
1
                        || get_version_get_charlist_packet_size(&version_has) == plen) {
1347
0
                    serv = TIBIA_LOGINSERV;
1348
0
                    convo->loginserv_is_peer = true;
1349
0
                }
1350
1
                break;
1351
0
            case C_LOGIN_CHAR:
1352
                /* The outcast client I tried, zero-pads the 760 login request.
1353
                 * I don't think the Cipsoft client ever did this.
1354
                 */
1355
0
                if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54)
1356
0
                        ||  get_version_char_login_packet_size(&version_has) == plen)
1357
0
                    serv = TIBIA_LOGINSERV;
1358
0
                break;
1359
20
            default:
1360
20
                is_xtea_encrypted = convo->has.xtea;
1361
177
        }
1362
177
    }
1363
1364
1365
21
    offset = 0; /* With the version extracted, let's build the tree */
1366
1367
21
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Tibia");
1368
21
    if (GPOINTER_TO_UINT(fragment_num) == 1) {
1369
        /* We don't want to repeat ourselves in the info column if there are fragments */
1370
21
        if (serv == TIBIA_LOGINSERV)
1371
0
            col_set_str(pinfo->cinfo, COL_INFO, "Login");
1372
21
        else if (pinfo->srcport == convo->servport)
1373
21
            col_set_str(pinfo->cinfo, COL_INFO, "Server");
1374
0
        else
1375
0
            col_set_str(pinfo->cinfo, COL_INFO, "Client");
1376
1377
21
    }
1378
1379
21
    proto_item *ti = proto_tree_add_item(tree, proto_tibia, tvb, 0, -1, ENC_NA);
1380
21
    proto_tree *tibia_tree = proto_item_add_subtree(ti, ett_tibia);
1381
1382
21
    proto_tree_add_item(tibia_tree, hf_tibia_len, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1383
21
    offset += 2;
1384
21
    if (convo->has.adler32) {
1385
0
        proto_tree_add_checksum(tibia_tree, tvb, offset, hf_tibia_adler32, hf_tibia_adler32_status, &ei_adler32_checksum_bad, pinfo, computed_cksum, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY);
1386
0
        offset += 4;
1387
21
    } else if (convo->has.compression) {
1388
0
        offset += 4;
1389
0
    }
1390
1391
21
    if (serv == TIBIA_GAMESERV)
1392
21
        return dissect_game_packet(convo, tvb, offset, pinfo, tibia_tree, is_xtea_encrypted, GPOINTER_TO_UINT(fragment_num) == 1);
1393
1394
0
    proto_tree_add_item(tibia_tree, hf_tibia_client_command, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1395
0
    offset += 1;
1396
0
    proto_tree_add_item(tibia_tree, hf_tibia_os, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1397
0
    offset += 2;
1398
1399
0
    convo->proto_version = tvb_get_letohs(tvb, offset);
1400
0
    convo->has = get_version_traits(convo->proto_version);
1401
0
    proto_tree_add_item(tibia_tree, hf_tibia_proto_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1402
0
    offset += 2;
1403
0
    if (convo->has.client_version) {
1404
0
        proto_tree_add_item(tibia_tree, hf_tibia_client_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1405
0
        offset += 4;
1406
0
    }
1407
0
    if (convo->loginserv_is_peer) {
1408
0
        proto_tree *vertree;
1409
        /* The first 4 bytes of the client's tibia.pic, tibia.dat and tibia.spr files */
1410
0
        proto_item *subti = proto_tree_add_item(tibia_tree, hf_tibia_file_versions, tvb, offset, 12, ENC_NA);
1411
0
        vertree = proto_item_add_subtree(subti, ett_file_versions);
1412
0
        proto_tree_add_item(vertree, hf_tibia_file_version_spr, tvb, offset, 4, ENC_BIG_ENDIAN);
1413
0
        offset += 4;
1414
0
        proto_tree_add_item(vertree, hf_tibia_file_version_dat, tvb, offset, 4, ENC_BIG_ENDIAN);
1415
0
        offset += 4;
1416
0
        proto_tree_add_item(vertree, hf_tibia_file_version_pic, tvb, offset, 4, ENC_BIG_ENDIAN);
1417
0
        offset += 4;
1418
0
    } else if (convo->has.game_content_revision) {
1419
0
        proto_tree_add_item(tibia_tree, hf_tibia_content_revision, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1420
0
        offset += 2;
1421
0
    }
1422
1423
0
    if (convo->has.game_preview) {
1424
0
        proto_tree_add_item(tibia_tree, hf_tibia_game_preview_state, tvb, offset, 1, ENC_NA);
1425
0
        offset += 1;
1426
0
    }
1427
1428
0
    int rsa1_end = 0; /* End of first RSA block */
1429
0
    if (convo->has.rsa) {
1430
0
        gcry_sexp_t privkey;
1431
0
        if (!(privkey = convo_get_privkey(convo))) {
1432
0
            proto_tree_add_item(tibia_tree, hf_tibia_undecoded_rsa_data, tvb, offset, plen - offset, ENC_NA);
1433
0
            return offset;
1434
0
        }
1435
1436
0
        unsigned ciphertext_len = tvb_captured_length_remaining(tvb, offset);
1437
0
        if (ciphertext_len < 128) {
1438
0
            expert_add_info(pinfo, ti, &ei_rsa_ciphertext_too_short);
1439
0
            return offset;
1440
0
        }
1441
0
        rsa1_end = offset + 128;
1442
0
        uint8_t *payload = (uint8_t*)tvb_memdup(pinfo->pool, tvb, offset, 128);
1443
1444
0
        char *err = NULL;
1445
0
        size_t payload_len;
1446
0
        if (!(payload_len = rsa_decrypt_inplace(128, payload, privkey, false, &err))) {
1447
0
            expert_add_info_format(pinfo, ti, &ei_rsa_decrypt_failed, "Decrypting RSA block failed: %s", err);
1448
0
            g_free(err);
1449
0
            return offset;
1450
0
        }
1451
0
        size_t leading_zeroes = 128 - payload_len;
1452
0
        memmove(payload + leading_zeroes, payload, payload_len);
1453
0
        memset(payload, 0x00, leading_zeroes);
1454
1455
0
        tvb_decrypted = tvb_new_child_real_data(tvb, payload, 128, 128);
1456
0
        add_new_data_source(pinfo, tvb_decrypted, "Decrypted Login Data");
1457
1458
0
        if (tvb_get_uint8(tvb_decrypted, 0) != 0x00) {
1459
0
            expert_add_info(pinfo, ti, &ei_rsa_plaintext_no_leading_zero);
1460
0
            return offset;
1461
0
        }
1462
1463
0
        offset = 1;
1464
1465
0
        tvb_memcpy(tvb_decrypted, convo->xtea_key, 1, XTEA_KEY_LEN);
1466
0
        proto_tree_add_item(tibia_tree, hf_tibia_xtea_key, tvb_decrypted, 1, XTEA_KEY_LEN, ENC_NA);
1467
0
        offset += XTEA_KEY_LEN;
1468
0
        convo->xtea_framenum = pinfo->num;
1469
0
    }
1470
1471
0
    if (!convo->loginserv_is_peer && convo->has.gmbyte) {
1472
0
        proto_tree_add_item(tibia_tree, hf_tibia_loginflags_gm, tvb_decrypted, offset, 1, ENC_NA);
1473
0
        offset += 1;
1474
0
    }
1475
1476
0
    int len;
1477
0
    if (convo->has.session_key && !convo->loginserv_is_peer) {
1478
        /* OTServs I tested against use "$acc\n$pacc" as session key */
1479
0
        if (convo->session_key) {
1480
0
            proto_tree_add_item_ret_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1481
0
        } else {
1482
0
            proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->session_key, &len);
1483
0
        }
1484
0
        offset += len;
1485
0
    } else if (convo->has.acc_name) {
1486
0
        if (convo->acc) {
1487
0
            proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1488
0
        } else {
1489
0
            proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->acc, &len);
1490
0
        }
1491
0
        offset += len;
1492
0
    } else /* account number */ {
1493
0
        char *accnum = wmem_strdup_printf(pinfo->pool, "%" PRIu32, tvb_get_letohl(tvb_decrypted, offset));
1494
0
        proto_tree_add_string(tibia_tree, hf_tibia_acc_number, tvb_decrypted, offset, 4, accnum);
1495
0
        if (!convo->acc)
1496
0
            convo->acc = (uint8_t*)wmem_strdup(wmem_file_scope(), accnum);
1497
0
        offset += 4;
1498
0
    }
1499
1500
0
    if (!convo->loginserv_is_peer) {
1501
0
        if (convo->char_name) {
1502
0
            proto_tree_add_item_ret_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1503
0
        } else {
1504
0
            proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->char_name, &len);
1505
0
        }
1506
0
        offset += len;
1507
0
    }
1508
1509
0
    if (!convo->has.session_key || convo->loginserv_is_peer) {
1510
0
        if (convo->pass) {
1511
0
            proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len);
1512
0
        } else {
1513
0
            proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->pass, &len);
1514
0
        }
1515
0
        offset += len;
1516
0
    }
1517
1518
0
    if (convo->loginserv_is_peer && convo->has.hwinfo) {
1519
0
        proto_item *item;
1520
0
        proto_tree *infotree, *subtree;
1521
1522
0
        item = proto_tree_add_item(tibia_tree, hf_tibia_client_info, tvb_decrypted, offset, 47, ENC_NA);
1523
0
        infotree = proto_item_add_subtree(item, ett_client_info);
1524
1525
        /* Subtree { */
1526
0
        unsigned locale_id;
1527
0
        const uint8_t *locale_name;
1528
1529
0
        item = proto_tree_add_item(infotree, hf_tibia_client_locale, tvb_decrypted, offset, 4, ENC_NA);
1530
0
        subtree = proto_item_add_subtree(item, ett_locale);
1531
1532
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_locale_id, tvb_decrypted, offset, 1, ENC_NA, &locale_id);
1533
0
        offset += 1;
1534
1535
0
        proto_tree_add_item_ret_string(subtree, hf_tibia_client_locale_name, tvb_decrypted, offset, 3, convo->has.string_enc|ENC_NA, pinfo->pool, &locale_name);
1536
0
        offset += 3;
1537
0
        proto_item_set_text(item, "Locale: %s (0x%X)", locale_name, locale_id);
1538
        /* } */
1539
1540
0
        proto_tree_add_item(infotree, hf_tibia_client_ram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN);
1541
0
        offset += 2;
1542
1543
0
        proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 6, ENC_NA);
1544
0
        offset += 6;
1545
1546
        /* Subtree { */
1547
0
        unsigned clock1, clock2;
1548
0
        const uint8_t *cpu;
1549
1550
0
        item = proto_tree_add_item(infotree, hf_tibia_client_cpu, tvb_decrypted, offset, 15, ENC_NA);
1551
0
        subtree = proto_item_add_subtree(item, ett_cpu);
1552
1553
0
        proto_tree_add_item_ret_string(subtree, hf_tibia_client_cpu_name, tvb_decrypted, offset, 9, convo->has.string_enc|ENC_NA, pinfo->pool, &cpu);
1554
0
        offset += 9;
1555
1556
0
        proto_tree_add_item(subtree, hf_tibia_unknown, tvb_decrypted, offset, 2, ENC_NA);
1557
0
        offset += 2;
1558
1559
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock1);
1560
0
        offset += 2;
1561
1562
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock2, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock2);
1563
0
        offset += 2;
1564
1565
0
        proto_item_set_text(item, "CPU: %s (%uMhz/%uMhz)", cpu, clock2, clock1);
1566
        /* } */
1567
1568
1569
0
        proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 4, ENC_NA);
1570
0
        offset += 4;
1571
1572
0
        proto_tree_add_item(infotree, hf_tibia_client_gpu, tvb_decrypted, offset, 9, ENC_NA | convo->has.string_enc);
1573
0
        offset += 9;
1574
1575
0
        proto_tree_add_item(infotree, hf_tibia_client_vram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN);
1576
0
        offset += 2;
1577
1578
        /* Subtree { */
1579
0
        unsigned x, y, hz;
1580
1581
0
        item = proto_tree_add_item(infotree, hf_tibia_client_resolution, tvb_decrypted, offset, 5, ENC_NA);
1582
0
        subtree = proto_item_add_subtree(item, ett_resolution);
1583
1584
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_x, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &x);
1585
0
        offset += 2;
1586
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_y, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &y);
1587
0
        offset += 2;
1588
0
        proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_hz, tvb_decrypted, offset, 1, ENC_LITTLE_ENDIAN, &hz);
1589
0
        offset += 1;
1590
1591
0
        proto_item_set_text(item, "Resolution: %ux%u @ %uHz", x, y, hz);
1592
        /* } */
1593
1594
0
    } else if (!convo->loginserv_is_peer && convo->has.nonce) {
1595
0
        proto_tree_add_item(tibia_tree, hf_tibia_nonce, tvb_decrypted, offset, 5, ENC_NA);
1596
0
        offset += 5;
1597
0
    }
1598
1599
0
    if (convo->has.rsa) {
1600
        /* Undecoded hardware info maybe */
1601
0
        call_data_dissector(tvb_new_subset_length(tvb_decrypted, offset, 128 - offset), pinfo, tibia_tree);
1602
0
    }
1603
1604
0
    if (rsa1_end)
1605
0
        offset = rsa1_end;
1606
1607
0
    if (offset != plen) {
1608
        /* TODO Extended GPU info and authentication token (RSA-encrypted again) */
1609
0
        call_data_dissector(tvb_new_subset_length(tvb, offset, plen - offset), pinfo, tibia_tree);
1610
0
    }
1611
0
    return plen;
1612
0
}
1613
1614
static const value_string operating_systems[] = {
1615
    { 2, "Windows" },
1616
    { 0, NULL }
1617
};
1618
1619
static const value_string speech_types[] = {
1620
    { 0x1, "Say" },
1621
    { 0x2, "Whisper" },
1622
    { 0x3, "Yell" },
1623
    { 0x7, "Public Channel" },
1624
    { 0, NULL }
1625
};
1626
1627
#if defined(HAVE_LIBGNUTLS)
1628
static unsigned
1629
rsakey_hash(const void *_rsakey)
1630
{
1631
    const struct rsakey *rsakey = (const struct rsakey *)_rsakey;
1632
    return add_address_to_hash(rsakey->port, &rsakey->addr);
1633
}
1634
1635
static gboolean
1636
rsakey_equal(const void *_a, const void *_b)
1637
{
1638
    const struct rsakey *a = (const struct rsakey *)_a,
1639
                        *b = (const struct rsakey *)_b;
1640
    return a->port == b->port && addresses_equal(&a->addr, &b->addr);
1641
}
1642
static void
1643
rsakey_free(void *_rsakey)
1644
{
1645
    struct rsakey *rsakey = (struct rsakey *)_rsakey;
1646
1647
    /* gcry_sexp_release(rsakey->privkey); */ /* private key may be shared. */
1648
    free_address_wmem(NULL, &rsakey->addr);
1649
    g_free(rsakey);
1650
}
1651
1652
static void
1653
rsa_parse_uat(void)
1654
{
1655
    g_hash_table_remove_all(rsakeys);
1656
1657
    for (unsigned i = 0; i < nrsakeys; i++) {
1658
        struct rsakeys_assoc *uats = &rsakeylist_uats[i];
1659
1660
        /* try to load keys file first */
1661
        FILE *fp = ws_fopen(uats->keyfile, "rb");
1662
        if (!fp) {
1663
            report_open_failure(uats->keyfile, errno, false);
1664
            return;
1665
        }
1666
1667
        gnutls_x509_privkey_t priv_key;
1668
        char *err = NULL;
1669
        if (*uats->password) {
1670
            priv_key = rsa_load_pkcs12(fp, uats->password, &err);
1671
            if (err) {
1672
                report_failure("%s\n", err);
1673
                g_free(err);
1674
            }
1675
        } else {
1676
            priv_key = rsa_load_pem_key(fp, &err);
1677
            if (err) {
1678
                report_failure("%s\n", err);
1679
                g_free(err);
1680
            }
1681
        }
1682
        fclose(fp);
1683
1684
        if (!priv_key) {
1685
            report_failure("Can't load private key from %s\n", uats->keyfile);
1686
            return;
1687
        }
1688
1689
        struct rsakey *entry;
1690
        uint32_t ipaddr;
1691
        gcry_sexp_t private_key = rsa_privkey_to_sexp(priv_key, &err);
1692
        if (!private_key) {
1693
            g_free(err);
1694
            report_failure("Can't extract private key parameters for %s", uats->keyfile);
1695
            goto end;
1696
        }
1697
1698
        entry = g_new(struct rsakey, 1);
1699
        ws_strtou16(uats->port, NULL, &entry->port);
1700
        ipaddr = ipv4tonl(uats->ipaddr);
1701
        alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr);
1702
        entry->privkey = private_key;
1703
1704
1705
        g_hash_table_insert(rsakeys, entry, entry->privkey);
1706
1707
end:
1708
        gnutls_x509_privkey_deinit(priv_key);
1709
    }
1710
}
1711
1712
static void
1713
rsakeys_free_cb(void *r)
1714
{
1715
    struct rsakeys_assoc *h = (struct rsakeys_assoc *)r;
1716
1717
    g_free(h->ipaddr);
1718
    g_free(h->port);
1719
    g_free(h->keyfile);
1720
    g_free(h->password);
1721
}
1722
1723
static void*
1724
rsakeys_copy_cb(void *dst_, const void *src_, size_t len _U_)
1725
{
1726
    const struct rsakeys_assoc *src = (const struct rsakeys_assoc *)src_;
1727
    struct rsakeys_assoc       *dst = (struct rsakeys_assoc *)dst_;
1728
1729
    dst->ipaddr    = g_strdup(src->ipaddr);
1730
    dst->port      = g_strdup(src->port);
1731
    dst->keyfile   = g_strdup(src->keyfile);
1732
    dst->password  = g_strdup(src->password);
1733
1734
    return dst;
1735
}
1736
1737
static bool
1738
rsakeys_uat_fld_ip_chk_cb(void* r _U_, const char* ipaddr, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
1739
{
1740
    /* There are no Tibia IPv6 servers, although Tibia 11.0+'s Protocol in theory supports it */
1741
    if (ipaddr && g_hostname_is_ip_address(ipaddr) && strchr(ipaddr, '.')) {
1742
        *err = NULL;
1743
        return true;
1744
    }
1745
1746
    *err = ws_strdup_printf("No IPv4 address given.");
1747
    return false;
1748
}
1749
1750
static bool
1751
rsakeys_uat_fld_port_chk_cb(void *_record _U_, const char *str, unsigned len _U_, const void *chk_data _U_, const void *fld_data _U_, char **err)
1752
{
1753
    uint16_t val;
1754
    if (!ws_strtou16(str, NULL, &val)) {
1755
        *err = g_strdup("Invalid argument. Expected a decimal between [0-65535]");
1756
        return false;
1757
    }
1758
    *err = NULL;
1759
    return true;
1760
}
1761
1762
static bool
1763
rsakeys_uat_fld_fileopen_chk_cb(void* r _U_, const char* p, unsigned len _U_, const void* u1 _U_, const void* u2 _U_, char** err)
1764
{
1765
    if (p && *p) {
1766
        ws_statb64 st;
1767
        if (ws_stat64(p, &st) != 0) {
1768
            *err = ws_strdup_printf("File '%s' does not exist or access is denied.", p);
1769
            return false;
1770
        }
1771
    } else {
1772
        *err = g_strdup("No filename given.");
1773
        return false;
1774
    }
1775
1776
    *err = NULL;
1777
    return true;
1778
}
1779
1780
static bool
1781
rsakeys_uat_fld_password_chk_cb(void *r, const char *p, unsigned len _U_, const void *u1 _U_, const void *u2 _U_, char **err)
1782
{
1783
    if (p && *p) {
1784
        struct rsakeys_assoc *f = (struct rsakeys_assoc *)r;
1785
        FILE *fp = ws_fopen(f->keyfile, "rb");
1786
        if (fp) {
1787
            char *msg = NULL;
1788
            gnutls_x509_privkey_t priv_key = rsa_load_pkcs12(fp, p, &msg);
1789
            if (!priv_key) {
1790
                fclose(fp);
1791
                *err = ws_strdup_printf("Could not load PKCS#12 key file: %s", msg);
1792
                g_free(msg);
1793
                return false;
1794
            }
1795
            g_free(msg);
1796
            gnutls_x509_privkey_deinit(priv_key);
1797
            fclose(fp);
1798
        } else {
1799
            *err = ws_strdup_printf("Leave this field blank if the keyfile is not PKCS#12.");
1800
            return false;
1801
        }
1802
    }
1803
1804
    *err = NULL;
1805
    return true;
1806
}
1807
#endif
1808
1809
static void
1810
xtea_parse_uat(void)
1811
14
{
1812
14
    g_hash_table_remove_all(xteakeys);
1813
1814
14
    for (unsigned i = 0; i < nxteakeys; i++) {
1815
0
        unsigned key_idx = 0;
1816
0
        uint8_t *key = (uint8_t*)g_malloc(XTEA_KEY_LEN);
1817
1818
0
        for (const char *str = xteakeylist_uats[i].key; str[0] && str[1] && key_idx < XTEA_KEY_LEN; str++) {
1819
0
            if (g_ascii_ispunct(*str))
1820
0
                continue;
1821
1822
0
            key[key_idx++] = (g_ascii_xdigit_value(str[0]) << 4)
1823
0
                           +  g_ascii_xdigit_value(str[1]);
1824
0
            str++;
1825
0
        }
1826
1827
0
        g_hash_table_insert(xteakeys, GUINT_TO_POINTER(xteakeylist_uats[i].framenum), key);
1828
0
    }
1829
14
}
1830
1831
static void
1832
xteakeys_free_cb(void *r)
1833
0
{
1834
0
    struct xteakeys_assoc *h = (struct xteakeys_assoc *)r;
1835
1836
0
    g_free(h->key);
1837
0
}
1838
1839
static void*
1840
xteakeys_copy_cb(void *dst_, const void *src_, size_t len _U_)
1841
0
{
1842
0
    const struct xteakeys_assoc *src = (const struct xteakeys_assoc *)src_;
1843
0
    struct xteakeys_assoc       *dst = (struct xteakeys_assoc *)dst_;
1844
1845
0
    dst->framenum = src->framenum;
1846
0
    dst->key      = g_strdup(src->key);
1847
1848
0
    return dst;
1849
0
}
1850
1851
static bool
1852
xteakeys_uat_fld_key_chk_cb(void *r _U_, const char *key, unsigned len, const void *u1 _U_, const void *u2 _U_, char **err)
1853
0
{
1854
0
    if (len >= XTEA_KEY_LEN*2) {
1855
0
        size_t i = 0;
1856
1857
0
        do {
1858
0
            if (g_ascii_ispunct(*key))
1859
0
                continue;
1860
0
            if (!g_ascii_isxdigit(*key))
1861
0
                break;
1862
0
            i++;
1863
0
        } while (*++key);
1864
1865
0
        if (*key == '\0' && i == 2*XTEA_KEY_LEN) {
1866
0
            *err = NULL;
1867
0
            return true;
1868
0
        }
1869
0
    }
1870
1871
0
    *err = ws_strdup_printf("XTEA keys are 32 character long hex strings.");
1872
0
    return false;
1873
0
}
1874
1875
1876
void
1877
proto_register_tibia(void)
1878
14
{
1879
14
    static hf_register_info hf[] = {
1880
14
        { &hf_tibia_len,
1881
14
            { "Packet length", "tibia.len",
1882
14
                FT_UINT16, BASE_DEC,
1883
14
                NULL, 0x0,
1884
14
                NULL, HFILL }
1885
14
        },
1886
14
        { &hf_tibia_adler32,
1887
14
            { "Adler32 checksum", "tibia.checksum",
1888
14
                FT_UINT32, BASE_HEX,
1889
14
                NULL, 0x0,
1890
14
                NULL, HFILL }
1891
14
        },
1892
14
        { &hf_tibia_adler32_status,
1893
14
            { "Checksum status", "tibia.checksum.status",
1894
14
                FT_UINT8, BASE_NONE,
1895
14
                VALS(proto_checksum_vals), 0x0,
1896
14
                NULL, HFILL }
1897
14
        },
1898
14
        { &hf_tibia_nonce,
1899
14
            { "Game server nonce", "tibia.nonce",
1900
14
                FT_BYTES, BASE_NONE,
1901
14
                NULL, 0x0,
1902
14
                NULL, HFILL }
1903
14
        },
1904
14
        { &hf_tibia_os,
1905
14
            { "Operating system", "tibia.os",
1906
14
                FT_UINT16, BASE_HEX,
1907
14
                VALS(operating_systems), 0x0,
1908
14
                NULL, HFILL }
1909
14
        },
1910
14
        { &hf_tibia_proto_version,
1911
14
            { "Protocol version", "tibia.version",
1912
14
                FT_UINT16, BASE_DEC,
1913
14
                NULL, 0x0,
1914
14
                NULL, HFILL }
1915
14
        },
1916
14
        { &hf_tibia_client_version,
1917
14
            { "Client version", "tibia.client_version",
1918
14
                FT_UINT32, BASE_DEC,
1919
14
                NULL, 0x0,
1920
14
                NULL, HFILL }
1921
14
        },
1922
14
        { &hf_tibia_file_versions,
1923
14
            { "File versions", "tibia.version.files",
1924
14
                FT_NONE, BASE_NONE, NULL, 0x0,
1925
14
                NULL, HFILL }
1926
14
        },
1927
14
        { &hf_tibia_file_version_spr,
1928
14
            { "Tibia.spr version", "tibia.version.spr",
1929
14
                FT_UINT32, BASE_HEX,
1930
14
                NULL, 0x0,
1931
14
                NULL, HFILL }
1932
14
        },
1933
14
        { &hf_tibia_file_version_dat,
1934
14
            { "Tibia.dat version", "tibia.version.dat",
1935
14
                FT_UINT32, BASE_HEX,
1936
14
                NULL, 0x0,
1937
14
                NULL, HFILL }
1938
14
        },
1939
14
        { &hf_tibia_file_version_pic,
1940
14
            { "Tibia.pic version", "tibia.version.pic",
1941
14
                FT_UINT32, BASE_HEX,
1942
14
                NULL, 0x0,
1943
14
                NULL, HFILL }
1944
14
        },
1945
14
        { &hf_tibia_content_revision,
1946
14
            { "Content revision", "tibia.version.content",
1947
14
                FT_UINT16, BASE_HEX,
1948
14
                NULL, 0x0,
1949
14
                NULL, HFILL }
1950
14
        },
1951
14
        { &hf_tibia_undecoded_rsa_data,
1952
14
            { "RSA-encrypted login data", "tibia.rsa_data",
1953
14
                FT_BYTES, BASE_NONE,
1954
14
                NULL, 0x0,
1955
14
                NULL, HFILL }
1956
14
        },
1957
14
        { &hf_tibia_undecoded_xtea_data,
1958
14
            { "XTEA-encrypted game data", "tibia.xtea_data",
1959
14
                FT_BYTES, BASE_NONE,
1960
14
                NULL, 0x0,
1961
14
                NULL, HFILL }
1962
14
        },
1963
14
        { &hf_tibia_unknown,
1964
14
            { "Unknown Data", "tibia.unknown",
1965
14
                FT_BYTES, BASE_NONE,
1966
14
                NULL, 0x0,
1967
14
                NULL, HFILL }
1968
14
        },
1969
14
        { &hf_tibia_xtea_key,
1970
14
            { "Symmetric key (XTEA)", "tibia.xtea",
1971
14
                FT_BYTES, BASE_NONE,
1972
14
                NULL, 0x0,
1973
14
                NULL, HFILL }
1974
14
        },
1975
14
        { &hf_tibia_loginflags_gm,
1976
14
            { "Gamemaster", "tibia.login.flags.gm",
1977
14
                FT_BOOLEAN, 8,
1978
14
                NULL, 0x1,
1979
14
                NULL, HFILL }
1980
14
        },
1981
14
        { &hf_tibia_game_preview_state,
1982
14
            { "Game Preview State", "tibia.login.flags.preview",
1983
14
                FT_BOOLEAN, 8,
1984
14
                NULL, 0x1,
1985
14
                NULL, HFILL }
1986
14
        },
1987
14
        { &hf_tibia_char_cond,
1988
14
          {"Character Condition", "tibia.cond",
1989
14
                FT_UINT32, BASE_HEX,
1990
14
                NULL, 0,
1991
14
                NULL, HFILL}
1992
14
        },
1993
14
        { &hf_tibia_char_cond_poisoned,
1994
14
            { "Poisoned", "tibia.cond.poisoned",
1995
14
                FT_BOOLEAN, 32,
1996
14
                TFS(&tfs_yes_no), COND_POISONED,
1997
14
                NULL, HFILL }
1998
14
        },
1999
14
        { &hf_tibia_char_cond_burning,
2000
14
            { "Burning", "tibia.cond.burning",
2001
14
                FT_BOOLEAN, 32,
2002
14
                TFS(&tfs_yes_no), COND_BURNING,
2003
14
                NULL, HFILL }
2004
14
        },
2005
14
        { &hf_tibia_char_cond_electrocuted,
2006
14
            { "Electrocuted", "tibia.cond.electrocuted",
2007
14
                FT_BOOLEAN, 32,
2008
14
                TFS(&tfs_yes_no), COND_ELECTROCUTED,
2009
14
                NULL, HFILL }
2010
14
        },
2011
14
        { &hf_tibia_char_cond_drunk,
2012
14
            { "Drunk", "tibia.cond.drunk",
2013
14
                FT_BOOLEAN, 32,
2014
14
                TFS(&tfs_yes_no), COND_DRUNK,
2015
14
                NULL, HFILL }
2016
14
        },
2017
14
        { &hf_tibia_char_cond_manashield, /* Utamo Vita */
2018
14
            { "Mana Shield", "tibia.cond.manashield",
2019
14
                FT_BOOLEAN, 32,
2020
14
                TFS(&tfs_yes_no), COND_MANASHIELD,
2021
14
                NULL, HFILL }
2022
14
        },
2023
14
        { &hf_tibia_char_cond_paralyzed,
2024
14
            { "Paralyzed", "tibia.cond.paralyzed",
2025
14
                FT_BOOLEAN, 32,
2026
14
                TFS(&tfs_yes_no), COND_PARALYZED,
2027
14
                NULL, HFILL }
2028
14
        },
2029
14
        { &hf_tibia_char_cond_haste,
2030
14
            { "Haste", "tibia.cond.haste",
2031
14
                FT_BOOLEAN, 32,
2032
14
                TFS(&tfs_yes_no), COND_HASTE,
2033
14
                NULL, HFILL }
2034
14
        },
2035
14
        { &hf_tibia_char_cond_battle,
2036
14
            { "Battle lock", "tibia.cond.battle",
2037
14
                FT_BOOLEAN, 32,
2038
14
                TFS(&tfs_yes_no), COND_BATTLE,
2039
14
                NULL, HFILL }
2040
14
        },
2041
14
        { &hf_tibia_char_cond_drowning,
2042
14
            { "Drowning", "tibia.cond.drowning",
2043
14
                FT_BOOLEAN, 32,
2044
14
                TFS(&tfs_yes_no), COND_DROWNING,
2045
14
                NULL, HFILL }
2046
14
        },
2047
14
        { &hf_tibia_char_cond_freezing,
2048
14
            { "Freezing", "tibia.cond.freezing",
2049
14
                FT_BOOLEAN, 32,
2050
14
                TFS(&tfs_yes_no), COND_FREEZING,
2051
14
                NULL, HFILL }
2052
14
        },
2053
14
        { &hf_tibia_char_cond_dazzled,
2054
14
            { "Dazzled", "tibia.cond.dazzled",
2055
14
                FT_BOOLEAN, 32,
2056
14
                TFS(&tfs_yes_no), COND_DAZZLED,
2057
14
                NULL, HFILL }
2058
14
        },
2059
14
        { &hf_tibia_char_cond_cursed,
2060
14
            { "Cursed", "tibia.cond.cursed",
2061
14
                FT_BOOLEAN, 32,
2062
14
                TFS(&tfs_yes_no), COND_CURSED,
2063
14
                NULL, HFILL }
2064
14
        },
2065
14
        { &hf_tibia_char_cond_buff, /* e.g. after casting Utura */
2066
14
            { "Buff", "tibia.cond.buff",
2067
14
                FT_BOOLEAN, 32,
2068
14
                TFS(&tfs_yes_no), COND_BUFF,
2069
14
                NULL, HFILL }
2070
14
        },
2071
14
        { &hf_tibia_char_cond_pzblock, /* Blocked from entering PZ */
2072
14
            { "Protection Zone Block", "tibia.cond.pzblock",
2073
14
                FT_BOOLEAN, 32,
2074
14
                TFS(&tfs_yes_no), COND_PZBLOCK,
2075
14
                NULL, HFILL }
2076
14
        },
2077
14
        { &hf_tibia_char_cond_pz,
2078
14
            { "Protection Zone", "tibia.cond.pz",
2079
14
                FT_BOOLEAN, 32,
2080
14
                TFS(&tfs_yes_no), COND_PZ,
2081
14
                NULL, HFILL }
2082
14
        },
2083
14
        { &hf_tibia_char_cond_bleeding,
2084
14
            { "Bleeding", "tibia.cond.bleeding",
2085
14
                FT_BOOLEAN, 32,
2086
14
                TFS(&tfs_yes_no), COND_BLEEDING,
2087
14
                NULL, HFILL }
2088
14
        },
2089
14
        { &hf_tibia_char_cond_hungry,
2090
14
            { "Hungry", "tibia.cond.hungry",
2091
14
                FT_BOOLEAN, 32,
2092
14
                TFS(&tfs_yes_no), COND_HUNGRY,
2093
14
                NULL, HFILL }
2094
14
        },
2095
14
        { &hf_tibia_acc_name,
2096
14
            { "Account", "tibia.acc",
2097
14
                FT_UINT_STRING, BASE_NONE,
2098
14
                NULL, 0x0,
2099
14
                NULL, HFILL }
2100
14
        },
2101
14
        { &hf_tibia_acc_number,
2102
14
            { "Account", "tibia.acc",
2103
14
                FT_STRING, BASE_NONE,
2104
14
                NULL, 0x0,
2105
14
                NULL, HFILL }
2106
14
        },
2107
14
        { &hf_tibia_session_key,
2108
14
            { "Session key", "tibia.session_key",
2109
14
                FT_UINT_STRING, BASE_NONE,
2110
14
                NULL, 0x0,
2111
14
                NULL, HFILL }
2112
14
        },
2113
14
        { &hf_tibia_char_name,
2114
14
            { "Character name", "tibia.char",
2115
14
                FT_UINT_STRING, BASE_NONE,
2116
14
                NULL, 0x0,
2117
14
                NULL, HFILL }
2118
14
        },
2119
14
        { &hf_tibia_acc_pass,
2120
14
            { "Password", "tibia.pass",
2121
14
                FT_UINT_STRING, BASE_NONE,
2122
14
                NULL, 0x0,
2123
14
                NULL, HFILL }
2124
14
        },
2125
14
        { &hf_tibia_char_name_convo,
2126
14
            { "Character name", "tibia.char",
2127
14
                FT_STRING, BASE_NONE,
2128
14
                NULL, 0x0,
2129
14
                NULL, HFILL }
2130
14
        },
2131
14
        { &hf_tibia_acc_name_convo,
2132
14
            { "Account", "tibia.acc",
2133
14
                FT_STRING, BASE_NONE,
2134
14
                NULL, 0x0,
2135
14
                NULL, HFILL }
2136
14
        },
2137
14
        { &hf_tibia_acc_pass_convo,
2138
14
            { "Password", "tibia.pass",
2139
14
                FT_STRING, BASE_NONE,
2140
14
                NULL, 0x0,
2141
14
                NULL, HFILL }
2142
14
        },
2143
14
        { &hf_tibia_session_key_convo,
2144
14
            { "Session key", "tibia.session_key",
2145
14
                FT_STRING, BASE_NONE,
2146
14
                NULL, 0x0,
2147
14
                NULL, HFILL }
2148
14
        },
2149
14
        { &hf_tibia_client_info,
2150
14
            { "Client information", "tibia.client.info",
2151
14
                FT_NONE, BASE_NONE,
2152
14
                NULL, 0x0,
2153
14
                NULL, HFILL }
2154
14
        },
2155
14
        { &hf_tibia_client_locale,
2156
14
            { "Locale", "tibia.client.locale",
2157
14
                FT_NONE, BASE_NONE,
2158
14
                NULL, 0x0,
2159
14
                NULL, HFILL }
2160
14
        },
2161
14
        { &hf_tibia_client_locale_id,
2162
14
            { "Locale ID", "tibia.client.locale.id",
2163
14
                FT_UINT8, BASE_DEC,
2164
14
                NULL, 0x0,
2165
14
                NULL, HFILL }
2166
14
        },
2167
14
        { &hf_tibia_client_locale_name,
2168
14
            { "Locale", "tibia.client.locale.name",
2169
14
                FT_STRING, BASE_NONE,
2170
14
                NULL, 0x0,
2171
14
                NULL, HFILL }
2172
14
        },
2173
14
        { &hf_tibia_client_ram,
2174
14
            { "Total RAM", "tibia.client.ram",
2175
14
                FT_UINT16, BASE_DEC,
2176
14
                NULL, 0x0,
2177
14
                NULL, HFILL }
2178
14
        },
2179
14
        { &hf_tibia_client_cpu,
2180
14
            { "CPU", "tibia.client.cpu",
2181
14
                FT_NONE, BASE_NONE,
2182
14
                NULL, 0x0,
2183
14
                NULL, HFILL }
2184
14
        },
2185
14
        { &hf_tibia_client_cpu_name,
2186
14
            { "CPU", "tibia.client.cpu.name",
2187
14
                FT_STRINGZ, BASE_NONE,
2188
14
                NULL, 0x0,
2189
14
                NULL, HFILL }
2190
14
        },
2191
14
        { &hf_tibia_client_clock,
2192
14
            { "CPU clock", "tibia.client.cpu.clock",
2193
14
                FT_UINT16, BASE_DEC,
2194
14
                NULL, 0x0,
2195
14
                NULL, HFILL }
2196
14
        },
2197
14
        { &hf_tibia_client_clock2,
2198
14
            { "CPU clock2", "tibia.client.cpu.clock2",
2199
14
                FT_UINT16, BASE_DEC,
2200
14
                NULL, 0x0,
2201
14
                NULL, HFILL }
2202
14
        },
2203
14
        { &hf_tibia_client_gpu,
2204
14
            { "GPU", "tibia.client.gpu",
2205
14
                FT_STRINGZ, BASE_NONE,
2206
14
                NULL, 0x0,
2207
14
                NULL, HFILL }
2208
14
        },
2209
14
        { &hf_tibia_client_vram,
2210
14
            { "Video RAM", "tibia.client.vram",
2211
14
                FT_UINT16, BASE_DEC|BASE_UNIT_STRING,
2212
14
                UNS(&mb_unit), 0x0,
2213
14
                NULL, HFILL }
2214
14
        },
2215
14
        { &hf_tibia_client_resolution,
2216
14
            { "Screen resolution", "tibia.client.resolution",
2217
14
                FT_NONE, BASE_NONE,
2218
14
                NULL, 0x0,
2219
14
                NULL, HFILL }
2220
14
        },
2221
14
        { &hf_tibia_client_resolution_x,
2222
14
            { "Horizontal resolution", "tibia.client.resolution.x",
2223
14
                FT_UINT16, BASE_DEC,
2224
14
                NULL, 0x0,
2225
14
                NULL, HFILL }
2226
14
        },
2227
14
        { &hf_tibia_client_resolution_y,
2228
14
            { "Vertical resolution", "tibia.client.resolution.y",
2229
14
                FT_UINT16, BASE_DEC,
2230
14
                NULL, 0x0,
2231
14
                NULL, HFILL }
2232
14
        },
2233
14
        { &hf_tibia_client_resolution_hz,
2234
14
            { "Refresh rate", "tibia.client.resolution.hz",
2235
14
                FT_UINT8, BASE_DEC,
2236
14
                NULL, 0x0,
2237
14
                NULL, HFILL }
2238
14
        },
2239
14
        { &hf_tibia_payload_len,
2240
14
            { "Payload length", "tibia.payload.len",
2241
14
                FT_UINT16, BASE_DEC,
2242
14
                NULL, 0x0,
2243
14
                NULL, HFILL }
2244
14
        },
2245
14
        { &hf_tibia_loginserv_command,
2246
14
            { "Command", "tibia.cmd",
2247
14
                FT_UINT8, BASE_HEX,
2248
14
                VALS(from_loginserv_packet_types), 0x0,
2249
14
                NULL, HFILL }
2250
14
        },
2251
14
        { &hf_tibia_gameserv_command,
2252
14
            { "Command", "tibia.cmd",
2253
14
                FT_UINT8, BASE_HEX|BASE_EXT_STRING,
2254
14
                &from_gameserv_packet_types_ext, 0x0,
2255
14
                NULL, HFILL }
2256
14
        },
2257
14
        { &hf_tibia_client_command,
2258
14
            { "Command", "tibia.cmd",
2259
14
                FT_UINT8, BASE_HEX|BASE_EXT_STRING,
2260
14
                &from_client_packet_types_ext, 0x0,
2261
14
                NULL, HFILL }
2262
14
        },
2263
14
        { &hf_tibia_motd,
2264
14
            { "Message of the day", "tibia.motd",
2265
14
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2266
14
                NULL, HFILL }
2267
14
        },
2268
14
        { &hf_tibia_dlg_error,
2269
14
            { "Error message", "tibia.login.err",
2270
14
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2271
14
                NULL, HFILL }
2272
14
        },
2273
14
        { &hf_tibia_dlg_info,
2274
14
            { "Info message", "tibia.login.info",
2275
14
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2276
14
                NULL, HFILL }
2277
14
        },
2278
14
        { &hf_tibia_charlist,
2279
14
            { "Character list", "tibia.charlist",
2280
14
                FT_NONE, BASE_NONE, NULL, 0x0,
2281
14
                NULL, HFILL }
2282
14
        },
2283
14
        { &hf_tibia_charlist_length,
2284
14
            { "Character count", "tibia.charlist.count",
2285
14
                FT_UINT8, BASE_DEC,
2286
14
                NULL, 0x0,
2287
14
                NULL, HFILL }
2288
14
        },
2289
14
        { &hf_tibia_charlist_entry_name,
2290
14
            { "Character name", "tibia.charlist.name",
2291
14
                FT_UINT_STRING, BASE_NONE,
2292
14
                NULL, 0x0,
2293
14
                NULL, HFILL }
2294
14
        },
2295
14
        { &hf_tibia_charlist_entry_world,
2296
14
            { "World", "tibia.charlist.world",
2297
14
                FT_UINT_STRING, BASE_NONE,
2298
14
                NULL, 0x0,
2299
14
                NULL, HFILL }
2300
14
        },
2301
14
        { &hf_tibia_charlist_entry_ip,
2302
14
            { "IP", "tibia.charlist.ip",
2303
14
                FT_IPv4, BASE_NONE,
2304
14
                NULL, 0x0,
2305
14
                NULL, HFILL }
2306
14
        },
2307
14
        { &hf_tibia_charlist_entry_port,
2308
14
            { "Port", "tibia.charlist.port",
2309
14
                FT_UINT16, BASE_DEC,
2310
14
                NULL, 0x0,
2311
14
                NULL, HFILL }
2312
14
        },
2313
14
        { &hf_tibia_worldlist,
2314
14
            { "World list", "tibia.worldlist",
2315
14
                FT_NONE, BASE_NONE, NULL, 0x0,
2316
14
                NULL, HFILL }
2317
14
        },
2318
14
        { &hf_tibia_worldlist_entry_name,
2319
14
            { "World", "tibia.worldlist.name",
2320
14
                FT_UINT_STRING, BASE_NONE,
2321
14
                NULL, 0x0,
2322
14
                NULL, HFILL }
2323
14
        },
2324
14
        { &hf_tibia_worldlist_length,
2325
14
            { "World count", "tibia.worldlist.count",
2326
14
                FT_UINT16, BASE_DEC,
2327
14
                NULL, 0x0,
2328
14
                NULL, HFILL }
2329
14
        },
2330
14
        { &hf_tibia_worldlist_entry_id,
2331
14
            { "World ID", "tibia.worldlist.id",
2332
14
                FT_UINT8, BASE_DEC,
2333
14
                NULL, 0x0,
2334
14
                NULL, HFILL }
2335
14
        },
2336
14
        { &hf_tibia_worldlist_entry_ip,
2337
14
            { "IP", "tibia.worldlist.ip",
2338
14
                FT_UINT_STRING, BASE_NONE,
2339
14
                NULL, 0x0,
2340
14
                NULL, HFILL }
2341
14
        },
2342
14
        { &hf_tibia_worldlist_entry_port,
2343
14
            { "Port", "tibia.worldlist.port",
2344
14
                FT_UINT16, BASE_DEC,
2345
14
                NULL, 0x0,
2346
14
                NULL, HFILL }
2347
14
        },
2348
14
        { &hf_tibia_worldlist_entry_preview,
2349
14
            { "Preview State", "tibia.worldlist.preview",
2350
14
                FT_BOOLEAN, 8,
2351
14
                NULL, 0x1,
2352
14
                NULL, HFILL }
2353
14
        },
2354
14
        { &hf_tibia_pacc_days,
2355
14
            { "Premium days left", "tibia.pacc",
2356
14
                FT_UINT16, BASE_DEC,
2357
14
                NULL, 0x0,
2358
14
                NULL, HFILL }
2359
14
        },
2360
14
        { &hf_tibia_channel_id,
2361
14
            { "Channel id", "tibia.channel.id",
2362
14
                FT_UINT16, BASE_HEX,
2363
14
                NULL, 0x0,
2364
14
                NULL, HFILL }
2365
14
        },
2366
14
        { &hf_tibia_channel_name,
2367
14
            { "Channel name", "tibia.channel",
2368
14
                FT_UINT_STRING, BASE_NONE,
2369
14
                NULL, 0x0,
2370
14
                NULL, HFILL }
2371
14
        },
2372
14
        { &hf_tibia_speech_type,
2373
14
            { "Type", "tibia.speechtype",
2374
14
                FT_UINT8, BASE_HEX,
2375
14
                VALS(speech_types), 0x0,
2376
14
                NULL, HFILL }
2377
14
        },
2378
14
        { &hf_tibia_chat_msg,
2379
14
            { "Message", "tibia.msg",
2380
14
                FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2381
14
                NULL, HFILL }
2382
14
        },
2383
14
        { &hf_tibia_coords_x,
2384
14
            { "X-Coordinate", "tibia.coord.x",
2385
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
2386
14
                NULL, HFILL }
2387
14
        },
2388
14
        { &hf_tibia_coords_y,
2389
14
            { "Y-Coordinate", "tibia.coords.y",
2390
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
2391
14
                NULL, HFILL }
2392
14
        },
2393
14
        { &hf_tibia_coords_z,
2394
14
            { "Z-Coordinate", "tibia.coords.z",
2395
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
2396
14
                NULL, HFILL }
2397
14
        },
2398
14
        { &hf_tibia_coords,
2399
14
            { "Coordinates", "tibia.coords",
2400
14
                FT_STRING, BASE_NONE,
2401
14
                NULL, 0x0,
2402
14
                NULL, HFILL }
2403
14
        },
2404
14
        { &hf_tibia_stackpos,
2405
14
            { "Stack position", "tibia.coords.stackpos",
2406
14
                FT_UINT8, BASE_DEC,
2407
14
                NULL, 0x0,
2408
14
                NULL, HFILL }
2409
14
        },
2410
#if 0
2411
        { &hf_tibia_item,
2412
            { "Item ID", "tibia.item",
2413
                FT_UINT16, BASE_DEC,
2414
                NULL, 0x0,
2415
                NULL, HFILL }
2416
        },
2417
#endif
2418
14
        { &hf_tibia_container,
2419
14
            { "Container index", "tibia.container",
2420
14
                FT_UINT8, BASE_DEC,
2421
14
                NULL, 0x0,
2422
14
                NULL, HFILL }
2423
14
        },
2424
14
        { &hf_tibia_container_icon,
2425
14
            { "Container icon", "tibia.container.icon",
2426
14
                FT_UINT16, BASE_DEC,
2427
14
                NULL, 0x0,
2428
14
                NULL, HFILL }
2429
14
        },
2430
14
        { &hf_tibia_container_slot,
2431
14
            { "Container slot", "tibia.container.slot",
2432
14
                FT_UINT8, BASE_DEC,
2433
14
                NULL, 0x0,
2434
14
                NULL, HFILL }
2435
14
        },
2436
14
        { &hf_tibia_container_slots,
2437
14
            { "Container slots", "tibia.container.slots",
2438
14
                FT_UINT16, BASE_DEC,
2439
14
                NULL, 0x0,
2440
14
                NULL, HFILL }
2441
14
        },
2442
14
        { &hf_tibia_inventory,
2443
14
            { "Inventory slot", "tibia.inventory",
2444
14
                FT_UINT16, BASE_DEC,
2445
14
                NULL, 0x0,
2446
14
                NULL, HFILL }
2447
14
        },
2448
14
        { &hf_tibia_vip,
2449
14
            { "VIP GUID", "tibia.vip",
2450
14
                FT_UINT32, BASE_HEX, NULL, 0x0,
2451
14
                NULL, HFILL }
2452
14
        },
2453
14
        { &hf_tibia_vip_online,
2454
14
            { "Online", "tibia.vip.online",
2455
14
                FT_BOOLEAN, 8,
2456
14
                NULL, 0x1,
2457
14
                NULL, HFILL }
2458
14
        },
2459
14
        { &hf_tibia_player,
2460
14
            { "Player name", "tibia.player",
2461
14
                FT_UINT_STRING, BASE_NONE,
2462
14
                NULL, 0x0,
2463
14
                NULL, HFILL }
2464
14
        },
2465
14
        { &hf_tibia_creature,
2466
14
            { "Creature", "tibia.creature",
2467
14
                FT_UINT32, BASE_HEX,
2468
14
                NULL, 0x0,
2469
14
                NULL, HFILL }
2470
14
        },
2471
14
        { &hf_tibia_creature_health,
2472
14
            { "Creature", "tibia.creature.health",
2473
14
                FT_UINT8, BASE_DEC|BASE_UNIT_STRING,
2474
14
                UNS(&units_percent), 0x0,
2475
14
                NULL, HFILL }
2476
14
        },
2477
14
        { &hf_tibia_window,
2478
14
            { "Window", "tibia.window",
2479
14
                FT_UINT32, BASE_HEX,
2480
14
                NULL, 0x0,
2481
14
                NULL, HFILL }
2482
14
        },
2483
14
        { &hf_tibia_window_icon,
2484
14
            { "Window Icon", "tibia.window.icon",
2485
14
                FT_UINT8, BASE_HEX,
2486
14
                NULL, 0x0,
2487
14
                NULL, HFILL }
2488
14
        },
2489
14
        { &hf_tibia_window_textlen,
2490
14
            { "Window Text Length", "tibia.window.text.len",
2491
14
                FT_UINT8, BASE_DEC,
2492
14
                NULL, 0x0,
2493
14
                NULL, HFILL }
2494
14
        },
2495
14
        { &hf_tibia_window_text,
2496
14
            { "Window Text", "tibia.window.text",
2497
14
                FT_UINT_STRING, BASE_NONE,
2498
14
                NULL, 0x0,
2499
14
                NULL, HFILL }
2500
14
        },
2501
14
        { &hf_tibia_squarecolor,
2502
14
            { "Square Color", "tibia.creature.square",
2503
14
                FT_UINT8, BASE_HEX,
2504
14
                NULL, 0x0,
2505
14
                NULL, HFILL }
2506
14
        },
2507
14
        { &hf_tibia_light_color,
2508
14
            { "Light Color", "tibia.light.color",
2509
14
                FT_UINT8, BASE_HEX,
2510
14
                NULL, 0x0,
2511
14
                NULL, HFILL }
2512
14
        },
2513
14
        { &hf_tibia_light_level,
2514
14
            { "Light Level", "tibia.light.level",
2515
14
                FT_UINT8, BASE_DEC,
2516
14
                NULL, 0x0,
2517
14
                NULL, HFILL }
2518
14
        },
2519
14
        { &hf_tibia_magic_effect_id,
2520
14
            { "Magic Effect", "tibia.magic_effect",
2521
14
                FT_UINT8, BASE_HEX,
2522
14
                NULL, 0x0,
2523
14
                NULL, HFILL }
2524
14
        },
2525
14
        { &hf_tibia_animated_text_color,
2526
14
            { "Text Color", "tibia.animated_text.color",
2527
14
                FT_UINT8, BASE_HEX,
2528
14
                NULL, 0x0,
2529
14
                NULL, HFILL }
2530
14
        },
2531
14
        { &hf_tibia_animated_text,
2532
14
            { "Text", "tibia.animated_text",
2533
14
                FT_UINT16, BASE_HEX,
2534
14
                NULL, 0x0,
2535
14
                NULL, HFILL }
2536
14
        },
2537
14
        { &hf_tibia_textmsg_class,
2538
14
            { "Text Message Class", "tibia.textmsg.class",
2539
14
                FT_UINT8, BASE_HEX,
2540
14
                NULL, 0x0,
2541
14
                NULL, HFILL }
2542
14
        },
2543
14
        { &hf_tibia_textmsg,
2544
14
            { "Text", "tibia.textmsg",
2545
14
                FT_UINT_STRING, BASE_NONE,
2546
14
                NULL, 0x0,
2547
14
                NULL, HFILL }
2548
14
        },
2549
14
        { &hf_tibia_projectile,
2550
14
            { "Projectile", "tibia.projectile",
2551
14
                FT_UINT32, BASE_HEX,
2552
14
                NULL, 0x0,
2553
14
                NULL, HFILL }
2554
14
        },
2555
14
        { &hf_tibia_walk_dir,
2556
14
            { "Walk Direction", "tibia.walk_dir",
2557
14
                FT_UINT8, BASE_HEX,
2558
14
                NULL, 0x0,
2559
14
                NULL, HFILL }
2560
14
        },
2561
14
    };
2562
2563
    /* Setup protocol subtree array */
2564
14
    static int *ett[] = {
2565
14
        &ett_tibia,
2566
14
        &ett_command,
2567
14
        &ett_file_versions,
2568
14
        &ett_client_info,
2569
14
        &ett_locale,
2570
14
        &ett_cpu,
2571
14
        &ett_resolution,
2572
14
        &ett_charlist,
2573
14
        &ett_char,
2574
14
        &ett_worldlist,
2575
14
        &ett_world,
2576
14
        &ett_coords,
2577
14
        &ett_char_cond,
2578
14
    };
2579
2580
14
    static ei_register_info ei[] = {
2581
14
        { &ei_xtea_len_toobig,
2582
14
            { "tibia.error.xtea.length.toobig", PI_DECRYPTION, PI_ERROR,
2583
14
                "XTEA-encrypted length exceeds packet", EXPFILL }
2584
14
        },
2585
14
        { &ei_adler32_checksum_bad, { "tibia.error.checksum_bad", PI_CHECKSUM, PI_ERROR,
2586
14
                "Bad checksum", EXPFILL }
2587
14
        },
2588
14
        { &ei_rsa_plaintext_no_leading_zero,
2589
14
            { "tibia.error.rsa", PI_DECRYPTION, PI_ERROR,
2590
14
                "First byte after RSA decryption must be zero", EXPFILL }
2591
14
        },
2592
14
        { &ei_rsa_ciphertext_too_short,
2593
14
            { "tibia.error.rsa.length.tooshort", PI_DECRYPTION, PI_ERROR,
2594
14
                "RSA-encrypted data is at least 128 byte long", EXPFILL }
2595
14
        },
2596
14
        { &ei_rsa_decrypt_failed,
2597
14
            { "tibia.error.rsa.failed", PI_DECRYPTION, PI_ERROR,
2598
14
                "Decrypting RSA block failed", EXPFILL }
2599
14
        },
2600
14
    };
2601
2602
14
    proto_tibia = proto_register_protocol (
2603
14
            "Tibia Protocol", /* name */
2604
14
            "Tibia",          /* short name */
2605
14
            "tibia"           /* abbrev */
2606
14
            );
2607
14
    proto_register_field_array(proto_tibia, hf, array_length(hf));
2608
14
    proto_register_subtree_array(ett, array_length(ett));
2609
14
    tibia_handle = register_dissector("tibia", dissect_tibia_tcp, proto_tibia);
2610
2611
14
    expert_module_t *expert_tibia = expert_register_protocol(proto_tibia);
2612
14
    expert_register_field_array (expert_tibia, ei, array_length (ei));
2613
2614
14
    module_t *tibia_module = prefs_register_protocol(proto_tibia, NULL);
2615
2616
14
    prefs_register_bool_preference(tibia_module, "try_otserv_key", "Try OTServ's RSA key",
2617
14
        "Try the default RSA key in use by nearly all Open Tibia servers", &try_otserv_key);
2618
2619
14
    prefs_register_bool_preference(tibia_module, "show_char_name", "Show character name for each packet",
2620
14
        "Shows active character for every packet", &show_char_name);
2621
14
    prefs_register_bool_preference(tibia_module, "show_acc_info", "Show account info for each packet",
2622
14
        "Shows account name/password or session key for every packet", &show_acc_info);
2623
14
    prefs_register_bool_preference(tibia_module, "show_xtea_key", "Show symmetric key used for each packet",
2624
14
        "Shows which XTEA key was applied for a packet", &show_xtea_key);
2625
14
    prefs_register_bool_preference(tibia_module, "dissect_game_commands", "Attempt dissection of game packet commands",
2626
14
        "Only decrypt packets and dissect login packets. Pass game commands to the data dissector", &dissect_game_commands);
2627
14
    prefs_register_bool_preference(tibia_module, "reassemble_tcp_segments",
2628
14
                                   "Reassemble Tibia packets spanning multiple TCP segments",
2629
14
                                   "Whether the Tibia dissector should reassemble packets spanning multiple TCP segments."
2630
14
                                   " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2631
14
                                   &reassemble_tcp_segments);
2632
2633
2634
#ifdef HAVE_LIBGNUTLS
2635
    static uat_field_t rsakeylist_uats_flds[] = {
2636
        UAT_FLD_CSTRING_OTHER(rsakeylist_uats, ipaddr, "IP address", rsakeys_uat_fld_ip_chk_cb, "IPv4 address"),
2637
        UAT_FLD_CSTRING_OTHER(rsakeylist_uats, port, "Port", rsakeys_uat_fld_port_chk_cb, "Port Number"),
2638
        UAT_FLD_FILENAME_OTHER(rsakeylist_uats, keyfile, "Key File", rsakeys_uat_fld_fileopen_chk_cb, "Private keyfile."),
2639
        UAT_FLD_CSTRING_OTHER(rsakeylist_uats, password,"Password", rsakeys_uat_fld_password_chk_cb, "Password (for keyfile)"),
2640
        UAT_END_FIELDS
2641
    };
2642
2643
    rsakeys_uat = uat_new("RSA Keys",
2644
            sizeof(struct rsakeys_assoc),
2645
            "tibia_rsa_keys",        /* filename */
2646
            true,                    /* from_profile */
2647
            &rsakeylist_uats,        /* data_ptr */
2648
            &nrsakeys,               /* numitems_ptr */
2649
            UAT_AFFECTS_DISSECTION,
2650
            NULL,
2651
            rsakeys_copy_cb,
2652
            NULL,
2653
            rsakeys_free_cb,
2654
            rsa_parse_uat,
2655
            NULL,
2656
            rsakeylist_uats_flds);
2657
    prefs_register_uat_preference(tibia_module, "rsakey_table",
2658
            "RSA keys list",
2659
            "A table of RSA keys for decrypting protocols newer than 7.61",
2660
            rsakeys_uat
2661
    );
2662
2663
    rsakeys = g_hash_table_new_full(rsakey_hash, rsakey_equal, rsakey_free, NULL);
2664
#endif
2665
2666
14
    static uat_field_t xteakeylist_uats_flds[] = {
2667
14
        UAT_FLD_DEC(xteakeylist_uats, framenum, "Frame Number", "XTEA key"),
2668
14
        UAT_FLD_CSTRING_OTHER(xteakeylist_uats, key, "XTEA Key", xteakeys_uat_fld_key_chk_cb, "Symmetric (XTEA) key"),
2669
14
        UAT_END_FIELDS
2670
14
    };
2671
2672
14
    xteakeys_uat = uat_new("XTEA Keys",
2673
14
            sizeof(struct xteakeys_assoc),
2674
14
            "tibia_xtea_keys",       /* filename */
2675
14
            true,                    /* from_profile */
2676
14
            &xteakeylist_uats,       /* data_ptr */
2677
14
            &nxteakeys,              /* numitems_ptr */
2678
14
            UAT_AFFECTS_DISSECTION,
2679
14
            NULL,
2680
14
            xteakeys_copy_cb,
2681
14
            NULL,
2682
14
            xteakeys_free_cb,
2683
14
            xtea_parse_uat,
2684
14
            NULL,
2685
14
            xteakeylist_uats_flds);
2686
14
    prefs_register_uat_preference(tibia_module, "xteakey_table",
2687
14
            "XTEA keys list",
2688
14
            "A table of XTEA keys for decrypting protocols newer than 7.61",
2689
14
            xteakeys_uat
2690
14
    );
2691
2692
14
    xteakeys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
2693
2694
    /* TODO best way to store this in source? */
2695
14
    static const char sexp[] =
2696
14
        "(private-key (rsa"
2697
14
        "(n #9b646903b45b07ac956568d87353bd7165139dd7940703b03e6dd079399661b4a837aa60561d7ccb9452fa0080594909882ab5bca58a1a1b35f8b1059b72b1212611c6152ad3dbb3cfbee7adc142a75d3d75971509c321c5c24a5bd51fd460f01b4e15beb0de1930528a5d3f15c1e3cbf5c401d6777e10acaab33dbe8d5b7ff5#)"
2698
14
        "(e #010001#)"
2699
14
        "(d #428bd3b5346daf71a761106f71a43102f8c857d6549c54660bb6378b52b0261399de8ce648bac410e2ea4e0a1ced1fac2756331220ca6db7ad7b5d440b7828865856e7aa6d8f45837feee9b4a3a0aa21322a1e2ab75b1825e786cf81a28a8a09a1e28519db64ff9baf311e850c2bfa1fb7b08a056cc337f7df443761aefe8d81#)"
2700
14
        "(p #91b37307abe12c05a1b78754746cda444177a784b035cbb96c945affdc022d21da4bd25a4eae259638153e9d73c97c89092096a459e5d16bcadd07fa9d504885#)"
2701
14
        "(q #0111071b206bafb9c7a2287d7c8d17a42e32abee88dfe9520692b5439d9675817ff4f8c94a4abcd4b5f88e220f3a8658e39247a46c6983d85618fd891001a0acb1#)"
2702
14
        "(u #6b21cd5e373fe462a22061b44a41fd01738a3892e0bd8728dbb5b5d86e7675235a469fea3266412fe9a659f486144c1e593d56eb3f6cfc7b2edb83ba8e95403a#)"
2703
14
        "))";
2704
2705
14
    gcry_error_t err = gcry_sexp_new(&otserv_key, sexp, 0, 1);
2706
14
    if (err)
2707
0
        report_failure("Loading OTServ RSA key failed: %s/%s\n", gcry_strerror(err), gcry_strsource(err));
2708
14
}
2709
2710
static unsigned
2711
get_dissect_tibia_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
2712
178
{
2713
178
    return tvb_get_letohs(tvb, offset) + 2;
2714
178
}
2715
2716
static int
2717
dissect_tibia_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2718
16
{
2719
16
    static uint32_t packet_num, fragment_num;
2720
2721
16
    if (!packet_num) packet_num = pinfo->num;
2722
16
    if (packet_num != pinfo->num) {
2723
15
        fragment_num = 0;
2724
15
        packet_num = pinfo->num;
2725
15
    }
2726
2727
16
    fragment_num++;
2728
2729
2730
16
    tcp_dissect_pdus(tvb, pinfo, tree, reassemble_tcp_segments, 2,
2731
16
               get_dissect_tibia_len, dissect_tibia, GUINT_TO_POINTER(fragment_num));
2732
16
    return tvb_reported_length(tvb);
2733
16
}
2734
2735
void
2736
proto_reg_handoff_tibia(void)
2737
14
{
2738
14
    dissector_add_uint_range_with_preference("tcp.port", TIBIA_DEFAULT_TCP_PORT_RANGE, tibia_handle);
2739
14
}
2740
2741
2742
/*
2743
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2744
 *
2745
 * Local variables:
2746
 * c-basic-offset: 4
2747
 * tab-width: 8
2748
 * indent-tabs-mode: nil
2749
 * End:
2750
 *
2751
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2752
 * :indentSize=4:tabSize=8:noTabs=true:
2753
 */