Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-trueconf.c
Line
Count
Source
1
/* packet-trueconf.c
2
 * Routines for TrueConf packet dissection
3
 * Copyright 2025, Sergey Rudakov <rudakov.private.bsf@gmail.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
#include <wireshark.h>
14
#include <epan/packet.h>
15
#include <epan/proto.h>
16
#include "packet-tcp.h"
17
18
19
15
#define TRUECONF_PORT 4307
20
0
#define TRUECONF_MAGIC "_VS_TRANSPORT_"
21
0
#define TRUECONF_MAGIC_LEN 14
22
23
static int proto_trueconf;
24
static int ett_trueconf;
25
26
static int hf_trueconf_magic;
27
static int hf_trueconf_zero2;
28
static int hf_trueconf_conn_id;
29
static int hf_trueconf_flags;
30
static int hf_trueconf_cap;
31
static int hf_trueconf_unk1;
32
static int hf_trueconf_ver_major;
33
static int hf_trueconf_ver_minor;
34
static int hf_trueconf_name_len;
35
static int hf_trueconf_host;
36
static int hf_trueconf_sep0;
37
static int hf_trueconf_token_len;
38
static int hf_trueconf_token;
39
static int hf_trueconf_msg_type;
40
static int hf_trueconf_len_a;
41
static int hf_trueconf_len_b;
42
static int hf_trueconf_seed16;
43
static int hf_trueconf_payload;
44
static int hf_trueconf_trailer1;
45
static int hf_trueconf_trailer2;
46
static int hf_trueconf_trailer3;
47
static int hf_trueconf_trailer4;
48
49
static int find_magic_offset(tvbuff_t *tvb, int offset)
50
0
{
51
0
    if (tvb_memeql(tvb, offset, (const uint8_t*)TRUECONF_MAGIC, TRUECONF_MAGIC_LEN) == 0)
52
0
        return offset;
53
54
0
    return -1;
55
0
}
56
57
58
static unsigned
59
get_trueconf_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
60
0
{
61
0
    int magic_off = find_magic_offset(tvb, offset);
62
0
    if (magic_off < 0)
63
0
        return 0;
64
65
0
    unsigned headers = 2 + 3 + 1 + 2 + 1 + 1 + 1 + 1;
66
0
    if (tvb_captured_length_remaining(tvb, magic_off) < TRUECONF_MAGIC_LEN + headers)
67
0
        return 0;
68
69
0
    unsigned pos = magic_off + TRUECONF_MAGIC_LEN + headers;
70
0
    unsigned name_len = tvb_get_uint8(tvb, pos - 1);
71
0
    unsigned caplen = tvb_captured_length(tvb);
72
0
    if (name_len > 0 && caplen - pos == 0 )  // if the name length is not 0 and the name is missing,
73
0
        return caplen; // it means that there will be no new data
74
75
0
    pos += name_len;
76
77
0
    if (pos + 2 > caplen)
78
0
        return 0; //  token_len
79
80
0
    unsigned token_len = tvb_get_ntohs(tvb, pos);
81
0
    pos += 2 + token_len;
82
0
    if (pos + 2 + 4 + 4 + 16 > caplen)
83
0
        return 0; // msg_type + len_a + len_b + seed16
84
85
0
    unsigned len_a = tvb_get_letohl(tvb, pos + 2);
86
0
    unsigned len_b = tvb_get_letohl(tvb, pos + 6);
87
0
    unsigned payload_len = len_a < len_b ? len_a : len_b;
88
0
    unsigned full_len = pos + 2 + 4 + 4 + 16 + payload_len - magic_off - headers;
89
0
    return full_len;
90
0
}
91
92
93
static int dissect_trueconf_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
94
0
{
95
0
    int off = find_magic_offset(tvb, 0);
96
0
    if (off < 0)
97
0
        return 0;
98
99
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "TRUECONF");
100
101
0
    proto_item *ti = proto_tree_add_item(tree, proto_trueconf, tvb, off, -1, ENC_NA);
102
0
    proto_tree *trueconf_tree = proto_item_add_subtree(ti, ett_trueconf);
103
104
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_magic, tvb, off, 14, ENC_ASCII);
105
0
    off += 14;
106
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_zero2, tvb, off, 2, ENC_NA);
107
0
    off += 2;
108
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_conn_id, tvb, off, 3, ENC_NA);
109
0
    off += 3;
110
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_flags, tvb, off, 1, ENC_BIG_ENDIAN);
111
0
    off += 1;
112
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_cap, tvb, off, 2, ENC_BIG_ENDIAN);
113
0
    off += 2;
114
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_unk1, tvb, off, 1, ENC_BIG_ENDIAN);
115
0
    off += 1;
116
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_ver_major, tvb, off, 1, ENC_BIG_ENDIAN);
117
0
    off += 1;
118
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_ver_minor, tvb, off, 1, ENC_BIG_ENDIAN);
119
0
    off += 1;
120
121
0
    uint32_t name_len;
122
0
    proto_tree_add_item_ret_uint(trueconf_tree, hf_trueconf_name_len, tvb, off, 1, ENC_BIG_ENDIAN, &name_len);
123
0
    off += 1;
124
125
0
    if (name_len > 0) {
126
0
        proto_tree_add_item(trueconf_tree, hf_trueconf_host, tvb, off, name_len, ENC_ASCII);
127
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Handshake host=%s", tvb_format_text(pinfo->pool, tvb, off, name_len));
128
0
        off += name_len;
129
0
    }
130
131
0
    if (tvb_reported_length_remaining(tvb, off) > 0 && tvb_get_uint8(tvb, off) == 0x00) {
132
0
        proto_tree_add_item(trueconf_tree, hf_trueconf_sep0, tvb, off, 1, ENC_BIG_ENDIAN);
133
0
        off += 1;
134
0
    }
135
136
0
    uint32_t token_len;
137
0
    proto_tree_add_item_ret_uint(trueconf_tree, hf_trueconf_token_len, tvb, off, 1, ENC_BIG_ENDIAN, &token_len);
138
0
    off += 1;
139
0
    if (token_len > 0) {
140
0
        proto_tree_add_item(trueconf_tree, hf_trueconf_token, tvb, off, token_len, ENC_ASCII);
141
0
        off += token_len;
142
0
    }
143
144
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_msg_type, tvb, off, 2, ENC_BIG_ENDIAN);
145
0
    off += 2;
146
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_len_a, tvb, off, 4, ENC_LITTLE_ENDIAN);
147
0
    off += 4;
148
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_len_b, tvb, off, 4, ENC_LITTLE_ENDIAN);
149
0
    off += 4;
150
0
    proto_tree_add_item(trueconf_tree, hf_trueconf_seed16, tvb, off, 16, ENC_NA);
151
0
    off += 16;
152
153
0
    int remain = tvb_reported_length_remaining(tvb, off);
154
0
    if (remain > 0) {
155
0
        proto_item *payload_ti = proto_tree_add_item(trueconf_tree, hf_trueconf_payload, tvb, off, remain, ENC_NA);
156
0
        if (remain >= 16) {
157
0
            int tail = off + remain - 16;
158
0
            proto_tree *tr = proto_item_add_subtree(payload_ti, ett_trueconf);
159
0
            proto_tree_add_item(tr, hf_trueconf_trailer1, tvb, tail, 4, ENC_LITTLE_ENDIAN);
160
0
            proto_tree_add_item(tr, hf_trueconf_trailer2, tvb, tail + 4, 4, ENC_LITTLE_ENDIAN);
161
0
            proto_tree_add_item(tr, hf_trueconf_trailer3, tvb, tail + 8, 4, ENC_LITTLE_ENDIAN);
162
0
            proto_tree_add_item(tr, hf_trueconf_trailer4, tvb, tail + 12, 4, ENC_LITTLE_ENDIAN);
163
0
        }
164
0
    }
165
166
0
    return tvb_captured_length(tvb);
167
0
}
168
169
static int dissect_trueconf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
170
0
{
171
0
    tcp_dissect_pdus(tvb, pinfo, tree, TRUE, TRUECONF_MAGIC_LEN, get_trueconf_pdu_len, dissect_trueconf_pdu, data);
172
0
    return tvb_captured_length(tvb);
173
0
}
174
175
176
void proto_register_trueconf(void)
177
15
{
178
15
    static hf_register_info hf[] = {
179
15
        { &hf_trueconf_magic,      { "Magic",          "trueconf.magic",     FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
180
15
        { &hf_trueconf_zero2,      { "Reserved(2)",    "trueconf.zero2",     FT_BYTES,  BASE_NONE, NULL, 0, NULL, HFILL }},
181
15
        { &hf_trueconf_conn_id,    { "ConnID(3)",      "trueconf.conn_id",   FT_BYTES,  BASE_NONE, NULL, 0, NULL, HFILL }},
182
15
        { &hf_trueconf_flags,      { "Flags",          "trueconf.flags",     FT_UINT8,  BASE_HEX,  NULL, 0, NULL, HFILL }},
183
15
        { &hf_trueconf_cap,        { "Capabilities",   "trueconf.cap",       FT_UINT16, BASE_HEX,  NULL, 0, NULL, HFILL }},
184
15
        { &hf_trueconf_unk1,       { "Unknown1",       "trueconf.unk1",      FT_UINT8,  BASE_HEX,  NULL, 0, NULL, HFILL }},
185
15
        { &hf_trueconf_ver_major,  { "Version Major",  "trueconf.ver.major", FT_UINT8,  BASE_DEC,  NULL, 0, NULL, HFILL }},
186
15
        { &hf_trueconf_ver_minor,  { "Version Minor",  "trueconf.ver.minor", FT_UINT8,  BASE_DEC,  NULL, 0, NULL, HFILL }},
187
15
        { &hf_trueconf_name_len,   { "Name Length",    "trueconf.name_len",  FT_UINT8,  BASE_DEC,  NULL, 0, NULL, HFILL }},
188
15
        { &hf_trueconf_host,       { "Server Name",    "trueconf.host",      FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
189
15
        { &hf_trueconf_sep0,       { "Separator(0x00)","trueconf.sep0",      FT_UINT8,  BASE_HEX,  NULL, 0, NULL, HFILL }},
190
15
        { &hf_trueconf_token_len,  { "Token Length",   "trueconf.token_len", FT_UINT16, BASE_DEC,  NULL, 0, NULL, HFILL }},
191
15
        { &hf_trueconf_token,      { "Token/ID",       "trueconf.token",     FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
192
15
        { &hf_trueconf_msg_type,   { "Message Type",   "trueconf.msg_type",  FT_UINT16, BASE_DEC,  NULL, 0, NULL, HFILL }},
193
15
        { &hf_trueconf_len_a,      { "Length A (LE)",  "trueconf.len_a",     FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
194
15
        { &hf_trueconf_len_b,      { "Length B (LE)",  "trueconf.len_b",     FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
195
15
        { &hf_trueconf_seed16,     { "Seed/Salt (16)", "trueconf.seed16",    FT_BYTES,  BASE_NONE, NULL, 0, NULL, HFILL }},
196
15
        { &hf_trueconf_payload,    { "Opaque Payload", "trueconf.payload",   FT_BYTES,  BASE_NONE, NULL, 0, NULL, HFILL }},
197
15
        { &hf_trueconf_trailer1,   { "Trailer1 (LE)",  "trueconf.trailer1",  FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
198
15
        { &hf_trueconf_trailer2,   { "Trailer2 (LE)",  "trueconf.trailer2",  FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
199
15
        { &hf_trueconf_trailer3,   { "Trailer3 (LE)",  "trueconf.trailer3",  FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
200
15
        { &hf_trueconf_trailer4,   { "Trailer4 (LE)",  "trueconf.trailer4",  FT_UINT32, BASE_DEC,  NULL, 0, NULL, HFILL }},
201
15
    };
202
203
15
    static int *ett[] = { &ett_trueconf };
204
205
15
    proto_trueconf = proto_register_protocol("TrueConf Protocol", "TrueConf", "trueconf");
206
207
15
    proto_register_field_array(proto_trueconf, hf, array_length(hf));
208
15
    proto_register_subtree_array(ett, array_length(ett));
209
15
}
210
211
void proto_reg_handoff_trueconf(void)
212
15
{
213
15
    dissector_handle_t trueconf_handle;
214
15
    trueconf_handle = create_dissector_handle(dissect_trueconf, proto_trueconf);
215
15
    dissector_add_uint_with_preference("tcp.port", TRUECONF_PORT, trueconf_handle);
216
15
}