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