Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-tcpcl.c
Line
Count
Source
1
/* packet-tcpcl.c
2
 * References:
3
 *     RFC 7242: https://tools.ietf.org/html/rfc7242
4
 *     RFC 9174: https://www.rfc-editor.org/rfc/rfc9174.html
5
 *
6
 * TCPCLv4 portions copyright 2019-2021, Brian Sipos <brian.sipos@gmail.com>
7
 * TCPCLv3 portions copyright 2006-2007 The MITRE Corporation.
8
 * All Rights Reserved.
9
 * Approved for Public Release; Distribution Unlimited.
10
 * Tracking Number 07-0090.
11
 *
12
 * The US Government will not be charged any license fee and/or royalties
13
 * related to this software. Neither name of The MITRE Corporation; nor the
14
 * names of its contributors may be used to endorse or promote products
15
 * derived from this software without specific prior written permission.
16
 *
17
 * Wireshark - Network traffic analyzer
18
 * By Gerald Combs <gerald@wireshark.org>
19
 * Copyright 1998 Gerald Combs
20
 *
21
 * SPDX-License-Identifier: GPL-2.0-or-later
22
 */
23
24
/*
25
 *    Modifications were made to this file under designation MFS-33289-1 and
26
 *    are Copyright 2015 United States Government as represented by NASA
27
 *       Marshall Space Flight Center. All Rights Reserved.
28
 *
29
 *    Released under the GNU GPL with NASA legal approval granted 2016-06-10.
30
 *
31
 *    The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
32
 *    either expressed, implied or statutory and this agreement does not,
33
 *    in any manner, constitute an endorsement by government agency of any
34
 *    results, designs or products resulting from use of the subject software.
35
 *    See the Agreement for the specific language governing permissions and
36
 *    limitations.
37
 */
38
39
#include "config.h"
40
41
#include <inttypes.h>
42
#include <epan/packet.h>
43
#include <epan/reassemble.h>
44
#include <epan/expert.h>
45
#include <epan/tfs.h>
46
#include <epan/tvbuff-int.h>
47
#include <epan/exceptions.h>
48
#include <wsutil/array.h>
49
#include "packet-tls-utils.h"
50
#include "packet-tcp.h"
51
#include "packet-ber.h"
52
#include "packet-bpv6.h"
53
#include "packet-tcpcl.h"
54
55
void proto_register_tcpcl(void);
56
void proto_reg_handoff_tcpcl(void);
57
58
/// Contact header magic bytes
59
static const uint8_t magic[] = {'d', 't', 'n', '!'};
60
/// Minimum size of contact header for any version
61
static const unsigned minimum_chdr_size = 6;
62
63
/// Options for missing contact header handling
64
enum AllowContactHeaderMissing {
65
    CHDRMSN_DISABLE,
66
    CHDRMSN_V3FIRST,
67
    CHDRMSN_V3ONLY,
68
    CHDRMSN_V4FIRST,
69
    CHDRMSN_V4ONLY,
70
};
71
72
static const enum_val_t chdr_missing_choices[] = {
73
    {"disabled", "Disabled", CHDRMSN_DISABLE},
74
    {"v4first", "Try TCPCLv4 first", CHDRMSN_V4FIRST},
75
    {"v4only", "Only TCPCLv4", CHDRMSN_V4ONLY},
76
    {"v3first", "Try TCPCLv3 first", CHDRMSN_V3FIRST},
77
    {"v3only", "Only TCPCLv3", CHDRMSN_V3ONLY},
78
    {NULL, NULL, 0},
79
};
80
81
static int proto_tcpcl;
82
static int proto_tcpcl_exts;
83
/// Protocol column name
84
static const char *const proto_name_tcpcl = "TCPCL";
85
86
static int tcpcl_chdr_missing = CHDRMSN_V4FIRST;
87
static bool tcpcl_desegment_transfer = true;
88
static bool tcpcl_analyze_sequence = true;
89
static bool tcpcl_decode_bundle = true;
90
91
/* For Reassembling TCP Convergence Layer segments */
92
static reassembly_table xfer_reassembly_table;
93
94
/// Dissector handles
95
static dissector_handle_t tcpcl_handle;
96
static dissector_handle_t tls_handle;
97
static dissector_handle_t bundle_handle;
98
99
/// Extension sub-dissectors
100
static dissector_table_t sess_ext_dissectors;
101
static dissector_table_t xfer_ext_dissectors;
102
103
static const value_string v3_message_type_vals[] = {
104
    {((TCPCLV3_DATA_SEGMENT>>4)  & 0x0F), "DATA_SEGMENT"},
105
    {((TCPCLV3_ACK_SEGMENT>>4)   & 0x0F), "ACK_SEGMENT"},
106
    {((TCPCLV3_REFUSE_BUNDLE>>4) & 0x0F), "REFUSE_BUNDLE"},
107
    {((TCPCLV3_KEEP_ALIVE>>4)    & 0x0F), "KEEPALIVE"},
108
    {((TCPCLV3_SHUTDOWN>>4)      & 0x0F), "SHUTDOWN"},
109
    {((TCPCLV3_LENGTH>>4)      & 0x0F), "LENGTH"},
110
    {0, NULL}
111
};
112
113
/* Refuse-Bundle Reason-Code Flags as per RFC-7242: Section-5.4 */
114
static const value_string v3_refuse_reason_code[] = {
115
    {TCPCLV3_REFUSE_REASON_UNKNOWN,       "Reason for refusal is unknown"},
116
    {TCPCLV3_REFUSE_REASON_RX_COMPLETE,   "Complete Bundle Received"},
117
    {TCPCLV3_REFUSE_REASON_RX_EXHAUSTED,  "Receiver's resources exhausted"},
118
    {TCPCLV3_REFUSE_REASON_RX_RETRANSMIT, "Receiver expects re-transmission of bundle"},
119
    {0, NULL}
120
};
121
122
static const value_string v4_message_type_vals[]={
123
    {TCPCLV4_MSGTYPE_SESS_INIT, "SESS_INIT"},
124
    {TCPCLV4_MSGTYPE_SESS_TERM, "SESS_TERM"},
125
    {TCPCLV4_MSGTYPE_MSG_REJECT, "MSG_REJECT"},
126
    {TCPCLV4_MSGTYPE_KEEPALIVE, "KEEPALIVE"},
127
    {TCPCLV4_MSGTYPE_XFER_SEGMENT, "XFER_SEGMENT"},
128
    {TCPCLV4_MSGTYPE_XFER_ACK, "XFER_ACK"},
129
    {TCPCLV4_MSGTYPE_XFER_REFUSE, "XFER_REFUSE"},
130
    {0, NULL},
131
};
132
133
static const value_string v4_sess_term_reason_vals[]={
134
    {0x00, "Unknown"},
135
    {0x01, "Idle timeout"},
136
    {0x02, "Version mismatch"},
137
    {0x03, "Busy"},
138
    {0x04, "Contact Failure"},
139
    {0x05, "Resource Exhaustion"},
140
    {0, NULL},
141
};
142
143
static const value_string v4_xfer_refuse_reason_vals[]={
144
    {0x00, "Unknown"},
145
    {0x01, "Completed"},
146
    {0x02, "No Resources"},
147
    {0x03, "Retransmit"},
148
    {0x04, "Not Acceptable"},
149
    {0x05, "Extension Failure"},
150
    {0, NULL},
151
};
152
153
static const value_string v4_msg_reject_reason_vals[]={
154
    {0x00, "reserved"},
155
    {0x01, "Message Type Unknown"},
156
    {0x02, "Message Unsupported"},
157
    {0x03, "Message Unexpected"},
158
    {0, NULL},
159
};
160
161
static int hf_chdr_tree;
162
static int hf_chdr_magic;
163
static int hf_chdr_version;
164
static int hf_chdr_related;
165
166
/* TCP Convergence Header Variables */
167
static int hf_tcpclv3_mhdr;
168
static int hf_tcpclv3_pkt_type;
169
170
/* Refuse-Bundle reason code */
171
static int hf_tcpclv3_refuse_reason_code;
172
173
static int hf_tcpclv3_chdr_flags;
174
static int hf_tcpclv3_chdr_keep_alive;
175
static int hf_tcpclv3_chdr_flags_ack_req;
176
static int hf_tcpclv3_chdr_flags_frag_enable;
177
static int hf_tcpclv3_chdr_flags_nak;
178
static int hf_tcpclv3_chdr_local_eid_length;
179
static int hf_tcpclv3_chdr_local_eid;
180
181
/* TCP Convergence Data Header Variables */
182
static int hf_tcpclv3_data_procflags;
183
static int hf_tcpclv3_data_procflags_start;
184
static int hf_tcpclv3_data_procflags_end;
185
static int hf_tcpclv3_xfer_id;
186
static int hf_tcpclv3_data_segment_length;
187
static int hf_tcpclv3_data_segment_data;
188
189
/* TCP Convergence Ack Variables */
190
static int hf_tcpclv3_ack_length;
191
192
/* TCP Convergence Shutdown Header Variables */
193
static int hf_tcpclv3_shutdown_flags;
194
static int hf_tcpclv3_shutdown_flags_reason;
195
static int hf_tcpclv3_shutdown_flags_delay;
196
static int hf_tcpclv3_shutdown_reason;
197
static int hf_tcpclv3_shutdown_delay;
198
199
static int hf_tcpclv4_chdr_flags;
200
static int hf_tcpclv4_chdr_flags_cantls;
201
static int hf_tcpclv4_negotiate_use_tls;
202
203
static int hf_tcpclv4_mhdr_tree;
204
static int hf_tcpclv4_mhdr_type;
205
static int hf_tcpclv4_sess_init_keepalive;
206
static int hf_tcpclv4_sess_init_seg_mru;
207
static int hf_tcpclv4_sess_init_xfer_mru;
208
static int hf_tcpclv4_sess_init_nodeid_len;
209
static int hf_tcpclv4_sess_init_nodeid_data;
210
static int hf_tcpclv4_sess_init_extlist_len;
211
static int hf_tcpclv4_sess_init_related;
212
static int hf_tcpclv4_negotiate_keepalive;
213
214
static int hf_tcpclv4_sess_term_flags;
215
static int hf_tcpclv4_sess_term_flags_reply;
216
static int hf_tcpclv4_sess_term_reason;
217
static int hf_tcpclv4_sess_term_related;
218
219
static int hf_tcpclv4_sessext_tree;
220
static int hf_tcpclv4_sessext_flags;
221
static int hf_tcpclv4_sessext_flags_crit;
222
static int hf_tcpclv4_sessext_type;
223
static int hf_tcpclv4_sessext_len;
224
static int hf_tcpclv4_sessext_data;
225
226
static int hf_tcpclv4_xferext_tree;
227
static int hf_tcpclv4_xferext_flags;
228
static int hf_tcpclv4_xferext_flags_crit;
229
static int hf_tcpclv4_xferext_type;
230
static int hf_tcpclv4_xferext_len;
231
static int hf_tcpclv4_xferext_data;
232
233
static int hf_tcpclv4_xfer_flags;
234
static int hf_tcpclv4_xfer_flags_start;
235
static int hf_tcpclv4_xfer_flags_end;
236
static int hf_tcpclv4_xfer_id;
237
static int hf_tcpclv4_xfer_total_len;
238
static int hf_tcpclv4_xfer_segment_extlist_len;
239
static int hf_tcpclv4_xfer_segment_data_len;
240
static int hf_tcpclv4_xfer_segment_data;
241
static int hf_tcpclv4_xfer_segment_seen_len;
242
static int hf_tcpclv4_xfer_segment_related_start;
243
static int hf_tcpclv4_xfer_segment_time_start;
244
static int hf_tcpclv4_xfer_segment_related_ack;
245
static int hf_tcpclv4_xfer_segment_time_diff;
246
static int hf_tcpclv4_xfer_ack_ack_len;
247
static int hf_tcpclv4_xfer_ack_related_start;
248
static int hf_tcpclv4_xfer_ack_time_start;
249
static int hf_tcpclv4_xfer_ack_related_seg;
250
static int hf_tcpclv4_xfer_ack_time_diff;
251
static int hf_tcpclv4_xfer_refuse_reason;
252
static int hf_tcpclv4_xfer_refuse_related_seg;
253
static int hf_tcpclv4_msg_reject_reason;
254
static int hf_tcpclv4_msg_reject_head;
255
256
static int hf_tcpclv4_xferext_transferlen_total_len;
257
258
static int hf_othername_bundleeid;
259
260
/*TCP Convergence Layer Reassembly boilerplate*/
261
static int hf_xfer_segments;
262
static int hf_xfer_segment;
263
static int hf_xfer_segment_overlap;
264
static int hf_xfer_segment_overlap_conflicts;
265
static int hf_xfer_segment_multiple_tails;
266
static int hf_xfer_segment_too_long_fragment;
267
static int hf_xfer_segment_error;
268
static int hf_xfer_segment_count;
269
static int hf_xfer_reassembled_in;
270
static int hf_xfer_reassembled_length;
271
static int hf_xfer_reassembled_data;
272
273
static hf_register_info hf_tcpcl[] = {
274
    {&hf_chdr_tree, {"Contact Header", "tcpcl.contact_hdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
275
    {&hf_chdr_magic, {"Protocol Magic", "tcpcl.contact_hdr.magic", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
276
    {&hf_chdr_version, {"Version", "tcpcl.contact_hdr.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
277
    {&hf_chdr_related, {"Related Header", "tcpcl.contact_hdr.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
278
279
    {&hf_tcpclv3_mhdr,
280
     {"TCPCLv3 Message", "tcpcl.mhdr",
281
      FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
282
    },
283
    {&hf_tcpclv3_pkt_type,
284
     {"Message Type", "tcpcl.pkt_type",
285
      FT_UINT8, BASE_DEC, VALS(v3_message_type_vals), 0xF0, NULL, HFILL}
286
    },
287
    {&hf_tcpclv3_refuse_reason_code,
288
     {"Reason-Code", "tcpcl.refuse.reason_code",
289
      FT_UINT8, BASE_DEC, VALS(v3_refuse_reason_code), 0x0F, NULL, HFILL}
290
    },
291
    {&hf_tcpclv3_data_procflags,
292
     {"Data Flags", "tcpcl.data.proc.flag",
293
      FT_UINT8, BASE_HEX, NULL, TCPCLV3_DATA_FLAGS, NULL, HFILL}
294
    },
295
    {&hf_tcpclv3_data_procflags_start,
296
     {"Segment contains start of bundle", "tcpcl.data.proc.start",
297
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_DATA_START_FLAG, NULL, HFILL}
298
    },
299
    {&hf_tcpclv3_data_procflags_end,
300
     {"Segment contains end of Bundle", "tcpcl.data.proc.end",
301
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_DATA_END_FLAG, NULL, HFILL}
302
    },
303
    {&hf_tcpclv3_xfer_id, {"Implied Transfer ID", "tcpcl.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
304
    {&hf_tcpclv3_data_segment_length,
305
     {"Segment Length", "tcpcl.data.length",
306
      FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
307
    },
308
    {&hf_tcpclv3_data_segment_data,
309
     {"Segment Data", "tcpcl.data",
310
      FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}
311
    },
312
    {&hf_tcpclv3_shutdown_flags,
313
     {"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
314
      FT_UINT8, BASE_HEX, NULL, TCPCLV3_SHUTDOWN_FLAGS, NULL, HFILL}
315
    },
316
    {&hf_tcpclv3_shutdown_flags_reason,
317
     {"Shutdown includes Reason Code", "tcpcl.shutdown.reason.flag",
318
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_SHUTDOWN_REASON, NULL, HFILL}
319
    },
320
    {&hf_tcpclv3_shutdown_flags_delay,
321
     {"Shutdown includes Reconnection Delay", "tcpcl.shutdown.delay.flag",
322
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_SHUTDOWN_DELAY, NULL, HFILL}
323
    },
324
    {&hf_tcpclv3_shutdown_reason,
325
     {"Shutdown Reason Code", "tcpcl.shutdown.reason",
326
      FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
327
    },
328
    {&hf_tcpclv3_shutdown_delay,
329
     {"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
330
      FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
331
    },
332
    {&hf_tcpclv3_ack_length,
333
     {"Ack Length", "tcpcl.ack.length",
334
      FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
335
    },
336
    {&hf_tcpclv3_chdr_flags,
337
     {"Flags", "tcpcl.contact_hdr.flags",
338
      FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
339
    },
340
    {&hf_tcpclv3_chdr_flags_ack_req,
341
     {"Bundle Acks Requested", "tcpcl.contact_hdr.flags.ackreq",
342
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_BUNDLE_ACK_FLAG, NULL, HFILL}
343
    },
344
    {&hf_tcpclv3_chdr_flags_frag_enable,
345
     {"Reactive Fragmentation Enabled", "tcpcl.contact_hdr.flags.fragen",
346
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_REACTIVE_FRAG_FLAG, NULL, HFILL}
347
    },
348
    {&hf_tcpclv3_chdr_flags_nak,
349
     {"Support Negative Acknowledgements", "tcpcl.contact_hdr.flags.nak",
350
      FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV3_CONNECTOR_RCVR_FLAG, NULL, HFILL}
351
    },
352
    {&hf_tcpclv3_chdr_keep_alive,
353
     {"Keep Alive", "tcpcl.contact_hdr.keep_alive",
354
      FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}
355
    },
356
    {&hf_tcpclv3_chdr_local_eid,
357
     {"Local EID", "tcpcl.contact_hdr.local_eid",
358
      FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
359
    },
360
    {&hf_tcpclv3_chdr_local_eid_length,
361
     {"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
362
      FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}
363
    },
364
365
    {&hf_tcpclv4_chdr_flags, {"Contact Flags", "tcpcl.v4.chdr.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
366
    {&hf_tcpclv4_chdr_flags_cantls, {"CAN_TLS", "tcpcl.v4.chdr.flags.can_tls", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_CONTACT_FLAG_CANTLS, NULL, HFILL}},
367
    // Contact negotiation results
368
    {&hf_tcpclv4_negotiate_use_tls, {"Negotiated Use TLS", "tcpcl.v4.negotiated.use_tls", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
369
370
    {&hf_tcpclv4_mhdr_tree, {"TCPCLv4 Message", "tcpcl.v4.mhdr", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
371
    {&hf_tcpclv4_mhdr_type, {"Message Type", "tcpcl.v4.mhdr.type", FT_UINT8, BASE_HEX, VALS(v4_message_type_vals), 0x0, NULL, HFILL}},
372
373
    // Session extension fields
374
    {&hf_tcpclv4_sessext_tree, {"Session Extension Item", "tcpcl.v4.sessext", FT_PROTOCOL, BASE_NONE, NULL, 0x0, NULL, HFILL}},
375
    {&hf_tcpclv4_sessext_flags, {"Item Flags", "tcpcl.v4.sessext.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
376
    {&hf_tcpclv4_sessext_flags_crit, {"CRITICAL", "tcpcl.v4.sessext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL, HFILL}},
377
    {&hf_tcpclv4_sessext_type, {"Item Type", "tcpcl.v4.sessext.type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
378
    {&hf_tcpclv4_sessext_len, {"Item Length", "tcpcl.v4.sessext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
379
    {&hf_tcpclv4_sessext_data, {"Type-Specific Data", "tcpcl.v4.sessext.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
380
381
    // Transfer extension fields
382
    {&hf_tcpclv4_xferext_tree, {"Transfer Extension Item", "tcpcl.v4.xferext", FT_PROTOCOL, BASE_NONE, NULL, 0x0, NULL, HFILL}},
383
    {&hf_tcpclv4_xferext_flags, {"Item Flags", "tcpcl.v4.xferext.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
384
    {&hf_tcpclv4_xferext_flags_crit, {"CRITICAL", "tcpcl.v4.xferext.flags.critical", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_EXTENSION_FLAG_CRITICAL, NULL, HFILL}},
385
    {&hf_tcpclv4_xferext_type, {"Item Type", "tcpcl.v4.xferext.type", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
386
    {&hf_tcpclv4_xferext_len, {"Item Length", "tcpcl.v4.xferext.len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
387
    {&hf_tcpclv4_xferext_data, {"Type-Specific Data", "tcpcl.v4.xferext.data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
388
389
    // SESS_INIT fields
390
    {&hf_tcpclv4_sess_init_keepalive, {"Keepalive Interval", "tcpcl.v4.sess_init.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}},
391
    {&hf_tcpclv4_sess_init_seg_mru, {"Segment MRU", "tcpcl.v4.sess_init.seg_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
392
    {&hf_tcpclv4_sess_init_xfer_mru, {"Transfer MRU", "tcpcl.v4.sess_init.xfer_mru", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
393
    {&hf_tcpclv4_sess_init_nodeid_len, {"Node ID Length", "tcpcl.v4.sess_init.nodeid_len", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
394
    {&hf_tcpclv4_sess_init_nodeid_data, {"Node ID Data (UTF8)", "tcpcl.v4.sess_init.nodeid_data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
395
    {&hf_tcpclv4_sess_init_extlist_len, {"Extension Items Length", "tcpcl.v4.sess_init.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
396
    {&hf_tcpclv4_sess_init_related, {"Related SESS_INIT", "tcpcl.v4.sess_init.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
397
    // Session negotiation results
398
    {&hf_tcpclv4_negotiate_keepalive, {"Negotiated Keepalive Interval", "tcpcl.v4.negotiated.keepalive", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_seconds), 0x0, NULL, HFILL}},
399
    // SESS_TERM fields
400
    {&hf_tcpclv4_sess_term_flags, {"Flags", "tcpcl.v4.sess_term.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
401
    {&hf_tcpclv4_sess_term_flags_reply, {"REPLY", "tcpcl.v4.sess_term.flags.reply", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_SESS_TERM_FLAG_REPLY, NULL, HFILL}},
402
    {&hf_tcpclv4_sess_term_reason, {"Reason", "tcpcl.v4.ses_term.reason", FT_UINT8, BASE_DEC, VALS(v4_sess_term_reason_vals), 0x0, NULL, HFILL}},
403
    {&hf_tcpclv4_sess_term_related, {"Related SESS_TERM", "tcpcl.v4.ses_term.related", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
404
405
    // Common transfer fields
406
    {&hf_tcpclv4_xfer_flags, {"Transfer Flags", "tcpcl.v4.xfer_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
407
    {&hf_tcpclv4_xfer_flags_start, {"START", "tcpcl.v4.xfer_flags.start", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_TRANSFER_FLAG_START, NULL, HFILL}},
408
    {&hf_tcpclv4_xfer_flags_end, {"END", "tcpcl.v4.xfer_flags.end", FT_BOOLEAN, 8, TFS(&tfs_set_notset), TCPCLV4_TRANSFER_FLAG_END, NULL, HFILL}},
409
    {&hf_tcpclv4_xfer_id, {"Transfer ID", "tcpcl.v4.xfer_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
410
    {&hf_tcpclv4_xfer_total_len, {"Expected Total Length", "tcpcl.v4.xfer.total_len", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
411
    // XFER_SEGMENT fields
412
    {&hf_tcpclv4_xfer_segment_extlist_len, {"Extension Items Length", "tcpcl.v4.xfer_segment.extlist_len", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
413
    {&hf_tcpclv4_xfer_segment_data_len, {"Segment Length", "tcpcl.v4.xfer_segment.data_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
414
    {&hf_tcpclv4_xfer_segment_data, {"Segment Data", "tcpcl.v4.xfer_segment.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
415
    {&hf_tcpclv4_xfer_segment_seen_len, {"Seen Length", "tcpcl.v4.xfer_segment.seen_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
416
    {&hf_tcpclv4_xfer_segment_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_segment.related_start", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
417
    {&hf_tcpclv4_xfer_segment_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_segment.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
418
    {&hf_tcpclv4_xfer_segment_related_ack, {"Related XFER_ACK", "tcpcl.v4.xfer_segment.related_ack", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
419
    {&hf_tcpclv4_xfer_segment_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_segment.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
420
    // XFER_ACK fields
421
    {&hf_tcpclv4_xfer_ack_ack_len, {"Acknowledged Length", "tcpcl.v4.xfer_ack.ack_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
422
    {&hf_tcpclv4_xfer_ack_related_start, {"Related XFER_SEGMENT start", "tcpcl.v4.xfer_ack.related_start", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
423
    {&hf_tcpclv4_xfer_ack_time_start, {"Time since transfer Start", "tcpcl.v4.xfer_ack.time_since_start", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
424
    {&hf_tcpclv4_xfer_ack_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_ack.related_seg", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0, NULL, HFILL}},
425
    {&hf_tcpclv4_xfer_ack_time_diff, {"Acknowledgment Time", "tcpcl.v4.xfer_ack.time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
426
    // XFER_REFUSE fields
427
    {&hf_tcpclv4_xfer_refuse_reason, {"Reason", "tcpcl.v4.xfer_refuse.reason", FT_UINT8, BASE_DEC, VALS(v4_xfer_refuse_reason_vals), 0x0, NULL, HFILL}},
428
    {&hf_tcpclv4_xfer_refuse_related_seg, {"Related XFER_SEGMENT", "tcpcl.v4.xfer_refuse.related_seg", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
429
    // MSG_REJECT fields
430
    {&hf_tcpclv4_msg_reject_reason, {"Reason", "tcpcl.v4.msg_reject.reason", FT_UINT8, BASE_DEC, VALS(v4_msg_reject_reason_vals), 0x0, NULL, HFILL}},
431
    {&hf_tcpclv4_msg_reject_head, {"Rejected Type", "tcpcl.v4.msg_reject.head", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
432
433
    // Specific extensions
434
    {&hf_tcpclv4_xferext_transferlen_total_len, {"Total Length", "tcpcl.v4.xferext.transfer_length.total_len", FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_octet_octets), 0x0, NULL, HFILL}},
435
    // PKIX other name form
436
    {&hf_othername_bundleeid, {"BundleEID", "tcpcl.v4.BundleEID", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
437
438
    {&hf_xfer_segments,
439
        {"TCPCL transfer segments", "tcpcl.xfer.fragments",
440
        FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
441
    {&hf_xfer_segment,
442
        {"TCPCL transfer segment", "tcpcl.xfer.fragment",
443
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
444
    {&hf_xfer_segment_overlap,
445
        {"Transfer segment overlap", "tcpcl.xfer.fragment.overlap",
446
        FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
447
    {&hf_xfer_segment_overlap_conflicts,
448
        {"Transfer segment overlapping with conflicting data",
449
        "tcpcl.xfer.fragment.overlap.conflicts",
450
        FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
451
    {&hf_xfer_segment_multiple_tails,
452
        {"Message has multiple tail segments",
453
        "tcpcl.xfer.fragment.multiple_tails",
454
        FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
455
    {&hf_xfer_segment_too_long_fragment,
456
        {"Transfer segment too long", "tcpcl.xfer.fragment.too_long_fragment",
457
        FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
458
    {&hf_xfer_segment_error,
459
        {"Transfer desegmentation error", "tcpcl.xfer.fragment.error",
460
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
461
    {&hf_xfer_segment_count,
462
        {"Transfer segment count", "tcpcl.xfer.fragment.count",
463
        FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
464
    {&hf_xfer_reassembled_in,
465
        {"Reassembled in", "tcpcl.xfer.reassembled.in",
466
        FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
467
    {&hf_xfer_reassembled_length,
468
        {"Reassembled length", "tcpcl.xfer.reassembled.length",
469
        FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
470
    {&hf_xfer_reassembled_data,
471
        {"Reassembled data", "tcpcl.xfer.reassembled.data",
472
        FT_BYTES, BASE_NONE, NULL, 0x00, NULL, HFILL } },
473
474
};
475
476
static int *const v3_chdr_flags[] = {
477
    &hf_tcpclv3_chdr_flags_ack_req,
478
    &hf_tcpclv3_chdr_flags_frag_enable,
479
    &hf_tcpclv3_chdr_flags_nak,
480
    NULL
481
};
482
483
static int *const v3_data_procflags[] = {
484
    &hf_tcpclv3_data_procflags_start,
485
    &hf_tcpclv3_data_procflags_end,
486
    NULL
487
};
488
static int *const v4_chdr_flags[] = {
489
    &hf_tcpclv4_chdr_flags_cantls,
490
    NULL
491
};
492
static int *const v4_sess_term_flags[] = {
493
    &hf_tcpclv4_sess_term_flags_reply,
494
    NULL
495
};
496
static int *const v4_xfer_flags[] = {
497
    &hf_tcpclv4_xfer_flags_start,
498
    &hf_tcpclv4_xfer_flags_end,
499
    NULL
500
};
501
static int *const v4_sessext_flags[] = {
502
    &hf_tcpclv4_sessext_flags_crit,
503
    NULL
504
};
505
static int *const v4_xferext_flags[] = {
506
    &hf_tcpclv4_xferext_flags_crit,
507
    NULL
508
};
509
510
/* Tree Node Variables */
511
static int ett_proto_tcpcl;
512
static int ett_chdr;
513
static int ett_tcpclv3_chdr_flags;
514
static int ett_tcpclv3_mhdr;
515
static int ett_tcpclv3_data_procflags;
516
static int ett_tcpclv3_shutdown_flags;
517
static int ett_xfer_segment;
518
static int ett_xfer_segments;
519
static int ett_tcpclv4_chdr_flags;
520
static int ett_tcpclv4_mhdr;
521
static int ett_tcpclv4_sess_term_flags;
522
static int ett_tcpclv4_xfer_flags;
523
static int ett_tcpclv4_sessext;
524
static int ett_tcpclv4_sessext_flags;
525
static int ett_tcpclv4_sessext_data;
526
static int ett_tcpclv4_xferext;
527
static int ett_tcpclv4_xferext_flags;
528
static int ett_tcpclv4_xferext_data;
529
530
static int *ett[] = {
531
    &ett_proto_tcpcl,
532
    &ett_chdr,
533
    &ett_tcpclv3_chdr_flags,
534
    &ett_tcpclv3_mhdr,
535
    &ett_tcpclv3_data_procflags,
536
    &ett_tcpclv3_shutdown_flags,
537
    &ett_tcpclv4_chdr_flags,
538
    &ett_tcpclv4_mhdr,
539
    &ett_tcpclv4_sess_term_flags,
540
    &ett_tcpclv4_xfer_flags,
541
    &ett_tcpclv4_sessext,
542
    &ett_tcpclv4_sessext_flags,
543
    &ett_tcpclv4_sessext_data,
544
    &ett_tcpclv4_xferext,
545
    &ett_tcpclv4_xferext_flags,
546
    &ett_tcpclv4_xferext_data,
547
    &ett_xfer_segment,
548
    &ett_xfer_segments,
549
};
550
551
static expert_field ei_invalid_magic;
552
static expert_field ei_invalid_version;
553
static expert_field ei_mismatch_version;
554
static expert_field ei_chdr_duplicate;
555
static expert_field ei_length_clamped;
556
static expert_field ei_chdr_missing;
557
558
static expert_field ei_tcpclv3_invalid_msg_type;
559
static expert_field ei_tcpclv3_data_flags;
560
561
static expert_field ei_tcpclv4_invalid_msg_type;
562
static expert_field ei_tcpclv4_invalid_sessext_type;
563
static expert_field ei_tcpclv4_invalid_xferext_type;
564
static expert_field ei_tcpclv4_extitem_critical;
565
static expert_field ei_tcpclv4_sess_init_missing;
566
static expert_field ei_tcpclv4_sess_init_duplicate;
567
static expert_field ei_tcpclv4_sess_term_duplicate;
568
static expert_field ei_tcpclv4_sess_term_reply_flag;
569
static expert_field ei_tcpclv4_xfer_seg_over_seg_mru;
570
static expert_field ei_tcpclv4_xfer_seg_missing_start;
571
static expert_field ei_tcpclv4_xfer_seg_duplicate_start;
572
static expert_field ei_tcpclv4_xfer_seg_missing_end;
573
static expert_field ei_tcpclv4_xfer_seg_duplicate_end;
574
static expert_field ei_tcpclv4_xfer_seg_no_relation;
575
static expert_field ei_xfer_seg_over_total_len;
576
static expert_field ei_xfer_mismatch_total_len;
577
static expert_field ei_xfer_ack_mismatch_flags;
578
static expert_field ei_xfer_ack_no_relation;
579
static expert_field ei_tcpclv4_xfer_refuse_no_transfer;
580
static expert_field ei_tcpclv4_xferload_over_xfer_mru;
581
582
static ei_register_info ei_tcpcl[] = {
583
    {&ei_invalid_magic, { "tcpcl.invalid_contact_magic", PI_PROTOCOL, PI_ERROR, "Magic string is invalid", EXPFILL}},
584
    {&ei_invalid_version, { "tcpcl.invalid_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version not handled", EXPFILL}},
585
    {&ei_mismatch_version, { "tcpcl.mismatch_contact_version", PI_PROTOCOL, PI_ERROR, "Protocol version mismatch", EXPFILL}},
586
    {&ei_chdr_duplicate, { "tcpcl.contact_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate Contact Header", EXPFILL}},
587
    {&ei_length_clamped, { "tcpcl.length_clamped", PI_UNDECODED, PI_ERROR, "Length too large for Wireshark to handle", EXPFILL}},
588
    {&ei_chdr_missing, { "tcpcl.contact_missing", PI_ASSUMPTION, PI_NOTE, "Contact Header is missing, TCPCL version is implied", EXPFILL}},
589
590
    {&ei_tcpclv3_invalid_msg_type, { "tcpcl.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}},
591
    {&ei_tcpclv3_data_flags, { "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }},
592
593
    {&ei_tcpclv4_invalid_msg_type, { "tcpcl.v4.unknown_message_type", PI_UNDECODED, PI_ERROR, "Message type is unknown", EXPFILL}},
594
    {&ei_tcpclv4_invalid_sessext_type, { "tcpcl.v4.unknown_sessext_type", PI_UNDECODED, PI_WARN, "Session Extension type is unknown", EXPFILL}},
595
    {&ei_tcpclv4_invalid_xferext_type, { "tcpcl.v4.unknown_xferext_type", PI_UNDECODED, PI_WARN, "Transfer Extension type is unknown", EXPFILL}},
596
    {&ei_tcpclv4_extitem_critical, { "tcpcl.v4.extitem_critical", PI_REQUEST_CODE, PI_CHAT, "Extension Item is critical", EXPFILL}},
597
    {&ei_tcpclv4_sess_init_missing, { "tcpcl.v4.sess_init_missing", PI_SEQUENCE, PI_ERROR, "Expected SESS_INIT message first", EXPFILL}},
598
    {&ei_tcpclv4_sess_init_duplicate, { "tcpcl.v4.sess_init_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate SESS_INIT message", EXPFILL}},
599
    {&ei_tcpclv4_sess_term_duplicate, { "tcpcl.v4.sess_term_duplicate", PI_SEQUENCE, PI_ERROR, "Duplicate SESS_TERM message", EXPFILL}},
600
    {&ei_tcpclv4_sess_term_reply_flag, { "tcpcl.v4.sess_term_reply_flag", PI_SEQUENCE, PI_ERROR, "Reply SESS_TERM missing flag", EXPFILL}},
601
    {&ei_tcpclv4_xfer_seg_over_seg_mru, { "tcpcl.v4.xfer_seg_over_seg_mru", PI_PROTOCOL, PI_WARN, "Segment data size larger than peer MRU", EXPFILL}},
602
    {&ei_tcpclv4_xfer_seg_missing_start, { "tcpcl.v4.xfer_seg_missing_start", PI_SEQUENCE, PI_ERROR, "First XFER_SEGMENT is missing START flag", EXPFILL}},
603
    {&ei_tcpclv4_xfer_seg_duplicate_start, { "tcpcl.v4.xfer_seg_duplicate_start", PI_SEQUENCE, PI_ERROR, "Non-first XFER_SEGMENT has START flag", EXPFILL}},
604
    {&ei_tcpclv4_xfer_seg_missing_end, { "tcpcl.v4.xfer_seg_missing_end", PI_SEQUENCE, PI_ERROR, "Last XFER_SEGMENT is missing END flag", EXPFILL}},
605
    {&ei_tcpclv4_xfer_seg_duplicate_end, { "tcpcl.v4.xfer_seg_duplicate_end", PI_SEQUENCE, PI_ERROR, "Non-last XFER_SEGMENT has END flag", EXPFILL}},
606
    {&ei_tcpclv4_xfer_seg_no_relation, { "tcpcl.v4.xfer_seg_no_relation", PI_SEQUENCE, PI_NOTE, "XFER_SEGMENT has no related XFER_ACK", EXPFILL}},
607
    {&ei_tcpclv4_xfer_refuse_no_transfer, { "tcpcl.v4.xfer_refuse_no_transfer", PI_SEQUENCE, PI_NOTE, "XFER_REFUSE has no related XFER_SEGMENT(s)", EXPFILL}},
608
    {&ei_tcpclv4_xferload_over_xfer_mru, { "tcpcl.v4.xferload_over_xfer_mru", PI_SEQUENCE, PI_NOTE, "Transfer larger than peer MRU", EXPFILL}},
609
    {&ei_xfer_seg_over_total_len, { "tcpcl.xfer_seg_over_total_len", PI_SEQUENCE, PI_ERROR, "XFER_SEGMENT has accumulated length beyond the Transfer Length extension", EXPFILL}},
610
    {&ei_xfer_mismatch_total_len, { "tcpcl.xfer_mismatch_total_len", PI_SEQUENCE, PI_ERROR, "Transfer has total length different than the Transfer Length extension", EXPFILL}},
611
    {&ei_xfer_ack_mismatch_flags, { "tcpcl.xfer_ack_mismatch_flags", PI_SEQUENCE, PI_ERROR, "XFER_ACK does not have flags matching XFER_SEGMENT", EXPFILL}},
612
    {&ei_xfer_ack_no_relation, { "tcpcl.xfer_ack_no_relation", PI_SEQUENCE, PI_NOTE, "XFER_ACK has no related XFER_SEGMENT", EXPFILL}},
613
};
614
615
static const fragment_items xfer_frag_items = {
616
    /*Fragment subtrees*/
617
    &ett_xfer_segment,
618
    &ett_xfer_segments,
619
    /*Fragment Fields*/
620
    &hf_xfer_segments,
621
    &hf_xfer_segment,
622
    &hf_xfer_segment_overlap,
623
    &hf_xfer_segment_overlap_conflicts,
624
    &hf_xfer_segment_multiple_tails,
625
    &hf_xfer_segment_too_long_fragment,
626
    &hf_xfer_segment_error,
627
    &hf_xfer_segment_count,
628
    /*Reassembled in field*/
629
    &hf_xfer_reassembled_in,
630
    /*Reassembled length field*/
631
    &hf_xfer_reassembled_length,
632
    /* Reassembled data field */
633
    &hf_xfer_reassembled_data,
634
    /*Tag*/
635
    "Transfer segments"
636
};
637
638
2.10k
static unsigned tvb_get_sdnv(tvbuff_t *tvb, unsigned offset, uint64_t *value) {
639
2.10k
    return tvb_get_varint(tvb, offset, FT_VARINT_MAX_LEN, value, ENC_VARINT_SDNV);
640
2.10k
}
641
642
8.49k
static void tcpcl_frame_loc_init(tcpcl_frame_loc_t *loc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
643
8.49k
    loc->frame_num = pinfo->num;
644
645
8.49k
    loc->ds_idx = get_data_source_index_by_tvb(pinfo, tvb_get_ds_tvb(tvb));
646
8.49k
    DISSECTOR_ASSERT(loc->ds_idx >= 0);
647
8.49k
    loc->raw_offset = tvb_raw_offset(tvb) + offset;
648
8.49k
    DISSECTOR_ASSERT(offset >= 0);
649
8.49k
}
650
651
/** Construct a new object on the file allocator.
652
 */
653
8.49k
static tcpcl_frame_loc_t * tcpcl_frame_loc_new(wmem_allocator_t *alloc, const packet_info *pinfo, tvbuff_t *tvb, const int offset) {
654
8.49k
    tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
655
8.49k
    tcpcl_frame_loc_init(obj, pinfo, tvb, offset);
656
8.49k
    return obj;
657
8.49k
}
658
659
/** Construct a new object on the file allocator.
660
 */
661
1.53k
static tcpcl_frame_loc_t * tcpcl_frame_loc_clone(wmem_allocator_t *alloc, const tcpcl_frame_loc_t *loc) {
662
1.53k
    tcpcl_frame_loc_t *obj = wmem_new(alloc, tcpcl_frame_loc_t);
663
1.53k
    *obj = *loc;
664
1.53k
    return obj;
665
1.53k
}
666
667
#define tcpcl_frame_loc_free wmem_free
668
669
/** Function to match the GCompareDataFunc signature.
670
 */
671
620
static int tcpcl_frame_loc_compare(const void *a, const void *b, void *user_data _U_) {
672
620
    const tcpcl_frame_loc_t *aloc = a;
673
620
    const tcpcl_frame_loc_t *bloc = b;
674
675
620
    if (aloc->frame_num < bloc->frame_num) {
676
352
        return -1;
677
352
    }
678
268
    else if (aloc->frame_num > bloc->frame_num) {
679
0
        return 1;
680
0
    }
681
682
268
    if (aloc->ds_idx < bloc->ds_idx) {
683
0
        return -1;
684
0
    }
685
268
    else if (aloc->ds_idx > bloc->ds_idx) {
686
0
        return 1;
687
0
    }
688
268
    if (aloc->raw_offset < bloc->raw_offset) {
689
268
        return -1;
690
268
    }
691
0
    else if (aloc->raw_offset > bloc->raw_offset) {
692
0
        return 1;
693
0
    }
694
0
    return 0;
695
268
}
696
697
/** Function to match the GCompareFunc signature.
698
 */
699
93
static gboolean tcpcl_frame_loc_equal(const void *a, const void *b) {
700
93
    const tcpcl_frame_loc_t *aobj = a;
701
93
    const tcpcl_frame_loc_t *bobj = b;
702
93
    return (
703
93
        (aobj->frame_num == bobj->frame_num)
704
6
        && (aobj->ds_idx == bobj->ds_idx)
705
6
        && (aobj->raw_offset == bobj->raw_offset)
706
93
    );
707
93
}
708
709
/** Function to match the GHashFunc signature.
710
 */
711
4.13k
static unsigned tcpcl_frame_loc_hash(const void *key) {
712
4.13k
    const tcpcl_frame_loc_t *obj = key;
713
4.13k
    return (
714
4.13k
        g_int_hash(&(obj->frame_num))
715
4.13k
        ^ g_int_hash(&(obj->ds_idx))
716
4.13k
        ^ g_int_hash(&(obj->raw_offset))
717
4.13k
    );
718
4.13k
}
719
720
struct tcpcl_ack_meta;
721
typedef struct tcpcl_ack_meta tcpcl_ack_meta_t;
722
struct tcpcl_seg_meta;
723
typedef struct tcpcl_seg_meta tcpcl_seg_meta_t;
724
725
struct tcpcl_seg_meta {
726
    /// Location associated with this metadata
727
    tcpcl_frame_loc_t frame_loc;
728
    /// Timestamp on the frame (end time if reassembled)
729
    nstime_t frame_time;
730
    /// Copy of message flags
731
    uint8_t flags;
732
    /// Total transfer length including this segment
733
    uint64_t seen_len;
734
735
    /// Potential related start segment
736
    tcpcl_seg_meta_t *related_start;
737
    /// Potential related XFER_ACK
738
    tcpcl_ack_meta_t *related_ack;
739
};
740
741
474
static tcpcl_seg_meta_t * tcpcl_seg_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
742
474
    tcpcl_seg_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_seg_meta_t);
743
474
    obj->frame_loc = *loc;
744
474
    obj->frame_time = pinfo->abs_ts;
745
474
    obj->flags = 0;
746
474
    obj->seen_len = 0;
747
474
    obj->related_start = NULL;
748
474
    obj->related_ack = NULL;
749
474
    return obj;
750
474
}
751
752
0
static void tcpcl_seg_meta_free(tcpcl_seg_meta_t *obj) {
753
0
    wmem_free(wmem_file_scope(), obj);
754
0
}
755
756
/** Function to match the GCompareFunc signature.
757
 */
758
257
static int tcpcl_seg_meta_compare_loc(const void *a, const void *b) {
759
257
    return tcpcl_frame_loc_compare(
760
257
        &(((tcpcl_seg_meta_t *)a)->frame_loc),
761
257
        &(((tcpcl_seg_meta_t *)b)->frame_loc),
762
257
        NULL
763
257
    );
764
257
}
765
766
struct tcpcl_ack_meta {
767
    /// Location associated with this metadata
768
    tcpcl_frame_loc_t frame_loc;
769
    /// Timestamp on the frame (end time if reassembled)
770
    nstime_t frame_time;
771
    /// Copy of message flags
772
    uint8_t flags;
773
    /// Total acknowledged length including this ack
774
    uint64_t seen_len;
775
776
    /// Potential related start segment
777
    tcpcl_seg_meta_t *related_start;
778
    /// Potential related XFER_SEGMENT
779
    tcpcl_seg_meta_t *related_seg;
780
};
781
782
1.09k
static tcpcl_ack_meta_t * tcpcl_ack_meta_new(const packet_info *pinfo, const tcpcl_frame_loc_t *loc) {
783
1.09k
    tcpcl_ack_meta_t *obj = wmem_new(wmem_file_scope(), tcpcl_ack_meta_t);
784
1.09k
    obj->frame_loc = *loc;
785
1.09k
    obj->frame_time = pinfo->abs_ts;
786
1.09k
    obj->flags = 0;
787
1.09k
    obj->seen_len = 0;
788
1.09k
    obj->related_start = NULL;
789
1.09k
    obj->related_seg = NULL;
790
1.09k
    return obj;
791
1.09k
}
792
793
0
static void tcpcl_ack_meta_free(tcpcl_ack_meta_t *obj) {
794
0
    wmem_free(wmem_file_scope(), obj);
795
0
}
796
797
/** Function to match the GCompareFunc signature.
798
 */
799
363
static int tcpcl_ack_meta_compare_loc(const void *a, const void *b) {
800
363
    return tcpcl_frame_loc_compare(
801
363
        &(((tcpcl_seg_meta_t *)a)->frame_loc),
802
363
        &(((tcpcl_seg_meta_t *)b)->frame_loc),
803
363
        NULL
804
363
    );
805
363
}
806
807
1.41k
static tcpcl_transfer_t * tcpcl_transfer_new(void) {
808
1.41k
    tcpcl_transfer_t *obj = wmem_new(wmem_file_scope(), tcpcl_transfer_t);
809
1.41k
    obj->seg_list = wmem_list_new(wmem_file_scope());
810
1.41k
    obj->ack_list = wmem_list_new(wmem_file_scope());
811
1.41k
    obj->total_length = NULL;
812
1.41k
    return obj;
813
1.41k
}
814
815
1.70k
static tcpcl_transfer_t * get_or_create_transfer_t(wmem_map_t *table, const uint64_t xfer_id) {
816
1.70k
    tcpcl_transfer_t *xfer = wmem_map_lookup(table, &xfer_id);
817
1.70k
    if (!xfer) {
818
1.41k
        uint64_t *key = wmem_new(wmem_file_scope(), uint64_t);
819
1.41k
        *key = xfer_id;
820
1.41k
        xfer = tcpcl_transfer_new();
821
1.41k
        wmem_map_insert(table, key, xfer);
822
1.41k
    }
823
1.70k
    return xfer;
824
1.70k
}
825
826
450
static tcpcl_peer_t * tcpcl_peer_new(void) {
827
450
    tcpcl_peer_t *obj = wmem_new0(wmem_file_scope(), tcpcl_peer_t);
828
450
    clear_address(&(obj->addr));
829
450
    obj->frame_loc_to_transfer = wmem_map_new(wmem_file_scope(), tcpcl_frame_loc_hash, tcpcl_frame_loc_equal);
830
450
    obj->transfers = wmem_map_new(wmem_file_scope(), g_int64_hash, g_int64_equal);
831
450
    return obj;
832
450
}
833
834
1.52k
static void tcpcl_peer_associate_transfer(tcpcl_peer_t *peer, const tcpcl_frame_loc_t *loc, const uint64_t xfer_id) {
835
1.52k
    void * *xfer = wmem_map_lookup(peer->frame_loc_to_transfer, loc);
836
1.52k
    if (!xfer) {
837
1.52k
        tcpcl_frame_loc_t *key = tcpcl_frame_loc_clone(wmem_file_scope(), loc);
838
1.52k
        uint64_t *val = wmem_new(wmem_file_scope(), uint64_t);
839
1.52k
        *val = xfer_id;
840
1.52k
        wmem_map_insert(peer->frame_loc_to_transfer, key, val);
841
1.52k
    }
842
1.52k
}
843
844
225
static tcpcl_conversation_t * tcpcl_conversation_new(void) {
845
225
    tcpcl_conversation_t *obj = wmem_new0(wmem_file_scope(), tcpcl_conversation_t);
846
225
    obj->active = tcpcl_peer_new();
847
225
    obj->passive = tcpcl_peer_new();
848
225
    return obj;
849
225
}
850
851
8.49k
tcpcl_dissect_ctx_t * tcpcl_dissect_ctx_get(tvbuff_t *tvb, packet_info *pinfo, const int offset) {
852
8.49k
    conversation_t *convo = find_or_create_conversation(pinfo);
853
8.49k
    tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
854
8.49k
    if (!tcpcl_convo) {
855
0
        return NULL;
856
0
    }
857
858
8.49k
    tcpcl_dissect_ctx_t *ctx = wmem_new0(pinfo->pool, tcpcl_dissect_ctx_t);
859
8.49k
    ctx->convo = tcpcl_convo;
860
8.49k
    ctx->cur_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, tvb, offset);
861
862
8.49k
    const bool src_is_active = (
863
8.49k
        addresses_equal(&(ctx->convo->active->addr), &(pinfo->src))
864
8.49k
        && (ctx->convo->active->port == pinfo->srcport)
865
8.49k
    );
866
8.49k
    if (src_is_active) {
867
8.49k
        ctx->tx_peer = ctx->convo->active;
868
8.49k
        ctx->rx_peer = ctx->convo->passive;
869
8.49k
    }
870
0
    else {
871
0
        ctx->tx_peer = ctx->convo->passive;
872
0
        ctx->rx_peer = ctx->convo->active;
873
0
    }
874
875
8.49k
    ctx->is_contact = (
876
8.49k
        !(ctx->tx_peer->chdr_missing)
877
248
        && (
878
248
            !(ctx->tx_peer->chdr_seen)
879
7
            || tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)
880
248
        )
881
8.49k
    );
882
883
8.49k
    return ctx;
884
8.49k
}
885
886
211
static void set_chdr_missing(tcpcl_peer_t *peer, uint8_t version) {
887
211
    peer->chdr_missing = true;
888
211
    peer->version = version;
889
    // assumed parameters
890
211
    peer->segment_mru = UINT64_MAX;
891
211
    peer->transfer_mru = UINT64_MAX;
892
211
}
893
894
895
288
static void try_negotiate(tcpcl_dissect_ctx_t *ctx, packet_info *pinfo) {
896
288
    if (!(ctx->convo->contact_negotiated)
897
288
        && (ctx->convo->active->chdr_seen)
898
4
        && (ctx->convo->passive->chdr_seen)) {
899
0
        ctx->convo->session_use_tls = (
900
0
            ctx->convo->active->can_tls & ctx->convo->passive->can_tls
901
0
        );
902
0
        ctx->convo->contact_negotiated = true;
903
904
0
        if (ctx->convo->session_use_tls
905
0
            && (!(ctx->convo->session_tls_start))) {
906
0
            col_append_str(pinfo->cinfo, COL_INFO, " [STARTTLS]");
907
0
            ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
908
0
            ssl_starttls_ack(tls_handle, pinfo, tcpcl_handle);
909
0
        }
910
0
    }
911
912
288
    if (!(ctx->convo->sess_negotiated)
913
288
        && (ctx->convo->active->sess_init_seen)
914
31
        && (ctx->convo->passive->sess_init_seen)) {
915
0
        ctx->convo->sess_keepalive = MIN(
916
0
            ctx->convo->active->keepalive,
917
0
            ctx->convo->passive->keepalive
918
0
        );
919
0
        ctx->convo->sess_negotiated = true;
920
921
0
    }
922
288
}
923
924
typedef struct {
925
    // key type for addresses_ports_reassembly_table_functions
926
    void *addr_port;
927
    // TCPCL ID
928
    uint64_t xfer_id;
929
} tcpcl_fragment_key_t;
930
931
700
static unsigned fragment_key_hash(const void *ptr) {
932
700
    const tcpcl_fragment_key_t *obj = (const tcpcl_fragment_key_t *)ptr;
933
700
    return (
934
700
        addresses_ports_reassembly_table_functions.hash_func(obj->addr_port)
935
700
        ^ g_int64_hash(&(obj->xfer_id))
936
700
    );
937
700
}
938
939
5.10k
static gboolean fragment_key_equal(const void *ptrA, const void *ptrB) {
940
5.10k
    const tcpcl_fragment_key_t *objA = (const tcpcl_fragment_key_t *)ptrA;
941
5.10k
    const tcpcl_fragment_key_t *objB = (const tcpcl_fragment_key_t *)ptrB;
942
5.10k
    return (
943
5.10k
        addresses_ports_reassembly_table_functions.equal_func(objA->addr_port, objB->addr_port)
944
258
        && (objA->xfer_id == objB->xfer_id)
945
5.10k
    );
946
5.10k
}
947
948
474
static void *fragment_key_temporary(const packet_info *pinfo, const uint32_t id, const void *data) {
949
474
    tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
950
474
    obj->addr_port = addresses_ports_reassembly_table_functions.temporary_key_func(pinfo, id, NULL);
951
474
    obj->xfer_id = *((const uint64_t *)data);
952
474
    return (void *)obj;
953
474
}
954
955
168
static void *fragment_key_persistent(const packet_info *pinfo, const uint32_t id, const void *data) {
956
168
    tcpcl_fragment_key_t *obj = g_slice_new(tcpcl_fragment_key_t);
957
168
    obj->addr_port = addresses_ports_reassembly_table_functions.persistent_key_func(pinfo, id, NULL);
958
168
    obj->xfer_id = *((const uint64_t *)data);
959
168
    return (void *)obj;
960
168
}
961
962
474
static void fragment_key_free_temporary(void *ptr) {
963
474
    tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
964
474
    if (obj) {
965
474
        addresses_ports_reassembly_table_functions.free_temporary_key_func(obj->addr_port);
966
474
        g_slice_free(tcpcl_fragment_key_t, obj);
967
474
    }
968
474
}
969
970
58
static void fragment_key_free_persistent(void *ptr) {
971
58
    tcpcl_fragment_key_t *obj = (tcpcl_fragment_key_t *)ptr;
972
58
    if (obj) {
973
58
        addresses_ports_reassembly_table_functions.free_persistent_key_func(obj->addr_port);
974
58
        g_slice_free(tcpcl_fragment_key_t, obj);
975
58
    }
976
58
}
977
978
static reassembly_table_functions xfer_reassembly_table_functions = {
979
    fragment_key_hash,
980
    fragment_key_equal,
981
    fragment_key_temporary,
982
    fragment_key_persistent,
983
    fragment_key_free_temporary,
984
    fragment_key_free_persistent
985
};
986
987
/** Record metadata about one segment in a transfer.
988
 */
989
static void transfer_add_segment(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
990
                                 uint64_t data_len,
991
                                 packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
992
474
                                 proto_item *item_msg, proto_item *item_flags) {
993
474
    tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, xfer_id);
994
995
474
    uint8_t flag_start, flag_end;
996
474
    if (ctx->tx_peer->version == 3) {
997
473
        flag_start = TCPCLV3_DATA_START_FLAG;
998
473
        flag_end = TCPCLV3_DATA_END_FLAG;
999
473
    }
1000
1
    else {
1001
1
        flag_start = TCPCLV4_TRANSFER_FLAG_START;
1002
1
        flag_end = TCPCLV4_TRANSFER_FLAG_END;
1003
1
    }
1004
1005
    // Add or get the segment metadata
1006
474
    tcpcl_seg_meta_t *seg_meta = tcpcl_seg_meta_new(pinfo, ctx->cur_loc);
1007
474
    wmem_list_frame_t *frm = wmem_list_find_custom(xfer->seg_list, seg_meta, tcpcl_seg_meta_compare_loc);
1008
474
    if (frm) {
1009
0
        tcpcl_seg_meta_free(seg_meta);
1010
0
        seg_meta = wmem_list_frame_data(frm);
1011
0
    }
1012
474
    else {
1013
474
        wmem_list_append(xfer->seg_list, seg_meta);
1014
474
        frm = wmem_list_tail(xfer->seg_list);
1015
        // Set for new item
1016
474
        seg_meta->flags = flags;
1017
474
    }
1018
1019
    // mark start-of-transfer
1020
474
    if (!(seg_meta->related_start)) {
1021
474
        wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1022
474
        tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1023
474
        if (seg_front && (seg_front->flags & flag_start)) {
1024
245
            seg_meta->related_start = seg_front;
1025
245
        }
1026
474
    }
1027
1028
    // accumulate segment sizes
1029
474
    uint64_t prev_seen_len;
1030
474
    wmem_list_frame_t *frm_prev = wmem_list_frame_prev(frm);
1031
474
    if (!frm_prev) {
1032
353
        if (!(flags & flag_start)) {
1033
229
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_start);
1034
229
        }
1035
353
        prev_seen_len = 0;
1036
353
    }
1037
121
    else {
1038
121
        const tcpcl_seg_meta_t *seg_prev = wmem_list_frame_data(frm_prev);
1039
121
        if (flags & flag_start) {
1040
0
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_start);
1041
0
        }
1042
121
        prev_seen_len = seg_prev->seen_len;
1043
121
    }
1044
474
    wmem_list_frame_t *frm_next = wmem_list_frame_next(frm);
1045
474
    if (!frm_next) {
1046
474
        if (!(flags & flag_end)) {
1047
205
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_missing_end);
1048
205
        }
1049
474
    }
1050
0
    else {
1051
0
        if (flags & flag_end) {
1052
0
            expert_add_info(pinfo, item_flags, &ei_tcpclv4_xfer_seg_duplicate_end);
1053
0
        }
1054
0
    }
1055
474
    seg_meta->seen_len = prev_seen_len + data_len;
1056
1057
474
    proto_item *item_seen = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_seen_len, tvb, 0, 0, seg_meta->seen_len);
1058
474
    proto_item_set_generated(item_seen);
1059
474
    if (seg_meta->seen_len > ctx->rx_peer->transfer_mru) {
1060
457
        expert_add_info(pinfo, item_seen, &ei_tcpclv4_xferload_over_xfer_mru);
1061
457
    }
1062
474
    if (xfer->total_length) {
1063
0
        if (seg_meta->seen_len > *(xfer->total_length)) {
1064
0
            expert_add_info(pinfo, item_seen, &ei_xfer_seg_over_total_len);
1065
0
        }
1066
0
        else if ((flags & flag_end)
1067
0
            && (seg_meta->seen_len != *(xfer->total_length))) {
1068
0
            expert_add_info(pinfo, item_seen, &ei_xfer_mismatch_total_len);
1069
0
        }
1070
0
        proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1071
0
        proto_item_set_generated(item_total);
1072
0
    }
1073
1074
474
    if (seg_meta->related_ack) {
1075
0
        proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_related_ack, tvb, 0, 0, seg_meta->related_ack->frame_loc.frame_num);
1076
0
        proto_item_set_generated(item_rel);
1077
1078
0
        nstime_t td;
1079
0
        nstime_delta(&td, &(seg_meta->related_ack->frame_time), &(seg_meta->frame_time));
1080
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_diff, tvb, 0, 0, &td);
1081
0
        proto_item_set_generated(item_td);
1082
1083
0
    }
1084
474
    else {
1085
474
        expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_seg_no_relation);
1086
474
    }
1087
474
    if (seg_meta->related_start && (seg_meta->related_start != seg_meta)) {
1088
121
        proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_related_start, tvb, 0, 0, seg_meta->related_start->frame_loc.frame_num);
1089
121
        proto_item_set_generated(item_rel);
1090
1091
121
        nstime_t td;
1092
121
        nstime_delta(&td, &(seg_meta->frame_time), &(seg_meta->related_start->frame_time));
1093
121
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_segment_time_start, tvb, 0, 0, &td);
1094
121
        proto_item_set_generated(item_td);
1095
121
    }
1096
474
}
1097
1098
static void transfer_add_ack(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id, uint8_t flags,
1099
                             uint64_t ack_len,
1100
                             packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1101
1.09k
                             proto_item *item_msg, proto_item *item_flags) {
1102
1.09k
    tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->rx_peer->transfers, xfer_id);
1103
1104
    // Add or get the ack metadata
1105
1.09k
    tcpcl_ack_meta_t *ack_meta = tcpcl_ack_meta_new(pinfo, ctx->cur_loc);
1106
1.09k
    wmem_list_frame_t *frm = wmem_list_find_custom(xfer->ack_list, ack_meta, tcpcl_ack_meta_compare_loc);
1107
1.09k
    if (frm) {
1108
0
        tcpcl_ack_meta_free(ack_meta);
1109
0
        ack_meta = wmem_list_frame_data(frm);
1110
0
    }
1111
1.09k
    else {
1112
1.09k
        wmem_list_append(xfer->ack_list, ack_meta);
1113
        // Set for new item
1114
1.09k
        ack_meta->flags = flags;
1115
1.09k
        ack_meta->seen_len = ack_len;
1116
1.09k
    }
1117
1118
    // mark start-of-transfer
1119
1.09k
    if (!(ack_meta->related_start)) {
1120
1.09k
        wmem_list_frame_t *frm_front = wmem_list_head(xfer->seg_list);
1121
1.09k
        tcpcl_seg_meta_t *seg_front = frm_front ? wmem_list_frame_data(frm_front) : NULL;
1122
1.09k
        if (seg_front && (seg_front->flags & TCPCLV4_TRANSFER_FLAG_START)) {
1123
0
            ack_meta->related_start = seg_front;
1124
0
        }
1125
1.09k
    }
1126
1127
    // Assemble both of the links here, as ACK will always follow segment
1128
1.09k
    if (!(ack_meta->related_seg)) {
1129
1.09k
        wmem_list_frame_t *seg_iter = wmem_list_head(xfer->seg_list);
1130
1.09k
        for (; seg_iter; seg_iter = wmem_list_frame_next(seg_iter)) {
1131
0
            tcpcl_seg_meta_t *seg_meta = wmem_list_frame_data(seg_iter);
1132
0
            if (seg_meta->seen_len == ack_meta->seen_len) {
1133
0
                seg_meta->related_ack = ack_meta;
1134
0
                ack_meta->related_seg = seg_meta;
1135
0
            }
1136
0
        }
1137
1.09k
    }
1138
1139
1.09k
    if (xfer->total_length) {
1140
0
        proto_item *item_total = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_total_len, tvb, 0, 0, *(xfer->total_length));
1141
0
        proto_item_set_generated(item_total);
1142
0
    }
1143
1.09k
    if (ack_meta->related_seg) {
1144
0
        proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_ack_related_seg, tvb, 0, 0, ack_meta->related_seg->frame_loc.frame_num);
1145
0
        proto_item_set_generated(item_rel);
1146
1147
0
        nstime_t td;
1148
0
        nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_seg->frame_time));
1149
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_diff, tvb, 0, 0, &td);
1150
0
        proto_item_set_generated(item_td);
1151
1152
0
        if (item_flags && (ack_meta->flags != ack_meta->related_seg->flags)) {
1153
0
            expert_add_info(pinfo, item_flags, &ei_xfer_ack_mismatch_flags);
1154
0
        }
1155
0
    }
1156
1.09k
    else {
1157
1.09k
        expert_add_info(pinfo, item_msg, &ei_xfer_ack_no_relation);
1158
1.09k
    }
1159
1.09k
    if (ack_meta->related_start) {
1160
0
        proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_ack_related_start, tvb, 0, 0, ack_meta->related_start->frame_loc.frame_num);
1161
0
        proto_item_set_generated(item_rel);
1162
1163
0
        nstime_t td;
1164
0
        nstime_delta(&td, &(ack_meta->frame_time), &(ack_meta->related_start->frame_time));
1165
0
        proto_item *item_td = proto_tree_add_time(tree_msg, hf_tcpclv4_xfer_ack_time_start, tvb, 0, 0, &td);
1166
0
        proto_item_set_generated(item_td);
1167
0
    }
1168
1.09k
}
1169
1170
static void transfer_add_refuse(tcpcl_dissect_ctx_t *ctx, uint64_t xfer_id,
1171
                                packet_info *pinfo, tvbuff_t *tvb, proto_tree *tree_msg,
1172
35
                                proto_item *item_msg) {
1173
35
    const tcpcl_transfer_t *xfer = wmem_map_lookup(ctx->rx_peer->transfers, &xfer_id);
1174
35
    const tcpcl_seg_meta_t *seg_last = NULL;
1175
35
    if (xfer) {
1176
1
        wmem_list_frame_t *seg_iter = wmem_list_tail(xfer->seg_list);
1177
1
        seg_iter = seg_iter ? wmem_list_frame_prev(seg_iter) : NULL;
1178
1
        seg_last = seg_iter ? wmem_list_frame_data(seg_iter) : NULL;
1179
1
    }
1180
1181
35
    if (seg_last) {
1182
0
        proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_related_seg, tvb, 0, 0, seg_last->frame_loc.frame_num);
1183
0
        proto_item_set_generated(item_rel);
1184
0
    }
1185
35
    else {
1186
35
        expert_add_info(pinfo, item_msg, &ei_tcpclv4_xfer_refuse_no_transfer);
1187
35
    }
1188
35
}
1189
1190
1.03k
static int get_clamped_length(uint64_t orig, packet_info *pinfo, proto_item *item) {
1191
1.03k
    int clamped;
1192
1.03k
    if (orig > INT_MAX) {
1193
10
        clamped = INT_MAX;
1194
10
        if (pinfo && item) {
1195
4
            expert_add_info(pinfo, item, &ei_length_clamped);
1196
4
        }
1197
10
    }
1198
1.02k
    else {
1199
1.02k
        clamped = (int) orig;
1200
1.02k
    }
1201
1.03k
    return clamped;
1202
1.03k
}
1203
1204
static unsigned
1205
get_v3_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1206
               tcpcl_dissect_ctx_t *ctx _U_)
1207
4.01k
{
1208
4.01k
    uint64_t len;
1209
4.01k
    unsigned bytecount;
1210
4.01k
    uint8_t conv_hdr = tvb_get_uint8(tvb, offset);
1211
4.01k
    offset += 1;
1212
4.01k
    unsigned msg_len = 1;
1213
1214
4.01k
    switch (conv_hdr & TCPCLV3_TYPE_MASK)
1215
4.01k
    {
1216
515
    case TCPCLV3_DATA_SEGMENT: {
1217
        /* get length from sdnv */
1218
515
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1219
515
        if (bytecount == 0) {
1220
2
            return 0;
1221
2
        }
1222
513
        const int len_clamp = get_clamped_length(len, NULL, NULL);
1223
513
        msg_len += bytecount + (unsigned)len_clamp;
1224
513
        break;
1225
515
    }
1226
1.01k
    case TCPCLV3_ACK_SEGMENT:
1227
        /* get length from sdnv */
1228
1.01k
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1229
1.01k
        if (bytecount == 0) {
1230
1
            return 0;
1231
1
        }
1232
1.01k
        msg_len += bytecount;
1233
1.01k
        break;
1234
1235
624
    case TCPCLV3_KEEP_ALIVE:
1236
1.17k
    case TCPCLV3_REFUSE_BUNDLE:
1237
        /* always 1 byte */
1238
1.17k
        break;
1239
541
    case TCPCLV3_SHUTDOWN:
1240
541
        if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1241
341
            msg_len += 1;
1242
341
        }
1243
541
        if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1244
219
            msg_len += 2;
1245
219
        }
1246
541
        break;
1247
1248
572
    case TCPCLV3_LENGTH:
1249
        /* get length from sdnv */
1250
572
        bytecount = tvb_get_sdnv(tvb, offset, &len);
1251
572
        if (bytecount == 0) {
1252
3
            return 0;
1253
3
        }
1254
569
        msg_len += bytecount;
1255
569
        break;
1256
1257
197
    default:
1258
        // no known message
1259
197
        return 0;
1260
4.01k
    }
1261
1262
3.80k
    return msg_len;
1263
4.01k
}
1264
1265
static int
1266
dissect_v3_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1267
               tcpcl_dissect_ctx_t *ctx)
1268
3.80k
{
1269
3.80k
    uint8_t        conv_hdr;
1270
3.80k
    const char *msgtype_name;
1271
3.80k
    uint8_t        refuse_bundle_hdr;
1272
3.80k
    int            offset = 0;
1273
3.80k
    unsigned sdnv_length;
1274
3.80k
    uint64_t segment_length;
1275
3.80k
    proto_item    *conv_item, *sub_item;
1276
3.80k
    proto_tree    *conv_tree, *sub_tree;
1277
3.80k
    uint64_t *xfer_id = NULL;
1278
3.80k
    proto_item *item_xfer_id = NULL;
1279
1280
3.80k
    conv_item = proto_tree_add_item(tree, hf_tcpclv3_mhdr, tvb, 0, -1, ENC_NA);
1281
3.80k
    conv_tree = proto_item_add_subtree(conv_item, ett_tcpclv3_mhdr);
1282
1283
3.80k
    conv_hdr = tvb_get_uint8(tvb, offset);
1284
3.80k
    proto_tree_add_item(conv_tree, hf_tcpclv3_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1285
1286
3.80k
    msgtype_name = val_to_str_const((conv_hdr>>4)&0xF, v3_message_type_vals, "Unknown");
1287
3.80k
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1288
3.80k
    proto_item_append_text(proto_tree_get_parent(conv_tree), ": %s", msgtype_name);
1289
1290
3.80k
    switch (conv_hdr & TCPCLV3_TYPE_MASK) {
1291
512
    case TCPCLV3_DATA_SEGMENT: {
1292
512
        proto_item *item_flags;
1293
1294
512
        item_flags = proto_tree_add_bitmask(
1295
512
            conv_tree, tvb,
1296
512
            offset, hf_tcpclv3_data_procflags,
1297
512
            ett_tcpclv3_data_procflags, v3_data_procflags,
1298
512
            ENC_BIG_ENDIAN
1299
512
        );
1300
512
        offset += 1;
1301
1302
        /* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
1303
512
        if ((conv_hdr & ~((uint8_t)TCPCLV3_TYPE_MASK | (uint8_t)TCPCLV3_DATA_FLAGS)) != 0) {
1304
288
            expert_add_info(pinfo, item_flags, &ei_tcpclv3_data_flags);
1305
288
        }
1306
1307
512
        sub_item = proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_data_segment_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
1308
512
        offset += sdnv_length;
1309
512
        const int data_len_clamp = get_clamped_length(segment_length, pinfo, sub_item);
1310
1311
        // implied transfer ID
1312
512
        xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
1313
512
        if (!xfer_id) {
1314
512
            xfer_id = wmem_new(pinfo->pool, uint64_t);
1315
512
            *xfer_id = wmem_map_size(ctx->tx_peer->transfers);
1316
1317
512
            if (conv_hdr & TCPCLV3_DATA_START_FLAG) {
1318
133
                *xfer_id += 1;
1319
133
                get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
1320
133
            }
1321
512
            tcpcl_peer_associate_transfer(ctx->tx_peer, ctx->cur_loc, *xfer_id);
1322
512
        }
1323
512
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1324
512
        proto_item_set_generated(item_xfer_id);
1325
1326
512
        proto_tree_add_item(conv_tree, hf_tcpclv3_data_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1327
1328
512
        if (tcpcl_analyze_sequence) {
1329
473
            transfer_add_segment(ctx, *xfer_id, (conv_hdr & TCPCLV3_DATA_FLAGS), segment_length, pinfo, tvb, conv_tree, conv_item, item_flags);
1330
473
        }
1331
1332
512
        if (tcpcl_desegment_transfer) {
1333
            // Reassemble the segments
1334
473
            fragment_head *frag_msg;
1335
473
            frag_msg = fragment_add_seq_next(
1336
473
                &xfer_reassembly_table,
1337
473
                tvb, offset,
1338
473
                pinfo, 0, xfer_id,
1339
473
                data_len_clamp,
1340
473
                !(conv_hdr & TCPCLV3_DATA_END_FLAG)
1341
473
            );
1342
473
            ctx->xferload = process_reassembled_data(
1343
473
                tvb, offset, pinfo,
1344
473
                "Reassembled Transfer",
1345
473
                frag_msg,
1346
473
                &xfer_frag_items,
1347
473
                NULL,
1348
473
                tree
1349
473
            );
1350
473
        }
1351
512
        offset += data_len_clamp;
1352
1353
512
        break;
1354
0
    }
1355
1.01k
    case TCPCLV3_ACK_SEGMENT: {
1356
        /*No valid flags*/
1357
1.01k
        offset += 1;
1358
1359
1.01k
        proto_tree_add_item_ret_varint(conv_tree, hf_tcpclv3_ack_length, tvb, offset, -1, ENC_VARINT_SDNV, &segment_length, &sdnv_length);
1360
1.01k
        offset += sdnv_length;
1361
1362
        // implied transfer ID
1363
1.01k
        xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1364
1.01k
        if (!xfer_id) {
1365
1.01k
            xfer_id = wmem_new(pinfo->pool, uint64_t);
1366
1.01k
            *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1367
1368
1.01k
            tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1369
1.01k
        }
1370
1.01k
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1371
1.01k
        proto_item_set_generated(item_xfer_id);
1372
1373
1.01k
        if (tcpcl_analyze_sequence) {
1374
1.01k
            transfer_add_ack(ctx, *xfer_id, 0, segment_length, pinfo, tvb, conv_tree, conv_item, NULL);
1375
1.01k
        }
1376
1377
1.01k
        break;
1378
0
    }
1379
624
    case TCPCLV3_KEEP_ALIVE:
1380
        /*No valid flags in Keep Alive*/
1381
624
        offset += 1;
1382
624
        break;
1383
1384
541
    case TCPCLV3_SHUTDOWN:
1385
        /* Add tree for Shutdown Flags */
1386
541
        sub_item = proto_tree_add_item(conv_tree, hf_tcpclv3_shutdown_flags, tvb,
1387
541
                                        offset, 1, ENC_BIG_ENDIAN);
1388
541
        sub_tree = proto_item_add_subtree(sub_item, ett_tcpclv3_shutdown_flags);
1389
1390
541
        proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_reason,
1391
541
                            tvb, offset, 1, ENC_BIG_ENDIAN);
1392
541
        proto_tree_add_item(sub_tree, hf_tcpclv3_shutdown_flags_delay,
1393
541
                            tvb, offset, 1, ENC_BIG_ENDIAN);
1394
1395
541
        offset += 1;
1396
541
        if (conv_hdr & TCPCLV3_SHUTDOWN_REASON) {
1397
341
            proto_tree_add_item(conv_tree,
1398
341
                                hf_tcpclv3_shutdown_reason, tvb,
1399
341
                                offset, 1, ENC_BIG_ENDIAN);
1400
341
            offset += 1;
1401
341
        }
1402
541
        if (conv_hdr & TCPCLV3_SHUTDOWN_DELAY) {
1403
219
            proto_tree_add_item(conv_tree,
1404
219
                                hf_tcpclv3_shutdown_delay, tvb,
1405
219
                                offset, 2, ENC_BIG_ENDIAN);
1406
219
            offset += 1;
1407
219
        }
1408
541
        break;
1409
550
    case TCPCLV3_REFUSE_BUNDLE:
1410
        /*No valid flags*/
1411
550
        offset += 1;
1412
1413
550
        refuse_bundle_hdr = tvb_get_uint8(tvb, offset);
1414
550
        proto_tree_add_item(conv_tree, hf_tcpclv3_refuse_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
1415
550
        offset += 1;
1416
550
        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, v3_refuse_reason_code, "Unknown"));
1417
1418
        // implied transfer ID
1419
550
        xfer_id = wmem_map_lookup(ctx->rx_peer->frame_loc_to_transfer, ctx->cur_loc);
1420
550
        if (!xfer_id) {
1421
0
            xfer_id = wmem_new(pinfo->pool, uint64_t);
1422
0
            *xfer_id = wmem_map_size(ctx->rx_peer->transfers);
1423
1424
0
            tcpcl_peer_associate_transfer(ctx->rx_peer, ctx->cur_loc, *xfer_id);
1425
0
        }
1426
550
        item_xfer_id = proto_tree_add_uint64(conv_tree, hf_tcpclv3_xfer_id, tvb, 0, 0, *xfer_id);
1427
550
        proto_item_set_generated(item_xfer_id);
1428
1429
550
        if (tcpcl_analyze_sequence) {
1430
0
            transfer_add_refuse(ctx, *xfer_id, pinfo, tvb, conv_tree, conv_item);
1431
0
        }
1432
1433
550
        break;
1434
1435
569
    default:
1436
569
        expert_add_info(pinfo, proto_tree_get_parent(conv_tree), &ei_tcpclv3_invalid_msg_type);
1437
569
        break;
1438
3.80k
    }
1439
1440
3.21k
    return offset;
1441
3.80k
}
1442
1443
static unsigned get_v4_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
1444
537
                            tcpcl_dissect_ctx_t *ctx _U_) {
1445
537
    const int init_offset = offset;
1446
537
    uint8_t msgtype = tvb_get_uint8(tvb, offset);
1447
537
    offset += 1;
1448
537
    switch(msgtype) {
1449
19
        case TCPCLV4_MSGTYPE_SESS_INIT: {
1450
19
            if (tvb_reported_length_remaining(tvb, offset) < 2 + 8 + 8 + 2) {
1451
1
                return 0;
1452
1
            }
1453
18
            offset += 2 + 8 + 8;
1454
18
            uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1455
18
            offset += 2;
1456
18
            if (tvb_reported_length_remaining(tvb, offset) < nodeid_len + 4U) {
1457
2
                return 0;
1458
2
            }
1459
16
            offset += nodeid_len;
1460
16
            uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1461
16
            offset += 4;
1462
16
            if (ckd_add(&offset, offset, extlist_len)) {
1463
1
                THROW(ReportedBoundsError);
1464
1
            }
1465
16
            break;
1466
18
        }
1467
7
        case TCPCLV4_MSGTYPE_SESS_TERM: {
1468
7
            offset += 1 + 1;
1469
7
            break;
1470
18
        }
1471
7
        case TCPCLV4_MSGTYPE_XFER_SEGMENT: {
1472
7
            if (tvb_reported_length_remaining(tvb, offset) < 1) {
1473
0
                return 0;
1474
0
            }
1475
7
            uint8_t flags = tvb_get_uint8(tvb, offset);
1476
7
            offset += 1;
1477
7
            offset += 8;
1478
7
            if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1479
2
                if (tvb_reported_length_remaining(tvb, offset) < 4) {
1480
0
                    return 0;
1481
0
                }
1482
2
                uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1483
2
                offset += 4;
1484
2
                if ((unsigned)tvb_reported_length_remaining(tvb, offset) < extlist_len) {
1485
2
                    return 0;
1486
2
                }
1487
0
                offset += extlist_len;
1488
0
            }
1489
5
            if (tvb_reported_length_remaining(tvb, offset) < 8) {
1490
1
                return 0;
1491
1
            }
1492
4
            uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1493
4
            offset += 8;
1494
4
            const int data_len_clamp = get_clamped_length(data_len, NULL, NULL);
1495
4
            if (ckd_add(&offset, offset, data_len_clamp)) {
1496
2
                THROW(ReportedBoundsError);
1497
2
            }
1498
4
            break;
1499
5
        }
1500
86
        case TCPCLV4_MSGTYPE_XFER_ACK: {
1501
86
            offset += 1 + 8 + 8;
1502
86
            break;
1503
5
        }
1504
35
        case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1505
35
            offset += 1 + 8;
1506
35
            break;
1507
5
        }
1508
33
        case TCPCLV4_MSGTYPE_KEEPALIVE: {
1509
33
            break;
1510
5
        }
1511
120
        case TCPCLV4_MSGTYPE_MSG_REJECT: {
1512
120
            offset += 1 + 1;
1513
120
            break;
1514
5
        }
1515
230
        default:
1516
            // no known message
1517
230
            return 0;
1518
537
    }
1519
298
    return offset - init_offset;
1520
537
}
1521
1522
static int
1523
dissect_v4_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1524
298
               tcpcl_dissect_ctx_t *ctx _U_) {
1525
298
    int offset  = 0;
1526
    // Length of non-protocol 'payload' data in this message
1527
298
    int payload_len = 0;
1528
1529
298
    uint8_t msgtype = 0;
1530
298
    const char *msgtype_name = NULL;
1531
1532
298
    proto_item *item_msg = proto_tree_add_item(tree, hf_tcpclv4_mhdr_tree, tvb, offset, 0, ENC_NA);
1533
298
    proto_tree *tree_msg = proto_item_add_subtree(item_msg, ett_tcpclv4_mhdr);
1534
1535
298
    msgtype = tvb_get_uint8(tvb, offset);
1536
298
    proto_tree_add_uint(tree_msg, hf_tcpclv4_mhdr_type, tvb, offset, 1, msgtype);
1537
298
    offset += 1;
1538
298
    msgtype_name = val_to_str(pinfo->pool, msgtype, v4_message_type_vals, "type 0x%02" PRIx32);
1539
298
    wmem_strbuf_t *suffix_text = wmem_strbuf_new(pinfo->pool, NULL);
1540
1541
298
    switch(msgtype) {
1542
15
        case TCPCLV4_MSGTYPE_SESS_INIT: {
1543
15
            uint16_t keepalive = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1544
15
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_keepalive, tvb, offset, 2, keepalive);
1545
15
            offset += 2;
1546
1547
15
            uint64_t seg_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1548
15
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_seg_mru, tvb, offset, 8, seg_mru);
1549
15
            offset += 8;
1550
1551
15
            uint64_t xfer_mru = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1552
15
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_sess_init_xfer_mru, tvb, offset, 8, xfer_mru);
1553
15
            offset += 8;
1554
1555
15
            uint16_t nodeid_len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1556
15
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_nodeid_len, tvb, offset, 2, nodeid_len);
1557
15
            offset += 2;
1558
1559
15
            {
1560
15
                uint8_t *nodeid_data = tvb_get_string_enc(pinfo->pool, tvb, offset, nodeid_len, ENC_UTF_8);
1561
15
                proto_tree_add_string(tree_msg, hf_tcpclv4_sess_init_nodeid_data, tvb, offset, nodeid_len, (const char *)nodeid_data);
1562
15
            }
1563
15
            offset += nodeid_len;
1564
1565
15
            uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1566
15
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_extlist_len, tvb, offset, 4, extlist_len);
1567
15
            offset += 4;
1568
1569
15
            int extlist_offset = 0;
1570
79
            while (extlist_offset < (int)extlist_len) {
1571
64
                int extitem_offset = 0;
1572
64
                proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_sessext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1573
64
                proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_sessext);
1574
1575
64
                uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1576
64
                proto_tree_add_bitmask(tree_ext, tvb, offset + extlist_offset + extitem_offset, hf_tcpclv4_sessext_flags, ett_tcpclv4_sessext_flags, v4_sessext_flags, ENC_BIG_ENDIAN);
1577
64
                extitem_offset += 1;
1578
64
                const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1579
64
                if (is_critical) {
1580
17
                    expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1581
17
                }
1582
1583
64
                uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1584
64
                proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1585
64
                extitem_offset += 2;
1586
1587
64
                dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1588
64
                const char *subname = dissector_handle_get_description(subdis);
1589
64
                if (subdis) {
1590
3
                    proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1591
3
                }
1592
1593
64
                uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1594
64
                proto_tree_add_uint(tree_ext, hf_tcpclv4_sessext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1595
64
                extitem_offset += 2;
1596
1597
64
                tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1598
64
                proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_sessext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA);
1599
64
                proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_sessext_data);
1600
1601
64
                int sublen = 0;
1602
64
                if (subdis) {
1603
2
                    sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1604
2
                }
1605
64
                if (sublen == 0) {
1606
55
                    expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_sessext_type);
1607
55
                }
1608
64
                extitem_offset += extitem_len;
1609
1610
64
                proto_item_set_len(item_ext, extitem_offset);
1611
64
                extlist_offset += extitem_offset;
1612
1613
64
                if (subname) {
1614
2
                    proto_item_append_text(item_ext, ": %s", subname);
1615
2
                }
1616
62
                else {
1617
62
                    proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1618
62
                }
1619
64
                if (is_critical) {
1620
17
                    proto_item_append_text(item_ext, ", CRITICAL");
1621
17
                }
1622
64
            }
1623
            // advance regardless of any internal offset processing
1624
15
            offset += extlist_len;
1625
1626
15
            if (ctx->tx_peer->sess_init_seen) {
1627
6
                if (tcpcl_analyze_sequence) {
1628
6
                    if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_init_seen, ctx->cur_loc)) {
1629
6
                        expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_duplicate);
1630
6
                    }
1631
6
                }
1632
6
            }
1633
9
            else {
1634
9
                ctx->tx_peer->sess_init_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1635
9
                ctx->tx_peer->keepalive = keepalive;
1636
9
                ctx->tx_peer->segment_mru = seg_mru;
1637
9
                ctx->tx_peer->transfer_mru = xfer_mru;
1638
9
            }
1639
1640
15
            break;
1641
0
        }
1642
7
        case TCPCLV4_MSGTYPE_SESS_TERM: {
1643
7
            uint8_t flags = tvb_get_uint8(tvb, offset);
1644
7
            proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_sess_term_flags, ett_tcpclv4_sess_term_flags, v4_sess_term_flags, ENC_BIG_ENDIAN);
1645
7
            offset += 1;
1646
1647
7
            uint8_t reason = tvb_get_uint8(tvb, offset);
1648
7
            proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_reason, tvb, offset, 1, reason);
1649
7
            offset += 1;
1650
1651
7
            if (ctx->tx_peer->sess_term_seen) {
1652
5
                if (tcpcl_analyze_sequence) {
1653
5
                    if (!tcpcl_frame_loc_equal(ctx->tx_peer->sess_term_seen, ctx->cur_loc)) {
1654
5
                        expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_duplicate);
1655
5
                    }
1656
5
                }
1657
5
            }
1658
2
            else {
1659
2
                ctx->tx_peer->sess_term_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1660
2
                ctx->tx_peer->sess_term_reason = reason;
1661
2
            }
1662
1663
7
            if (tcpcl_analyze_sequence) {
1664
7
                if (ctx->rx_peer->sess_term_seen) {
1665
0
                    proto_item *item_rel = proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_term_related, tvb, 0, 0, ctx->rx_peer->sess_term_seen->frame_num);
1666
0
                    proto_item_set_generated(item_rel);
1667
1668
                    // Is this message after the other SESS_TERM?
1669
0
                    if (tcpcl_frame_loc_compare(ctx->tx_peer->sess_term_seen, ctx->rx_peer->sess_term_seen, NULL) > 0) {
1670
0
                        if (!(flags & TCPCLV4_SESS_TERM_FLAG_REPLY)) {
1671
0
                            expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_term_reply_flag);
1672
0
                        }
1673
0
                    }
1674
0
                }
1675
7
            }
1676
1677
7
            break;
1678
0
        }
1679
2
        case TCPCLV4_MSGTYPE_XFER_SEGMENT:{
1680
2
            uint8_t flags = tvb_get_uint8(tvb, offset);
1681
2
            proto_item *item_flags = proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_xfer_flags, ett_tcpclv4_xfer_flags, v4_xfer_flags, ENC_BIG_ENDIAN);
1682
2
            offset += 1;
1683
1684
2
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1685
2
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1686
2
            offset += 8;
1687
1688
2
            if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1689
0
                uint32_t extlist_len = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
1690
0
                proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_segment_extlist_len, tvb, offset, 4, extlist_len);
1691
0
                offset += 4;
1692
1693
0
                int extlist_offset = 0;
1694
0
                while (extlist_offset < (int)extlist_len) {
1695
0
                    int extitem_offset = 0;
1696
0
                    proto_item *item_ext = proto_tree_add_item(tree_msg, hf_tcpclv4_xferext_tree, tvb, offset + extlist_offset, 0, ENC_NA);
1697
0
                    proto_tree *tree_ext = proto_item_add_subtree(item_ext, ett_tcpclv4_xferext);
1698
1699
0
                    uint8_t extitem_flags = tvb_get_uint8(tvb, offset + extlist_offset + extitem_offset);
1700
0
                    proto_tree_add_bitmask(tree_ext, tvb, offset + extlist_offset + extitem_offset, hf_tcpclv4_xferext_flags, ett_tcpclv4_xferext_flags, v4_xferext_flags, ENC_BIG_ENDIAN);
1701
0
                    extitem_offset += 1;
1702
0
                    const bool is_critical = (extitem_flags & TCPCLV4_EXTENSION_FLAG_CRITICAL);
1703
0
                    if (is_critical) {
1704
0
                        expert_add_info(pinfo, item_ext, &ei_tcpclv4_extitem_critical);
1705
0
                    }
1706
1707
0
                    uint16_t extitem_type = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1708
0
                    proto_item *item_type = proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_type, tvb, offset + extlist_offset + extitem_offset, 2, extitem_type);
1709
0
                    extitem_offset += 2;
1710
1711
0
                    dissector_handle_t subdis = dissector_get_uint_handle(xfer_ext_dissectors, extitem_type);
1712
0
                    const char *subname = dissector_handle_get_description(subdis);
1713
0
                    if (subdis) {
1714
0
                        proto_item_set_text(item_type, "Item Type: %s (0x%04" PRIx16 ")", subname, extitem_type);
1715
0
                    }
1716
1717
0
                    uint16_t extitem_len = tvb_get_uint16(tvb, offset + extlist_offset + extitem_offset, ENC_BIG_ENDIAN);
1718
0
                    proto_tree_add_uint(tree_ext, hf_tcpclv4_xferext_len, tvb, offset + extlist_offset + extitem_offset, 2, extitem_len);
1719
0
                    extitem_offset += 2;
1720
1721
0
                    tvbuff_t *extitem_tvb = tvb_new_subset_length(tvb, offset + extlist_offset + extitem_offset, extitem_len);
1722
0
                    proto_item *item_extdata = proto_tree_add_item(tree_ext, hf_tcpclv4_xferext_data, extitem_tvb, 0, tvb_captured_length(extitem_tvb), ENC_NA);
1723
0
                    proto_tree *tree_extdata = proto_item_add_subtree(item_extdata, ett_tcpclv4_xferext_data);
1724
1725
0
                    tcpcl_frame_loc_t *extitem_loc = tcpcl_frame_loc_new(pinfo->pool, pinfo, extitem_tvb, 0);
1726
0
                    tcpcl_peer_associate_transfer(ctx->tx_peer, extitem_loc, xfer_id);
1727
1728
0
                    int sublen = 0;
1729
0
                    if (subdis) {
1730
0
                        sublen = call_dissector_only(subdis, extitem_tvb, pinfo, tree_extdata, NULL);
1731
0
                    }
1732
0
                    if (sublen == 0) {
1733
0
                        expert_add_info(pinfo, item_type, &ei_tcpclv4_invalid_xferext_type);
1734
0
                    }
1735
0
                    extitem_offset += extitem_len;
1736
1737
0
                    proto_item_set_len(item_ext, extitem_offset);
1738
0
                    extlist_offset += extitem_offset;
1739
1740
0
                    if (subname) {
1741
0
                        proto_item_append_text(item_ext, ": %s", subname);
1742
0
                    }
1743
0
                    else {
1744
0
                        proto_item_append_text(item_ext, ": Type 0x%04" PRIx16, extitem_type);
1745
0
                    }
1746
0
                    if (is_critical) {
1747
0
                        proto_item_append_text(item_ext, ", CRITICAL");
1748
0
                    }
1749
0
                }
1750
                // advance regardless of any internal offset processing
1751
0
                offset += extlist_len;
1752
0
            }
1753
1754
2
            uint64_t data_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1755
2
            proto_item *item_len = proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_segment_data_len, tvb, offset, 8, data_len);
1756
2
            offset += 8;
1757
1758
2
            if (data_len > ctx->rx_peer->segment_mru) {
1759
1
                expert_add_info(pinfo, item_len, &ei_tcpclv4_xfer_seg_over_seg_mru);
1760
1
            }
1761
2
            const int data_len_clamp = get_clamped_length(data_len, pinfo, item_len);
1762
1763
            // Treat data as payload layer
1764
2
            const int data_offset = offset;
1765
2
            proto_tree_add_item(tree_msg, hf_tcpclv4_xfer_segment_data, tvb, offset, data_len_clamp, ENC_NA);
1766
2
            offset += data_len_clamp;
1767
2
            payload_len = data_len_clamp;
1768
1769
2
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1770
1771
2
            if (flags) {
1772
1
                wmem_strbuf_append(suffix_text, ", Flags: ");
1773
1
                bool sep = false;
1774
1
                if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1775
0
                    wmem_strbuf_append(suffix_text, "START");
1776
0
                    sep = true;
1777
0
                }
1778
1
                if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1779
1
                    if (sep) {
1780
0
                        wmem_strbuf_append(suffix_text, "|");
1781
0
                    }
1782
1
                    wmem_strbuf_append(suffix_text, "END");
1783
1
                }
1784
1
            }
1785
1786
2
            if (tcpcl_analyze_sequence) {
1787
1
                transfer_add_segment(ctx, xfer_id, flags, data_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1788
1
            }
1789
1790
2
            if (tcpcl_desegment_transfer) {
1791
                // Reassemble the segments
1792
1
                fragment_head *xferload_frag_msg = fragment_add_seq_next(
1793
1
                    &xfer_reassembly_table,
1794
1
                    tvb, data_offset,
1795
1
                    pinfo, 0, &xfer_id,
1796
1
                    data_len_clamp,
1797
1
                    !(flags & TCPCLV4_TRANSFER_FLAG_END)
1798
1
                );
1799
1
                ctx->xferload = process_reassembled_data(
1800
1
                    tvb, data_offset, pinfo,
1801
1
                    "Reassembled Transfer",
1802
1
                    xferload_frag_msg,
1803
1
                    &xfer_frag_items,
1804
1
                    NULL,
1805
1
                    tree
1806
1
                );
1807
1
            }
1808
1809
2
            break;
1810
0
        }
1811
86
        case TCPCLV4_MSGTYPE_XFER_ACK:{
1812
86
            uint8_t flags = tvb_get_uint8(tvb, offset);
1813
86
            proto_item *item_flags = proto_tree_add_bitmask(tree_msg, tvb, offset, hf_tcpclv4_xfer_flags, ett_tcpclv4_xfer_flags, v4_xfer_flags, ENC_BIG_ENDIAN);
1814
86
            offset += 1;
1815
1816
86
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1817
86
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1818
86
            offset += 8;
1819
1820
86
            uint64_t ack_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1821
86
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_ack_ack_len, tvb, offset, 8, ack_len);
1822
86
            offset += 8;
1823
1824
86
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1825
1826
86
            if (flags) {
1827
79
                wmem_strbuf_append(suffix_text, ", Flags: ");
1828
79
                bool sep = false;
1829
79
                if (flags & TCPCLV4_TRANSFER_FLAG_START) {
1830
73
                    wmem_strbuf_append(suffix_text, "START");
1831
73
                    sep = true;
1832
73
                }
1833
79
                if (flags & TCPCLV4_TRANSFER_FLAG_END) {
1834
6
                    if (sep) {
1835
3
                        wmem_strbuf_append(suffix_text, "|");
1836
3
                    }
1837
6
                    wmem_strbuf_append(suffix_text, "END");
1838
6
                }
1839
79
            }
1840
1841
86
            if (tcpcl_analyze_sequence) {
1842
82
                transfer_add_ack(ctx, xfer_id, flags, ack_len, pinfo, tvb, tree_msg, item_msg, item_flags);
1843
82
            }
1844
1845
86
            break;
1846
0
        }
1847
35
        case TCPCLV4_MSGTYPE_XFER_REFUSE: {
1848
35
            uint8_t reason = tvb_get_uint8(tvb, offset);
1849
35
            proto_tree_add_uint(tree_msg, hf_tcpclv4_xfer_refuse_reason, tvb, offset, 1, reason);
1850
35
            offset += 1;
1851
1852
35
            uint64_t xfer_id = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
1853
35
            proto_tree_add_uint64(tree_msg, hf_tcpclv4_xfer_id, tvb, offset, 8, xfer_id);
1854
35
            offset += 8;
1855
1856
35
            wmem_strbuf_append_printf(suffix_text, ", Xfer ID: %" PRIi64, xfer_id);
1857
1858
35
            if (tcpcl_analyze_sequence) {
1859
35
                transfer_add_refuse(ctx, xfer_id, pinfo, tvb, tree_msg, item_msg);
1860
35
            }
1861
1862
35
            break;
1863
0
        }
1864
33
        case TCPCLV4_MSGTYPE_KEEPALIVE: {
1865
33
            break;
1866
0
        }
1867
120
        case TCPCLV4_MSGTYPE_MSG_REJECT: {
1868
120
            uint8_t reason = tvb_get_uint8(tvb, offset);
1869
120
            proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_reason, tvb, offset, 1, reason);
1870
120
            offset += 1;
1871
1872
120
            uint8_t rej_head = tvb_get_uint8(tvb, offset);
1873
120
            proto_tree_add_uint(tree_msg, hf_tcpclv4_msg_reject_head, tvb, offset, 1, rej_head);
1874
120
            offset += 1;
1875
1876
120
            break;
1877
0
        }
1878
0
        default:
1879
0
            expert_add_info(pinfo, item_msg, &ei_tcpclv4_invalid_msg_type);
1880
0
            break;
1881
298
    }
1882
1883
286
    proto_item_set_len(item_msg, offset - payload_len);
1884
286
    proto_item_append_text(item_msg, ": %s%s", msgtype_name, wmem_strbuf_get_str(suffix_text));
1885
286
    wmem_strbuf_finalize(suffix_text);
1886
1887
286
    if (tcpcl_analyze_sequence) {
1888
286
        if (!(ctx->tx_peer->chdr_missing)) {
1889
            // assume the capture is somewhere in the middle
1890
2
            if (!(ctx->tx_peer->sess_init_seen)) {
1891
2
                expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1892
2
            }
1893
0
            else {
1894
                // This message is before SESS_INIT (but is not the SESS_INIT)
1895
0
                const int cmp_sess_init = tcpcl_frame_loc_compare(ctx->cur_loc, ctx->tx_peer->sess_init_seen, NULL);
1896
0
                if (((msgtype == TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init < 0))
1897
0
                    || ((msgtype != TCPCLV4_MSGTYPE_SESS_INIT) && (cmp_sess_init <= 0))) {
1898
0
                    expert_add_info(pinfo, item_msg, &ei_tcpclv4_sess_init_missing);
1899
0
                }
1900
0
            }
1901
2
        }
1902
286
    }
1903
1904
286
    if (msgtype_name) {
1905
286
        col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, msgtype_name);
1906
286
    }
1907
1908
286
    try_negotiate(ctx, pinfo);
1909
    // Show negotiation results
1910
286
    if (msgtype == TCPCLV4_MSGTYPE_SESS_INIT) {
1911
8
        if (ctx->convo->sess_negotiated) {
1912
0
            if (ctx->rx_peer->sess_init_seen){
1913
0
                proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_sess_init_related, tvb, 0, 0, ctx->rx_peer->sess_init_seen->frame_num);
1914
0
                proto_item_set_generated(item_nego);
1915
0
            }
1916
0
            {
1917
0
                proto_item *item_nego = proto_tree_add_uint(tree_msg, hf_tcpclv4_negotiate_keepalive, tvb, 0, 0, ctx->convo->sess_keepalive);
1918
0
                proto_item_set_generated(item_nego);
1919
0
            }
1920
0
        }
1921
8
    }
1922
1923
286
    return offset;
1924
298
}
1925
1926
/** Function to extract a message length, or zero if not valid.
1927
 * This will call set_chdr_missing() if valid.
1928
 */
1929
typedef unsigned (*chdr_missing_check)(packet_info *, tvbuff_t *, int offset, tcpcl_dissect_ctx_t *);
1930
1931
/** Inspect a single segment to determine if this looks like a TLS record set.
1932
 */
1933
static unsigned chdr_missing_tls(packet_info *pinfo, tvbuff_t *tvb, int offset,
1934
220
                              tcpcl_dissect_ctx_t *ctx) {
1935
220
    if (ctx->convo->session_tls_start) {
1936
        // already in a TLS context
1937
0
        return 0;
1938
0
    }
1939
1940
    // similar heuristics to is_sslv3_or_tls() from packet-tls.c
1941
220
    if (tvb_captured_length(tvb) < 5) {
1942
2
        return 0;
1943
2
    }
1944
218
    uint8_t rectype = tvb_get_uint8(tvb, offset);
1945
218
    uint16_t recvers = tvb_get_uint16(tvb, offset+1, ENC_BIG_ENDIAN);
1946
218
    uint16_t reclen = tvb_get_uint16(tvb, offset+1+2, ENC_BIG_ENDIAN);
1947
1948
218
    switch(rectype) {
1949
        // These overlap with TCPCLV3_DATA_SEGMENT but have invalid flags
1950
        // They are valid but unallocated v4 message type codes
1951
88
        case SSL_ID_ALERT:
1952
91
        case SSL_ID_HANDSHAKE:
1953
91
        case SSL_ID_APP_DATA:
1954
92
        case SSL_ID_HEARTBEAT:
1955
92
            break;
1956
126
        default:
1957
126
            return 0;
1958
218
    }
1959
92
    if ((recvers & 0xFF00) != 0x0300) {
1960
92
        return 0;
1961
92
    }
1962
0
    if (reclen == 0 || reclen >= TLS_MAX_RECORD_LENGTH + 2048) {
1963
0
        return 0;
1964
0
    }
1965
1966
    // post-STARTTLS
1967
0
    ctx->convo->session_use_tls = true;
1968
0
    ctx->convo->session_tls_start = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
1969
0
    ssl_starttls_post_ack(tls_handle, pinfo, tcpcl_handle);
1970
1971
0
    return tvb_reported_length(tvb);
1972
1973
0
}
1974
1975
static unsigned chdr_missing_v3(packet_info *pinfo, tvbuff_t *tvb, int offset,
1976
193
                             tcpcl_dissect_ctx_t *ctx) {
1977
193
    unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
1978
193
    if (sublen > 0) {
1979
185
        set_chdr_missing(ctx->tx_peer, 3);
1980
185
    }
1981
193
    return sublen;
1982
193
}
1983
1984
static unsigned chdr_missing_v4(packet_info *pinfo, tvbuff_t *tvb, int offset,
1985
220
                             tcpcl_dissect_ctx_t *ctx) {
1986
220
    unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
1987
220
    if (sublen > 0) {
1988
26
        set_chdr_missing(ctx->tx_peer, 4);
1989
26
    }
1990
220
    return sublen;
1991
220
}
1992
1993
static const chdr_missing_check chdr_missing_v3first[] = {
1994
    &chdr_missing_tls,
1995
    &chdr_missing_v3,
1996
    &chdr_missing_v4,
1997
    NULL
1998
};
1999
static const chdr_missing_check chdr_missing_v3only[] = {
2000
    &chdr_missing_v3,
2001
    NULL
2002
};
2003
static const chdr_missing_check chdr_missing_v4first[] = {
2004
    &chdr_missing_tls,
2005
    &chdr_missing_v4,
2006
    &chdr_missing_v3,
2007
    NULL
2008
};
2009
static const chdr_missing_check chdr_missing_v4only[] = {
2010
    &chdr_missing_v4,
2011
    NULL
2012
};
2013
2014
4.38k
static unsigned get_message_len(packet_info *pinfo, tvbuff_t *tvb, int ext_offset, void *data _U_) {
2015
4.38k
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, ext_offset);
2016
4.38k
    if (!ctx) {
2017
0
        return 0;
2018
0
    }
2019
4.38k
    const unsigned init_offset = ext_offset;
2020
4.38k
    unsigned offset = ext_offset;
2021
2022
4.38k
    if (ctx->is_contact) {
2023
239
        if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2024
            // Optional heuristic dissection of a message
2025
220
            const chdr_missing_check *checks = NULL;
2026
220
            switch (tcpcl_chdr_missing) {
2027
0
                case CHDRMSN_V3FIRST:
2028
0
                    checks = chdr_missing_v3first;
2029
0
                    break;
2030
0
                case CHDRMSN_V3ONLY:
2031
0
                    checks = chdr_missing_v3only;
2032
0
                    break;
2033
220
                case CHDRMSN_V4FIRST:
2034
220
                    checks = chdr_missing_v4first;
2035
220
                    break;
2036
0
                case CHDRMSN_V4ONLY:
2037
0
                    checks = chdr_missing_v4only;
2038
0
                    break;
2039
220
            }
2040
220
            if (checks) {
2041
642
                for (const chdr_missing_check *chk = checks; *chk; ++chk) {
2042
633
                    unsigned sublen = (**chk)(pinfo, tvb, offset, ctx);
2043
633
                    if (sublen > 0) {
2044
211
                        return sublen;
2045
211
                    }
2046
633
                }
2047
                // no match
2048
9
                return 0;
2049
220
            }
2050
0
            else {
2051
                // require the contact header
2052
0
                const unsigned available = tvb_captured_length(tvb) - offset;
2053
0
                if (available < sizeof(magic) + 1) {
2054
0
                    return DESEGMENT_ONE_MORE_SEGMENT;
2055
0
                }
2056
                // sufficient size available but no match
2057
0
                return 0;
2058
0
            }
2059
220
        }
2060
19
        offset += sizeof(magic);
2061
2062
19
        uint8_t version = tvb_get_uint8(tvb, offset);
2063
19
        offset += 1;
2064
19
        if (version == 3) {
2065
0
            offset += 3; // flags + keepalive
2066
0
            uint64_t eid_len;
2067
0
            const unsigned bytecount = tvb_get_sdnv(tvb, offset, &eid_len);
2068
0
            const int len_clamp = get_clamped_length(eid_len, NULL, NULL);
2069
0
            offset += bytecount + len_clamp;
2070
0
        }
2071
19
        else if (version == 4) {
2072
2
            offset += 1; // flags
2073
2
        }
2074
17
        else {
2075
17
            return 0;
2076
17
        }
2077
19
    }
2078
4.14k
    else {
2079
4.14k
        if (ctx->tx_peer->version == 3) {
2080
3.82k
            unsigned sublen = get_v3_msg_len(pinfo, tvb, offset, ctx);
2081
3.82k
            if (sublen == 0) {
2082
195
                return 0;
2083
195
            }
2084
3.62k
            offset += sublen;
2085
3.62k
        }
2086
317
        else if (ctx->tx_peer->version == 4) {
2087
317
            unsigned sublen = get_v4_msg_len(pinfo, tvb, offset, ctx);
2088
317
            if (sublen == 0) {
2089
43
                return 0;
2090
43
            }
2091
274
            offset += sublen;
2092
274
        }
2093
0
        else {
2094
0
            return 0;
2095
0
        }
2096
4.14k
    }
2097
3.90k
    const int needlen = offset - init_offset;
2098
3.90k
    return needlen;
2099
4.38k
}
2100
2101
4.10k
static int dissect_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2102
4.10k
    unsigned offset = 0;
2103
4.10k
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2104
4.10k
    if (!ctx) {
2105
0
        return 0;
2106
0
    }
2107
2108
4.10k
    {
2109
4.10k
        const char *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
2110
4.10k
        if (g_strcmp0(proto_name, proto_name_tcpcl) != 0) {
2111
4.10k
            col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_name_tcpcl);
2112
4.10k
            col_clear(pinfo->cinfo, COL_INFO);
2113
4.10k
        }
2114
4.10k
    }
2115
2116
    // Append to the last TCPCL tree item if there is one
2117
4.10k
    proto_item *item_tcpcl;
2118
4.10k
    proto_tree *tree_tcpcl;
2119
4.10k
    bool is_new_item_tcpcl = false;
2120
4.10k
    if (tree && (tree->last_child)
2121
4.10k
            && (PITEM_HFINFO(tree->last_child)->id == proto_tcpcl)) {
2122
3.09k
        item_tcpcl = tree->last_child;
2123
3.09k
        tree_tcpcl = proto_item_get_subtree(item_tcpcl);
2124
3.09k
    }
2125
1.01k
    else {
2126
1.01k
        item_tcpcl = proto_tree_add_item(tree, proto_tcpcl, tvb, 0, -1, ENC_NA);
2127
1.01k
        tree_tcpcl = proto_item_add_subtree(item_tcpcl, ett_proto_tcpcl);
2128
1.01k
        is_new_item_tcpcl = true;
2129
1.01k
    }
2130
2131
4.10k
    if (ctx->tx_peer->chdr_missing) {
2132
4.10k
        expert_add_info(pinfo, item_tcpcl, &ei_chdr_missing);
2133
4.10k
    }
2134
4.10k
    if (ctx->is_contact) {
2135
2
        col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Contact Header");
2136
2137
2
        proto_item *item_chdr = proto_tree_add_item(tree_tcpcl, hf_chdr_tree, tvb, offset, -1, ENC_NA);
2138
2
        proto_tree *tree_chdr = proto_item_add_subtree(item_chdr, ett_chdr);
2139
2140
2
        proto_item *item_magic = proto_tree_add_item(tree_chdr, hf_chdr_magic, tvb, offset, sizeof(magic), ENC_NA);
2141
2
        if (tvb_memeql(tvb, offset, magic, sizeof(magic)) != 0) {
2142
0
            expert_add_info(pinfo, item_magic, &ei_invalid_magic);
2143
0
            return 0;
2144
0
        }
2145
2
        offset += sizeof(magic);
2146
2147
2
        ctx->tx_peer->version = tvb_get_uint8(tvb, offset);
2148
2
        proto_item *item_version = proto_tree_add_uint(tree_chdr, hf_chdr_version, tvb, offset, 1, ctx->tx_peer->version);
2149
2
        offset += 1;
2150
2151
        // Mark or check version match
2152
2
        if (!ctx->convo->version) {
2153
2
            ctx->convo->version = wmem_new(wmem_file_scope(), uint8_t);
2154
2
            *(ctx->convo->version) = ctx->tx_peer->version;
2155
2
        }
2156
0
        else if (*(ctx->convo->version) != ctx->tx_peer->version) {
2157
0
            expert_add_info(pinfo, item_version, &ei_mismatch_version);
2158
0
        }
2159
2160
2
        if ((ctx->tx_peer->version < 3) || (ctx->tx_peer->version > 4)) {
2161
0
            expert_add_info(pinfo, item_version, &ei_invalid_version);
2162
0
            return offset;
2163
0
        }
2164
2165
2
        if (ctx->tx_peer->version == 3) {
2166
            /* Subtree to expand the bits in the Contact Header Flags */
2167
0
            proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv3_chdr_flags, ett_tcpclv3_chdr_flags, v3_chdr_flags, ENC_BIG_ENDIAN);
2168
0
            offset++;
2169
2170
0
            proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
2171
0
            offset += 2;
2172
2173
            /*
2174
             * New format Contact header has length field followed by EID.
2175
             */
2176
0
            uint64_t eid_length;
2177
0
            unsigned sdnv_length;
2178
0
            proto_item *sub_item = proto_tree_add_item_ret_varint(tree_chdr, hf_tcpclv3_chdr_local_eid_length, tvb, offset, -1, ENC_VARINT_SDNV, &eid_length, &sdnv_length);
2179
0
            offset += sdnv_length;
2180
0
            const int eid_len_clamp = get_clamped_length(eid_length, pinfo, sub_item);
2181
2182
0
            proto_tree_add_item(tree_chdr, hf_tcpclv3_chdr_local_eid, tvb, offset, eid_len_clamp, ENC_ASCII);
2183
0
            offset += eid_len_clamp;
2184
2185
            // assumed parameters
2186
0
            ctx->tx_peer->segment_mru = UINT64_MAX;
2187
0
            ctx->tx_peer->transfer_mru = UINT64_MAX;
2188
0
        }
2189
2
        else {          /* (version == 4) */
2190
2
            uint8_t flags = tvb_get_uint8(tvb, offset);
2191
2
            proto_tree_add_bitmask(tree_chdr, tvb, offset, hf_tcpclv4_chdr_flags, ett_tcpclv4_chdr_flags, v4_chdr_flags, ENC_BIG_ENDIAN);
2192
2
            offset += 1;
2193
2194
2
            ctx->tx_peer->can_tls = (flags & TCPCLV4_CONTACT_FLAG_CANTLS);
2195
2
        }
2196
2197
2
        proto_item_set_len(item_chdr, offset);
2198
2199
2
        if (ctx->tx_peer->chdr_seen) {
2200
0
            if (tcpcl_analyze_sequence) {
2201
0
                if (!tcpcl_frame_loc_equal(ctx->tx_peer->chdr_seen, ctx->cur_loc)) {
2202
0
                    expert_add_info(pinfo, item_chdr, &ei_chdr_duplicate);
2203
0
                }
2204
0
            }
2205
0
        }
2206
2
        else {
2207
2
            ctx->tx_peer->chdr_seen = tcpcl_frame_loc_clone(wmem_file_scope(), ctx->cur_loc);
2208
2
        }
2209
2210
2
        try_negotiate(ctx, pinfo);
2211
        // Show negotiation results
2212
2
        if (ctx->convo->contact_negotiated) {
2213
0
            if (ctx->rx_peer->chdr_seen) {
2214
0
                proto_item *item_nego = proto_tree_add_uint(tree_chdr, hf_chdr_related, tvb, 0, 0, ctx->rx_peer->chdr_seen->frame_num);
2215
0
                proto_item_set_generated(item_nego);
2216
0
            }
2217
0
            if (ctx->tx_peer->version == 4) {
2218
0
                proto_item *item_nego = proto_tree_add_boolean(tree_chdr, hf_tcpclv4_negotiate_use_tls, tvb, 0, 0, ctx->convo->session_use_tls);
2219
0
                proto_item_set_generated(item_nego);
2220
0
            }
2221
0
        }
2222
2
    }
2223
4.10k
    else {
2224
4.10k
        if (ctx->tx_peer->version == 3) {
2225
3.80k
            offset += dissect_v3_msg(tvb, pinfo, tree_tcpcl, ctx);
2226
3.80k
        }
2227
298
        else if (ctx->tx_peer->version == 4) {
2228
298
            offset += dissect_v4_msg(tvb, pinfo, tree_tcpcl, ctx);
2229
298
        }
2230
4.10k
    }
2231
2232
4.10k
    if (is_new_item_tcpcl) {
2233
536
        proto_item_set_len(item_tcpcl, offset);
2234
536
        proto_item_append_text(item_tcpcl, " Version %d", ctx->tx_peer->version);
2235
536
    }
2236
3.57k
    else {
2237
3.57k
        proto_item_set_len(item_tcpcl, proto_item_get_len(item_tcpcl) + offset);
2238
3.57k
    }
2239
2240
4.10k
    if (ctx->xferload) {
2241
269
        col_append_str(pinfo->cinfo, COL_INFO, " [Bundle]");
2242
2243
269
        if (tcpcl_decode_bundle) {
2244
269
            if (bundle_handle) {
2245
269
                call_dissector(
2246
269
                    bundle_handle,
2247
269
                    ctx->xferload,
2248
269
                    pinfo,
2249
269
                    tree
2250
269
                );
2251
269
            }
2252
269
        }
2253
269
    }
2254
2255
4.10k
    return offset;
2256
4.10k
}
2257
2258
static int
2259
dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2260
331
{
2261
    /* Retrieve information from conversation, or add it if it isn't
2262
     * there yet */
2263
331
    conversation_t *convo = find_or_create_conversation(pinfo);
2264
331
    tcpcl_conversation_t *tcpcl_convo = (tcpcl_conversation_t *)conversation_get_proto_data(convo, proto_tcpcl);
2265
331
    if (!tcpcl_convo) {
2266
225
        tcpcl_convo = tcpcl_conversation_new();
2267
225
        conversation_add_proto_data(convo, proto_tcpcl, tcpcl_convo);
2268
        // Assume the first source (i.e. TCP initiator) is the active node
2269
225
        copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->active->addr), &(pinfo->src));
2270
225
        tcpcl_convo->active->port = pinfo->srcport;
2271
225
        copy_address_wmem(wmem_file_scope(), &(tcpcl_convo->passive->addr), &(pinfo->dst));
2272
225
        tcpcl_convo->passive->port = pinfo->destport;
2273
225
    }
2274
2275
331
    tcp_dissect_pdus(tvb, pinfo, tree, true, 1, get_message_len, dissect_message, NULL);
2276
2277
331
    const unsigned buflen = tvb_captured_length(tvb);
2278
331
    return buflen;
2279
331
}
2280
2281
static bool
2282
dissect_tcpcl_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2283
2.98k
{
2284
2.98k
    if (tvb_reported_length(tvb) < minimum_chdr_size) {
2285
224
        return false;
2286
224
    }
2287
2.76k
    if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) {
2288
2.75k
        return false;
2289
2.75k
    }
2290
2291
    // treat the rest of the connection as TCPCL
2292
10
    conversation_t *convo = find_or_create_conversation(pinfo);
2293
10
    conversation_set_dissector(convo, tcpcl_handle);
2294
2295
10
    dissect_tcpcl(tvb, pinfo, tree, data);
2296
10
    return true;
2297
2.76k
}
2298
2299
2
static int dissect_xferext_transferlen(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) {
2300
2
    unsigned offset = 0;
2301
2
    tcpcl_dissect_ctx_t *ctx = tcpcl_dissect_ctx_get(tvb, pinfo, offset);
2302
2
    if (!ctx) {
2303
0
        return 0;
2304
0
    }
2305
2306
2
    uint64_t total_len = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
2307
2
    proto_item *item_len = proto_tree_add_uint64(tree, hf_tcpclv4_xferext_transferlen_total_len, tvb, offset, 8, total_len);
2308
2
    offset += 8;
2309
2
    if (total_len > ctx->rx_peer->transfer_mru) {
2310
2
        expert_add_info(pinfo, item_len, &ei_tcpclv4_xferload_over_xfer_mru);
2311
2
    }
2312
2313
2
    if (tcpcl_analyze_sequence) {
2314
2
        uint64_t *xfer_id = wmem_map_lookup(ctx->tx_peer->frame_loc_to_transfer, ctx->cur_loc);
2315
2
        if (xfer_id) {
2316
0
            tcpcl_transfer_t *xfer = get_or_create_transfer_t(ctx->tx_peer->transfers, *xfer_id);
2317
0
            xfer->total_length = wmem_new(wmem_file_scope(), uint64_t);
2318
0
            *(xfer->total_length) = total_len;
2319
0
        }
2320
2
    }
2321
2322
2
    return offset;
2323
2
}
2324
2325
0
static int dissect_othername_bundleeid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
2326
0
    unsigned offset = 0;
2327
0
    asn1_ctx_t actx;
2328
0
    asn1_ctx_init(&actx, ASN1_ENC_BER, true, pinfo);
2329
0
    offset += dissect_ber_restricted_string(
2330
0
        false, BER_UNI_TAG_IA5String,
2331
0
        &actx, tree, tvb, offset, hf_othername_bundleeid, NULL
2332
0
    );
2333
0
    return offset;
2334
0
}
2335
2336
/// Re-initialize after a configuration change
2337
16
static void reinit_tcpcl(void) {
2338
16
}
2339
2340
void
2341
proto_register_tcpcl(void)
2342
16
{
2343
16
    expert_module_t *expert_tcpcl;
2344
2345
16
    proto_tcpcl = proto_register_protocol("DTN TCP Convergence Layer Protocol", "TCPCL", "tcpcl");
2346
2347
16
    proto_tcpcl_exts = proto_register_protocol_in_name_only(
2348
16
        "TCPCL Extension Subdissectors",
2349
16
        "TCPCL Extension Subdissectors",
2350
16
        "tcpcl_exts",
2351
16
        proto_tcpcl,
2352
16
        FT_PROTOCOL
2353
16
    );
2354
2355
16
    proto_register_field_array(proto_tcpcl, hf_tcpcl, array_length(hf_tcpcl));
2356
16
    proto_register_subtree_array(ett, array_length(ett));
2357
16
    expert_tcpcl = expert_register_protocol(proto_tcpcl);
2358
16
    expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl));
2359
2360
16
    tcpcl_handle = register_dissector("tcpcl", dissect_tcpcl, proto_tcpcl);
2361
16
    sess_ext_dissectors = register_dissector_table("tcpcl.v4.sess_ext", "TCPCLv4 Session Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2362
16
    xfer_ext_dissectors = register_dissector_table("tcpcl.v4.xfer_ext", "TCPCLv4 Transfer Extension", proto_tcpcl, FT_UINT16, BASE_HEX);
2363
2364
16
    module_t *module_tcpcl = prefs_register_protocol(proto_tcpcl, reinit_tcpcl);
2365
16
    prefs_register_enum_preference(
2366
16
        module_tcpcl,
2367
16
        "allow_chdr_missing",
2368
16
        "Allow missing Contact Header",
2369
16
        "Whether the TCPCL dissector should use heuristic "
2370
16
        "dissection of messages in the absence of a Contact Header "
2371
16
        "(if the capture misses the start of session).",
2372
16
        &tcpcl_chdr_missing,
2373
16
        chdr_missing_choices,
2374
16
        false
2375
16
    );
2376
16
    prefs_register_bool_preference(
2377
16
        module_tcpcl,
2378
16
        "analyze_sequence",
2379
16
        "Analyze message sequences",
2380
16
        "Whether the TCPCL dissector should analyze the sequencing of "
2381
16
        "the messages within each session.",
2382
16
        &tcpcl_analyze_sequence
2383
16
    );
2384
16
    prefs_register_bool_preference(
2385
16
        module_tcpcl,
2386
16
        "desegment_transfer",
2387
16
        "Reassemble the segments of each transfer",
2388
16
        "Whether the TCPCL dissector should combine the sequential segments "
2389
16
        "of a transfer into the full bundle being transferred."
2390
16
        "To use this option, you must also enable "
2391
16
        "\"Allow subdissectors to reassemble TCP streams\" "
2392
16
        "in the TCP protocol settings.",
2393
16
        &tcpcl_desegment_transfer
2394
16
    );
2395
16
    prefs_register_bool_preference(
2396
16
        module_tcpcl,
2397
16
        "decode_bundle",
2398
16
        "Decode bundle data",
2399
16
        "If enabled, the transfer bundle will be decoded.",
2400
16
        &tcpcl_decode_bundle
2401
16
    );
2402
2403
16
    reassembly_table_register(
2404
16
        &xfer_reassembly_table,
2405
16
        &xfer_reassembly_table_functions
2406
16
    );
2407
2408
16
}
2409
2410
void
2411
proto_reg_handoff_tcpcl(void)
2412
16
{
2413
16
    tls_handle = find_dissector_add_dependency("tls", proto_tcpcl);
2414
16
    bundle_handle = find_dissector("bundle");
2415
2416
16
    dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT, tcpcl_handle);
2417
16
    heur_dissector_add("tcp", dissect_tcpcl_heur, "TCPCL over TCP", "tcpcl_tcp", proto_tcpcl, HEURISTIC_ENABLE);
2418
2419
    /* Packaged extensions */
2420
16
    {
2421
16
        dissector_handle_t dis_h = create_dissector_handle_with_name_and_description(dissect_xferext_transferlen, proto_tcpcl_exts, NULL, "Transfer Length");
2422
16
        dissector_add_uint("tcpcl.v4.xfer_ext", TCPCLV4_XFEREXT_TRANSFER_LEN, dis_h);
2423
16
    }
2424
2425
16
    register_ber_oid_dissector("1.3.6.1.5.5.7.3.35", NULL, proto_tcpcl_exts, "id-kp-bundleSecurity");
2426
16
    register_ber_oid_dissector("1.3.6.1.5.5.7.8.11", dissect_othername_bundleeid, proto_tcpcl_exts, "id-on-bundleEID");
2427
2428
16
    reinit_tcpcl();
2429
16
}
2430
2431
/*
2432
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2433
 *
2434
 * Local variables:
2435
 * c-basic-offset: 4
2436
 * tab-width: 8
2437
 * indent-tabs-mode: nil
2438
 * End:
2439
 *
2440
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2441
 * :indentSize=4:tabSize=8:noTabs=true:
2442
 */