/src/wireshark/epan/dissectors/packet-amt.c
Line | Count | Source |
1 | | /* packet-amt.c |
2 | | * Routines for Automatic Multicast Tunneling (AMT) dissection |
3 | | * Copyright 2017, Alexis La Goutte (See AUTHORS) |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * RFC 7450 : Automatic Multicast Tunneling |
14 | | */ |
15 | | |
16 | | #include <config.h> |
17 | | #include <epan/packet.h> |
18 | | #include <epan/expert.h> |
19 | | #include <epan/tfs.h> |
20 | | |
21 | 15 | #define AMT_UDP_PORT 2268 |
22 | | |
23 | | void proto_reg_handoff_amt(void); |
24 | | void proto_register_amt(void); |
25 | | |
26 | | static dissector_handle_t amt_handle; |
27 | | |
28 | | static int proto_amt; |
29 | | static int hf_amt_version; |
30 | | static int hf_amt_type; |
31 | | static int hf_amt_reserved; |
32 | | static int hf_amt_discovery_nonce; |
33 | | static int hf_amt_relay_address_ipv4; |
34 | | static int hf_amt_relay_address_ipv6; |
35 | | static int hf_amt_request_nonce; |
36 | | static int hf_amt_request_reserved; |
37 | | static int hf_amt_request_p; |
38 | | static int hf_amt_membership_query_reserved; |
39 | | static int hf_amt_membership_query_l; |
40 | | static int hf_amt_membership_query_g; |
41 | | static int hf_amt_response_mac; |
42 | | static int hf_amt_gateway_port_number; |
43 | | static int hf_amt_gateway_ip_address; |
44 | | static int hf_amt_multicast_data; |
45 | | |
46 | | static expert_field ei_amt_relay_address_unknown; |
47 | | static expert_field ei_amt_unknown; |
48 | | |
49 | | static int ett_amt; |
50 | | |
51 | 1 | #define RELAY_DISCOVERY 1 |
52 | 3 | #define RELAY_ADVERTISEMENT 2 |
53 | 1 | #define REQUEST 3 |
54 | 2 | #define MEMBERSHIP_QUERY 4 |
55 | 1 | #define MEMBERSHIP_UPDATE 5 |
56 | 1 | #define MULTICAST_DATA 6 |
57 | 1 | #define TEARDOWN 7 |
58 | | |
59 | | static const value_string amt_type_vals[] = { |
60 | | { RELAY_DISCOVERY, "Relay Discovery" }, |
61 | | { RELAY_ADVERTISEMENT, "Relay Advertisement" }, |
62 | | { REQUEST, "Request" }, |
63 | | { MEMBERSHIP_QUERY, "Membership Query" }, |
64 | | { MEMBERSHIP_UPDATE, "Membership Update" }, |
65 | | { MULTICAST_DATA, "Multicast Data" }, |
66 | | { TEARDOWN, "Teardown" }, |
67 | | {0, NULL } |
68 | | }; |
69 | | |
70 | | static const true_false_string tfs_request_p = { |
71 | | "IPv4 packet carrying an IGMPv3 General Query", |
72 | | "IPv6 packet carrying an MLDv2 General Query" |
73 | | }; |
74 | | |
75 | | static dissector_handle_t ip_handle; |
76 | | |
77 | | /* Code to actually dissect the packets */ |
78 | | static int |
79 | | dissect_amt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
80 | 12 | { |
81 | 12 | proto_item *ti; |
82 | 12 | proto_tree *amt_tree; |
83 | 12 | unsigned offset = 0; |
84 | 12 | uint32_t type; |
85 | 12 | tvbuff_t *next_tvb; |
86 | | |
87 | 12 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "AMT"); |
88 | | |
89 | 12 | ti = proto_tree_add_item(tree, proto_amt, tvb, 0, -1, ENC_NA); |
90 | | |
91 | 12 | amt_tree = proto_item_add_subtree(ti, ett_amt); |
92 | | |
93 | 12 | proto_tree_add_item(amt_tree, hf_amt_version, tvb, offset, 1, ENC_NA); |
94 | 12 | proto_tree_add_item_ret_uint(amt_tree, hf_amt_type, tvb, offset, 1, ENC_NA, &type); |
95 | 12 | col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(type, amt_type_vals, "Unknown AMT TYPE")); |
96 | 12 | offset += 1; |
97 | | |
98 | 12 | switch(type){ |
99 | 1 | case RELAY_DISCOVERY: /* 1 */ |
100 | 1 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 3, ENC_NA); |
101 | 1 | offset += 3; |
102 | 1 | proto_tree_add_item(amt_tree, hf_amt_discovery_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
103 | 1 | offset += 4; |
104 | 1 | break; |
105 | 3 | case RELAY_ADVERTISEMENT:{ /* 2 */ |
106 | 3 | uint32_t relay_length; |
107 | 3 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 3, ENC_NA); |
108 | 3 | offset += 3; |
109 | 3 | proto_tree_add_item(amt_tree, hf_amt_discovery_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
110 | 3 | offset += 4; |
111 | 3 | relay_length = tvb_reported_length_remaining(tvb, offset); |
112 | 3 | switch(relay_length){ |
113 | 1 | case 4: /* IPv4 Address */ |
114 | 1 | proto_tree_add_item(amt_tree, hf_amt_relay_address_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN); |
115 | 1 | offset += 4; |
116 | 1 | break; |
117 | 1 | case 16: /* IPv6 Address */ |
118 | 1 | proto_tree_add_item(amt_tree, hf_amt_relay_address_ipv6, tvb, offset, 16, ENC_NA); |
119 | 1 | offset += 16; |
120 | 1 | break; |
121 | 1 | default: /* Unknown type.. */ |
122 | 1 | proto_tree_add_expert(amt_tree, pinfo, &ei_amt_relay_address_unknown, tvb, offset, relay_length); |
123 | 1 | offset += relay_length; |
124 | 1 | break; |
125 | 3 | } |
126 | 3 | } |
127 | 3 | break; |
128 | 3 | case REQUEST: /* 3 */ |
129 | 1 | proto_tree_add_item(amt_tree, hf_amt_request_reserved, tvb, offset, 1, ENC_NA); |
130 | 1 | proto_tree_add_item(amt_tree, hf_amt_request_p, tvb, offset, 1, ENC_NA); |
131 | 1 | offset += 1; |
132 | 1 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 2, ENC_NA); |
133 | 1 | offset += 2; |
134 | 1 | proto_tree_add_item(amt_tree, hf_amt_request_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
135 | 1 | offset += 4; |
136 | 1 | break; |
137 | 2 | case MEMBERSHIP_QUERY:{ /* 4 */ |
138 | 2 | uint32_t flags_g; |
139 | 2 | proto_tree_add_item(amt_tree, hf_amt_membership_query_reserved, tvb, offset, 1, ENC_NA); |
140 | 2 | proto_tree_add_item(amt_tree, hf_amt_membership_query_l, tvb, offset, 1, ENC_NA); |
141 | 2 | proto_tree_add_item_ret_uint(amt_tree, hf_amt_membership_query_g, tvb, offset, 1, ENC_NA, &flags_g); |
142 | 2 | offset += 1; |
143 | 2 | proto_tree_add_item(amt_tree, hf_amt_response_mac, tvb, offset, 6, ENC_BIG_ENDIAN); |
144 | 2 | offset += 6; |
145 | 2 | proto_tree_add_item(amt_tree, hf_amt_request_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
146 | 2 | offset += 4; |
147 | 2 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
148 | 2 | call_dissector(ip_handle, next_tvb, pinfo, amt_tree); |
149 | 2 | offset += tvb_reported_length_remaining(tvb, offset); |
150 | 2 | if(flags_g){ |
151 | 1 | offset -= 2; |
152 | 1 | offset -= 16; |
153 | 1 | proto_tree_add_item(amt_tree, hf_amt_gateway_port_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
154 | 1 | offset += 2; |
155 | 1 | proto_tree_add_item(amt_tree, hf_amt_gateway_ip_address, tvb, offset, 16, ENC_NA); |
156 | 1 | offset += 16; |
157 | 1 | } |
158 | 2 | } |
159 | 2 | break; |
160 | 1 | case MEMBERSHIP_UPDATE: /* 5 */ |
161 | 1 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 1, ENC_NA); |
162 | 1 | offset += 1; |
163 | 1 | proto_tree_add_item(amt_tree, hf_amt_response_mac, tvb, offset, 6, ENC_BIG_ENDIAN); |
164 | 1 | offset += 6; |
165 | 1 | proto_tree_add_item(amt_tree, hf_amt_request_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
166 | 1 | offset += 4; |
167 | 1 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
168 | 1 | call_dissector(ip_handle, next_tvb, pinfo, amt_tree); |
169 | 1 | offset += tvb_reported_length_remaining(tvb, offset); |
170 | 1 | break; |
171 | 1 | case MULTICAST_DATA: /* 6 */ |
172 | 1 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 1, ENC_NA); |
173 | 1 | offset += 1; |
174 | 1 | proto_tree_add_item(amt_tree, hf_amt_multicast_data, tvb, offset, -1, ENC_NA); |
175 | 1 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
176 | 1 | call_dissector(ip_handle, next_tvb, pinfo, amt_tree); |
177 | 1 | offset += tvb_reported_length_remaining(tvb, offset); |
178 | 1 | break; |
179 | 1 | case TEARDOWN:{ /* 7 */ |
180 | 1 | proto_tree_add_item(amt_tree, hf_amt_reserved, tvb, offset, 1, ENC_NA); |
181 | 1 | offset += 1; |
182 | 1 | proto_tree_add_item(amt_tree, hf_amt_response_mac, tvb, offset, 6, ENC_BIG_ENDIAN); |
183 | 1 | offset += 6; |
184 | 1 | proto_tree_add_item(amt_tree, hf_amt_request_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); |
185 | 1 | offset += 4; |
186 | 1 | proto_tree_add_item(amt_tree, hf_amt_gateway_port_number, tvb, offset, 2, ENC_BIG_ENDIAN); |
187 | 1 | offset += 2; |
188 | 1 | proto_tree_add_item(amt_tree, hf_amt_gateway_ip_address, tvb, offset, 16, ENC_NA); |
189 | 1 | offset += 16; |
190 | 1 | } |
191 | 1 | break; |
192 | 2 | default:{ |
193 | 2 | uint32_t len_unknown; |
194 | 2 | len_unknown = tvb_reported_length_remaining(tvb, offset); |
195 | 2 | proto_tree_add_expert(amt_tree, pinfo, &ei_amt_unknown, tvb, offset, len_unknown); |
196 | 2 | offset += len_unknown; |
197 | 2 | } |
198 | 2 | break; |
199 | 12 | } |
200 | 10 | return offset; |
201 | 12 | } |
202 | | |
203 | | void |
204 | | proto_register_amt(void) |
205 | 15 | { |
206 | 15 | expert_module_t *expert_amt; |
207 | | |
208 | 15 | static hf_register_info hf[] = { |
209 | 15 | { &hf_amt_version, |
210 | 15 | { "Version", "amt.version", |
211 | 15 | FT_UINT8, BASE_DEC, NULL, 0xF0, |
212 | 15 | "Must be always 0", HFILL } |
213 | 15 | }, |
214 | 15 | { &hf_amt_type, |
215 | 15 | { "Type", "amt.type", |
216 | 15 | FT_UINT8, BASE_DEC, VALS(amt_type_vals), 0x0F, |
217 | 15 | NULL, HFILL } |
218 | 15 | }, |
219 | 15 | { &hf_amt_reserved, |
220 | 15 | { "Reserved", "amt.reserved", |
221 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
222 | 15 | NULL, HFILL } |
223 | 15 | }, |
224 | 15 | { &hf_amt_discovery_nonce, |
225 | 15 | { "Discovery Nonce", "amt.discovery_nonce", |
226 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
227 | 15 | NULL, HFILL } |
228 | 15 | }, |
229 | 15 | { &hf_amt_relay_address_ipv4, |
230 | 15 | { "Relay Address (IPv4)", "amt.relay_address.ipv4", |
231 | 15 | FT_IPv4, BASE_NONE, NULL, 0x0, |
232 | 15 | NULL, HFILL } |
233 | 15 | }, |
234 | 15 | { &hf_amt_relay_address_ipv6, |
235 | 15 | { "Relay Address (IPv6)", "amt.relay_address.ipv6", |
236 | 15 | FT_IPv6, BASE_NONE, NULL, 0x0, |
237 | 15 | NULL, HFILL } |
238 | 15 | }, |
239 | 15 | { &hf_amt_request_nonce, |
240 | 15 | { "Request Nonce", "amt.request_nonce", |
241 | 15 | FT_UINT32, BASE_HEX, NULL, 0x0, |
242 | 15 | NULL, HFILL } |
243 | 15 | }, |
244 | 15 | { &hf_amt_request_reserved, |
245 | 15 | { "Reserved", "amt.request.reserved", |
246 | 15 | FT_UINT8, BASE_HEX, NULL, 0xFE, |
247 | 15 | NULL, HFILL } |
248 | 15 | }, |
249 | 15 | { &hf_amt_request_p, |
250 | 15 | { "P Flags", "amt.request.p", |
251 | 15 | FT_BOOLEAN, 8, TFS(&tfs_request_p), 0x01, |
252 | 15 | NULL, HFILL } |
253 | 15 | }, |
254 | 15 | { &hf_amt_membership_query_reserved, |
255 | 15 | { "Reserved", "amt.membership_query.reserved", |
256 | 15 | FT_UINT8, BASE_HEX, NULL, 0xFC, |
257 | 15 | NULL, HFILL } |
258 | 15 | }, |
259 | 15 | { &hf_amt_membership_query_l, |
260 | 15 | { "L Flags", "amt.membership_query.l", |
261 | 15 | FT_UINT8, BASE_DEC, NULL, 0x02, |
262 | 15 | NULL, HFILL } |
263 | 15 | }, |
264 | 15 | { &hf_amt_membership_query_g, |
265 | 15 | { "G Flags", "amt.membership_query.g", |
266 | 15 | FT_UINT8, BASE_DEC, NULL, 0x01, |
267 | 15 | NULL, HFILL } |
268 | 15 | }, |
269 | | /* TODO: should be FT_ETHER? */ |
270 | 15 | { &hf_amt_response_mac, |
271 | 15 | { "Response MAC", "amt.response_mac", |
272 | 15 | FT_UINT48, BASE_HEX, NULL, 0x0, |
273 | 15 | NULL, HFILL } |
274 | 15 | }, |
275 | 15 | { &hf_amt_gateway_port_number, |
276 | 15 | { "Gateway Port Number", "amt.gateway.port_number", |
277 | 15 | FT_UINT16, BASE_DEC, NULL, 0x0, |
278 | 15 | NULL, HFILL } |
279 | 15 | }, |
280 | 15 | { &hf_amt_gateway_ip_address, |
281 | 15 | { "Gateway IP Address", "amt.gateway.ip_address", |
282 | 15 | FT_IPv6, BASE_NONE, NULL, 0x0, |
283 | 15 | NULL, HFILL } |
284 | 15 | }, |
285 | 15 | { &hf_amt_multicast_data, |
286 | 15 | { "Multicast Data", "amt.multicast_data", |
287 | 15 | FT_BYTES, BASE_NONE, NULL, 0x0, |
288 | 15 | NULL, HFILL } |
289 | 15 | }, |
290 | 15 | }; |
291 | | |
292 | 15 | static int *ett[] = { |
293 | 15 | &ett_amt |
294 | 15 | }; |
295 | | |
296 | | |
297 | 15 | static ei_register_info ei[] = { |
298 | 15 | { &ei_amt_relay_address_unknown, |
299 | 15 | { "amt.relay_address.unknown", PI_UNDECODED, PI_NOTE, |
300 | 15 | "Relay Address (Unknown Type)", EXPFILL } |
301 | 15 | }, |
302 | 15 | { &ei_amt_unknown, |
303 | 15 | { "amt.unknown", PI_UNDECODED, PI_NOTE, |
304 | 15 | "Unknown Data", EXPFILL } |
305 | 15 | } |
306 | 15 | }; |
307 | | |
308 | | |
309 | 15 | proto_amt = proto_register_protocol("Automatic Multicast Tunneling", "AMT", "amt"); |
310 | | |
311 | 15 | proto_register_field_array(proto_amt, hf, array_length(hf)); |
312 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
313 | | |
314 | | |
315 | 15 | expert_amt = expert_register_protocol(proto_amt); |
316 | 15 | expert_register_field_array(expert_amt, ei, array_length(ei)); |
317 | | |
318 | 15 | amt_handle = register_dissector("amt", dissect_amt, proto_amt); |
319 | 15 | } |
320 | | |
321 | | void |
322 | | proto_reg_handoff_amt(void) |
323 | 15 | { |
324 | 15 | ip_handle = find_dissector_add_dependency("ip", proto_amt); |
325 | | |
326 | 15 | dissector_add_uint_with_preference("udp.port", AMT_UDP_PORT, amt_handle); |
327 | 15 | } |
328 | | |
329 | | /* |
330 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
331 | | * |
332 | | * Local variables: |
333 | | * c-basic-offset: 4 |
334 | | * tab-width: 8 |
335 | | * indent-tabs-mode: nil |
336 | | * End: |
337 | | * |
338 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
339 | | * :indentSize=4:tabSize=8:noTabs=true: |
340 | | */ |