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