/src/wireshark/epan/dissectors/packet-turnchannel.c
Line | Count | Source |
1 | | /* packet-turnchannel.c |
2 | | * Routines for TURN channel dissection (TURN negotiation is handled |
3 | | * in the STUN2 dissector |
4 | | * Copyright 2008, 8x8 Inc. <petithug@8x8.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * |
12 | | * Please refer to the following specs for protocol detail: |
13 | | * - draft-ietf-behave-rfc3489bis-15 |
14 | | * - draft-ietf-mmusic-ice-19 |
15 | | * - draft-ietf-behave-nat-behavior-discovery-03 |
16 | | * - draft-ietf-behave-turn-07 |
17 | | * - draft-ietf-behave-turn-ipv6-03 |
18 | | * |
19 | | * XXX - these are now: |
20 | | * - RFC 5389 |
21 | | * - RFC 5245 |
22 | | * - RFC 5780 |
23 | | * - RFC 5766 |
24 | | * - RFC 6156 |
25 | | * - RFC 8656 |
26 | | * |
27 | | * Update as necessary. |
28 | | */ |
29 | | |
30 | | #include "config.h" |
31 | | |
32 | | #include <epan/packet.h> |
33 | | #include "packet-tcp.h" |
34 | | |
35 | | void proto_register_turnchannel(void); |
36 | | void proto_reg_handoff_turnchannel(void); |
37 | | |
38 | | /* heuristic subdissectors */ |
39 | | static heur_dissector_list_t heur_subdissector_list; |
40 | | |
41 | | /* Initialize the protocol and registered fields */ |
42 | | static int proto_turnchannel; |
43 | | |
44 | | static int hf_turnchannel_id; |
45 | | static int hf_turnchannel_len; |
46 | | |
47 | 0 | #define TURNCHANNEL_HDR_LEN ((unsigned)4) |
48 | | |
49 | 0 | #define MS_MULTIPLEX_TURN 0xFF10 |
50 | | |
51 | | /* Initialize the subtree pointers */ |
52 | | static int ett_turnchannel; |
53 | | |
54 | | static dissector_handle_t turnchannel_tcp_handle; |
55 | | static dissector_handle_t turnchannel_udp_handle; |
56 | | |
57 | | /* |
58 | | * RFC 5764 defined a demultiplexing scheme to allow TURN is co-exist |
59 | | * on the same 5-tuple as STUN, DTLS, RTP/RTCP, and ZTLS by rejecting |
60 | | * previous reserved channel numbers, restricting the channel numbers |
61 | | * to 0x4000-0x7FFF. RFC 5766 (TURN) did not incorporate the restriction, |
62 | | * but RFC 8656 did, further restricting the channel numbers to the |
63 | | * range 0x4000-0x4FFF. |
64 | | * |
65 | | * Reject channel numbers outside 0x4000-0x7FFF (except for the special |
66 | | * MS-TURN multiplex channel number), since no implementation has used |
67 | | * any value outside that range, and the 0x5000-0x7FFF range is reserved |
68 | | * in the multiplexing scheme. |
69 | | */ |
70 | | static bool |
71 | | test_turnchannel_id(uint16_t channel_id) |
72 | 0 | { |
73 | 0 | if ((channel_id & 0x4000) == 0x4000 || channel_id == MS_MULTIPLEX_TURN) |
74 | 0 | return true; |
75 | | |
76 | 0 | return false; |
77 | 0 | } |
78 | | |
79 | | static int |
80 | | dissect_turnchannel_message(tvbuff_t *tvb, packet_info *pinfo, |
81 | | proto_tree *tree, void *data _U_) |
82 | 0 | { |
83 | 0 | unsigned len; |
84 | 0 | uint16_t channel_id; |
85 | 0 | uint16_t data_len; |
86 | 0 | proto_item *ti; |
87 | 0 | proto_tree *turnchannel_tree; |
88 | 0 | heur_dtbl_entry_t *hdtbl_entry; |
89 | |
|
90 | 0 | len = tvb_captured_length(tvb); |
91 | | /* First, make sure we have enough data to do the check. */ |
92 | 0 | if (len < TURNCHANNEL_HDR_LEN) { |
93 | 0 | return 0; |
94 | 0 | } |
95 | | |
96 | 0 | channel_id = tvb_get_ntohs(tvb, 0); |
97 | 0 | data_len = tvb_get_ntohs(tvb, 2); |
98 | |
|
99 | 0 | if (!test_turnchannel_id(channel_id)) { |
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | 0 | if (len != TURNCHANNEL_HDR_LEN + data_len) { |
104 | 0 | return 0; |
105 | 0 | } |
106 | | |
107 | | /* Seems to be a decent TURN channel message */ |
108 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "TURN CHANNEL"); |
109 | |
|
110 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "Channel Id 0x%x", channel_id); |
111 | |
|
112 | 0 | ti = proto_tree_add_item(tree, proto_turnchannel, tvb, 0, -1, ENC_NA); |
113 | |
|
114 | 0 | turnchannel_tree = proto_item_add_subtree(ti, ett_turnchannel); |
115 | |
|
116 | 0 | proto_tree_add_uint(turnchannel_tree, hf_turnchannel_id, tvb, 0, 2, channel_id); |
117 | 0 | proto_tree_add_uint(turnchannel_tree, hf_turnchannel_len, tvb, 2, 2, data_len); |
118 | |
|
119 | 0 | if (len > TURNCHANNEL_HDR_LEN) { |
120 | 0 | tvbuff_t *next_tvb; |
121 | 0 | unsigned reported_len; |
122 | |
|
123 | 0 | reported_len = tvb_reported_length_remaining(tvb, |
124 | 0 | TURNCHANNEL_HDR_LEN); |
125 | 0 | if (data_len < reported_len) { |
126 | 0 | reported_len = data_len; |
127 | 0 | } |
128 | 0 | next_tvb = tvb_new_subset_length(tvb, TURNCHANNEL_HDR_LEN, reported_len); |
129 | | |
130 | |
|
131 | 0 | if (!dissector_try_heuristic(heur_subdissector_list, |
132 | 0 | next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { |
133 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
134 | 0 | } |
135 | 0 | } |
136 | |
|
137 | 0 | return tvb_captured_length(tvb); |
138 | 0 | } |
139 | | |
140 | | static unsigned |
141 | | get_turnchannel_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, |
142 | | int offset, void *data _U_) |
143 | 0 | { |
144 | 0 | uint16_t channel_id; |
145 | 0 | channel_id = tvb_get_ntohs(tvb, 0); |
146 | | /* If the channel number is outside the range, either we missed |
147 | | * a TCP segment or this is STUN, DTLS, RTP, etc. multiplexed on |
148 | | * the same 5-tuple. Report the length as the rest of the packet |
149 | | * and dissect_turnchannel_message will reject it, rather than |
150 | | * using a bogus PDU length and messing up the dissection of |
151 | | * future TURN packets. |
152 | | */ |
153 | 0 | if (!test_turnchannel_id(channel_id)) { |
154 | 0 | return tvb_reported_length(tvb); |
155 | 0 | } |
156 | 0 | return (unsigned)tvb_get_ntohs(tvb, offset+2) + TURNCHANNEL_HDR_LEN; |
157 | 0 | } |
158 | | |
159 | | static int |
160 | | dissect_turnchannel_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
161 | 0 | { |
162 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, true, TURNCHANNEL_HDR_LEN, |
163 | 0 | get_turnchannel_message_len, dissect_turnchannel_message, data); |
164 | 0 | return tvb_captured_length(tvb); |
165 | 0 | } |
166 | | |
167 | | void |
168 | | proto_register_turnchannel(void) |
169 | 14 | { |
170 | 14 | static hf_register_info hf[] = { |
171 | 14 | { &hf_turnchannel_id, |
172 | 14 | { "TURN Channel ID", "turnchannel.id", FT_UINT16, |
173 | 14 | BASE_HEX, NULL, 0x0, NULL, HFILL } |
174 | 14 | }, |
175 | 14 | { &hf_turnchannel_len, |
176 | 14 | { "Data Length", "turnchannel.length", FT_UINT16, |
177 | 14 | BASE_DEC, NULL, 0x0, NULL, HFILL } |
178 | 14 | }, |
179 | 14 | }; |
180 | | |
181 | | /* Setup protocol subtree array */ |
182 | 14 | static int *ett[] = { |
183 | 14 | &ett_turnchannel, |
184 | 14 | }; |
185 | | |
186 | | /* Register the protocol name and description */ |
187 | 14 | proto_turnchannel = proto_register_protocol("TURN Channel", "TURNCHANNEL", "turnchannel"); |
188 | | |
189 | 14 | turnchannel_tcp_handle = register_dissector("turnchannel-tcp", dissect_turnchannel_tcp, proto_turnchannel); |
190 | 14 | turnchannel_udp_handle = register_dissector("turnchannel", dissect_turnchannel_message, proto_turnchannel); |
191 | | |
192 | | /* subdissectors */ |
193 | | /* XXX: Nothing actually registers to this list. All dissectors register |
194 | | * to the heuristic subdissector list for STUN, since the STUN dissector |
195 | | * doesn't actually call this dissector but uses its own implementation |
196 | | * of TURN Channel messages. |
197 | | */ |
198 | 14 | heur_subdissector_list = register_heur_dissector_list_with_description("turnchannel", "TURN Channel message", proto_turnchannel); |
199 | | |
200 | | /* Required function calls to register the header fields and subtrees used */ |
201 | 14 | proto_register_field_array(proto_turnchannel, hf, array_length(hf)); |
202 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
203 | | |
204 | 14 | } |
205 | | |
206 | | |
207 | | void |
208 | | proto_reg_handoff_turnchannel(void) |
209 | 14 | { |
210 | | /* Register for "Decode As" in case STUN negotiation isn't captured */ |
211 | 14 | dissector_add_for_decode_as_with_preference("tcp.port", turnchannel_tcp_handle); |
212 | 14 | dissector_add_for_decode_as_with_preference("udp.port", turnchannel_udp_handle); |
213 | | |
214 | | /* |
215 | | * SSL/TLS and DTLS Application-Layer Protocol Negotiation (ALPN) |
216 | | * protocol ID. |
217 | | */ |
218 | 14 | dissector_add_string("tls.alpn", "stun.turn", turnchannel_tcp_handle); |
219 | 14 | dissector_add_string("dtls.alpn", "stun.turn", turnchannel_udp_handle); |
220 | 14 | } |
221 | | |
222 | | /* |
223 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
224 | | * |
225 | | * Local variables: |
226 | | * c-basic-offset: 8 |
227 | | * tab-width: 8 |
228 | | * indent-tabs-mode: t |
229 | | * End: |
230 | | * |
231 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
232 | | * :indentSize=8:tabSize=8:noTabs=false: |
233 | | */ |