1 /* packet-teredo.c v.1.0
2 * Routines for Teredo packets disassembly
3 * draft-huitema-v6ops-teredo-02.txt
5 * Copyright 2003, Ragi BEJJANI - 6WIND - <ragi.bejjani@6wind.com>
6 * Copyright 2003, Vincent JARDIN - 6WIND - <vincent.jardin@6wind.com>
7 * Copyright 2004, Remi DENIS-COURMONT
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
23 #define UDP_PORT_TEREDO 3544
25 void proto_reg_handoff_teredo(void);
26 void proto_register_teredo(void);
28 static int teredo_tap
;
30 static int proto_teredo
;
32 static int hf_teredo_auth
;
33 static int hf_teredo_auth_idlen
;
34 static int hf_teredo_auth_aulen
;
35 static int hf_teredo_auth_id
;
36 static int hf_teredo_auth_value
;
37 static int hf_teredo_auth_nonce
;
38 static int hf_teredo_auth_conf
;
39 static int hf_teredo_orig
;
40 static int hf_teredo_orig_port
;
41 static int hf_teredo_orig_addr
;
43 static int ett_teredo
;
44 static int ett_teredo_auth
;
45 static int ett_teredo_orig
;
57 uint32_t th_iporgaddr
;
60 static dissector_table_t teredo_dissector_table
;
61 /*static heur_dissector_list_t heur_subdissector_list;*/
62 static dissector_handle_t teredo_handle
;
63 static dissector_handle_t data_handle
;
66 parse_teredo_auth(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
67 int offset
, e_teredohdr
*teredoh
)
69 unsigned idlen
, aulen
;
71 col_append_sep_str (pinfo
->cinfo
, COL_INFO
, ", ",
72 "Authentication header");
74 teredoh
->th_indtyp
= 1;
77 idlen
= tvb_get_uint8(tvb
, offset
);
78 teredoh
->th_cidlen
= idlen
;
81 aulen
= tvb_get_uint8(tvb
, offset
);
82 teredoh
->th_authdlen
= aulen
;
88 ti
= proto_tree_add_item(tree
, hf_teredo_auth
, tvb
, offset
-4,
89 13 + idlen
+ aulen
, ENC_NA
);
90 tree
= proto_item_add_subtree(ti
, ett_teredo_auth
);
92 proto_tree_add_item(tree
, hf_teredo_auth_idlen
, tvb
,
93 offset
- 2, 1, ENC_BIG_ENDIAN
);
94 proto_tree_add_item(tree
, hf_teredo_auth_aulen
, tvb
,
95 offset
- 1, 1, ENC_BIG_ENDIAN
);
97 /* idlen is usually zero */
99 proto_tree_add_item(tree
, hf_teredo_auth_id
, tvb
,
100 offset
, idlen
, ENC_NA
);
104 /* aulen is usually zero */
106 proto_tree_add_item(tree
, hf_teredo_auth_value
, tvb
,
107 offset
, aulen
, ENC_NA
);
111 proto_tree_add_item(tree
, hf_teredo_auth_nonce
, tvb
,
115 proto_tree_add_item(tree
, hf_teredo_auth_conf
, tvb
,
120 offset
+= idlen
+ aulen
+ 9;
122 tvb_memcpy(tvb
, teredoh
->th_nonce
, offset
- 9, 8);
123 teredoh
->th_conf
= tvb_get_uint8(tvb
, offset
- 1);
130 parse_teredo_orig(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
131 int offset
, e_teredohdr
*teredoh
)
133 proto_item
*ti
= NULL
;
135 col_append_sep_str (pinfo
->cinfo
, COL_INFO
, ", ",
136 "Origin indication");
139 ti
= proto_tree_add_item(tree
, hf_teredo_orig
, tvb
, offset
,
141 tree
= proto_item_add_subtree(ti
, ett_teredo_orig
);
145 teredoh
->th_orgport
= tvb_get_ntohs(tvb
, offset
);
148 * The "usual arithmetic conversions" will convert
149 * "teredoh->th_orgport" to an "int" (because all
150 * "unsigned short" values will fit in an "int"),
151 * which will zero-extend it. This means that
152 * complementing it will turn all the zeroes in
153 * the upper 16 bits into ones; we just want the
154 * lower 16 bits (containing the port number)
155 * complemented, with the result zero-extended.
157 * That's what the cast is for.
159 proto_tree_add_uint(tree
, hf_teredo_orig_port
, tvb
,
161 (uint16_t)~teredoh
->th_orgport
);
165 teredoh
->th_iporgaddr
= tvb_get_ipv4(tvb
, offset
);
167 proto_tree_add_ipv4(tree
, hf_teredo_orig_addr
, tvb
,
168 offset
, 4, ~teredoh
->th_iporgaddr
);
176 /* Determine if there is a sub-dissector and call it. This has been */
177 /* separated into a stand alone routine to other protocol dissectors */
178 /* can call to it, ie. socks */
182 decode_teredo_ports(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,proto_tree
*tree
, int th_header
)
186 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
188 if (dissector_try_uint(teredo_dissector_table
, th_header
, next_tvb
, pinfo
, tree
))
191 call_dissector(data_handle
,next_tvb
, pinfo
, tree
);
195 dissect_teredo(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
197 proto_tree
*teredo_tree
;
200 static e_teredohdr teredohstruct
[4], *teredoh
;
201 static int teredoh_count
= 0;
204 if(teredoh_count
>=4){
207 teredoh
= &teredohstruct
[teredoh_count
];
209 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Teredo");
210 col_clear(pinfo
->cinfo
, COL_INFO
);
212 ti
= proto_tree_add_item(tree
, proto_teredo
, tvb
, 0, -1, ENC_NA
);
213 teredo_tree
= proto_item_add_subtree(ti
, ett_teredo
);
215 teredoh
->th_header
= tvb_get_ntohs(tvb
, offset
);
217 if (teredoh
->th_header
== 1) {
218 offset
= parse_teredo_auth(tvb
, pinfo
, teredo_tree
,
220 teredoh
->th_header
= tvb_get_ntohs(tvb
, offset
);
223 teredoh
->th_indtyp
= 0;
225 if ( teredoh
->th_header
== 0 ) {
226 offset
= parse_teredo_orig(tvb
, pinfo
, teredo_tree
,
230 teredoh
->th_ip_v_hl
= tvb_get_uint8(tvb
, offset
);
232 decode_teredo_ports(tvb
, offset
, pinfo
, tree
, teredoh
->th_header
/* , teredoh->th_orgport*/);
233 tap_queue_packet(teredo_tap
, pinfo
, teredoh
);
234 return tvb_captured_length(tvb
);
239 dissect_teredo_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
244 if (tvb_captured_length_remaining(tvb
, offset
) < 40)
247 val
= tvb_get_ntohs(tvb
, offset
);
249 if (val
== 1) /* possible auth header */
251 uint8_t idlen
, aulen
;
255 idlen
= tvb_get_uint8(tvb
, offset
);
258 aulen
= tvb_get_uint8(tvb
, offset
);
261 if (tvb_captured_length_remaining(tvb
, offset
) < idlen
+ aulen
+ 40)
264 offset
+= idlen
+ aulen
;
266 val
= tvb_get_ntohs(tvb
, offset
);
269 if (val
== 0) /* origin indication */
273 if (tvb_captured_length_remaining(tvb
, offset
) < 40)
276 val
= tvb_get_ntohs(tvb
, offset
);
280 * We have to check upper-layer packet a little bit otherwise we will
281 * match -almost- *ANY* packet.
282 * These checks are in the Teredo specification by the way.
283 * Unfortunately, that will cause false-negative if the snaplen is too
284 * short to get the packet entirely.
286 if ((val
>> 12) == 6) /* IPv6 header */
288 /* checks IPv6 payload length */
289 val
= tvb_get_ntohs(tvb
, offset
+ 4);
293 return false; /* length too big for Teredo */
295 if (tvb_reported_length_remaining(tvb
, offset
) != val
)
296 return false; /* length mismatch */
298 dissect_teredo (tvb
, pinfo
, tree
, data
);
302 return false; /* not an IPv6 packet */
307 proto_register_teredo(void)
309 static hf_register_info hf
[] = {
310 /* Authentication header */
312 { "Teredo Authentication header", "teredo.auth",
313 FT_NONE
, BASE_NONE
, NULL
, 0x0,
316 { &hf_teredo_auth_idlen
,
317 { "Client identifier length", "teredo.auth.idlen",
318 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
319 "Client identifier length (ID-len)", HFILL
}},
321 { &hf_teredo_auth_aulen
,
322 { "Authentication value length", "teredo.auth.aulen",
323 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
324 "Authentication value length (AU-len)", HFILL
}},
326 { &hf_teredo_auth_id
,
327 { "Client identifier", "teredo.auth.id",
328 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
329 "Client identifier (ID)", HFILL
}},
331 { &hf_teredo_auth_value
,
332 { "Authentication value", "teredo.auth.value",
333 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
334 "Authentication value (hash)", HFILL
}},
336 { &hf_teredo_auth_nonce
,
337 { "Nonce value", "teredo.auth.nonce",
338 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
339 "Nonce value prevents spoofing Teredo server.",
342 { &hf_teredo_auth_conf
,
343 { "Confirmation byte", "teredo.auth.conf",
344 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
345 "Confirmation byte is zero upon successful authentication.",
348 /* Origin indication */
350 { "Teredo Origin Indication header", "teredo.orig",
351 FT_NONE
, BASE_NONE
, NULL
, 0x0,
354 { &hf_teredo_orig_port
,
355 { "Origin UDP port", "teredo.orig.port",
356 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
359 { &hf_teredo_orig_addr
,
360 { "Origin IPv4 address", "teredo.orig.addr",
361 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
365 static int *ett
[] = {
366 &ett_teredo
, &ett_teredo_auth
, &ett_teredo_orig
369 module_t
*teredo_module
;
371 proto_teredo
= proto_register_protocol("Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
372 proto_register_field_array(proto_teredo
, hf
, array_length(hf
));
373 proto_register_subtree_array(ett
, array_length(ett
));
374 teredo_handle
= register_dissector("teredo", dissect_teredo
, proto_teredo
);
376 /* subdissector code */
377 teredo_dissector_table
= register_dissector_table("teredo", "Teredo", proto_teredo
, FT_UINT16
, BASE_DEC
);
379 teredo_module
= prefs_register_protocol(proto_teredo
, NULL
);
381 prefs_register_obsolete_preference(teredo_module
, "heuristic_teredo");
383 teredo_tap
= register_tap("teredo");
387 proto_reg_handoff_teredo(void)
389 data_handle
= find_dissector("ipv6");
391 dissector_add_uint_with_preference("udp.port", UDP_PORT_TEREDO
, teredo_handle
);
392 heur_dissector_add("udp", dissect_teredo_heur
, "Teredo over UDP", "teredo_udp", proto_teredo
, HEURISTIC_DISABLE
);
396 * Editor modelines - https://www.wireshark.org/tools/modelines.html
401 * indent-tabs-mode: t
404 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
405 * :indentSize=8:tabSize=8:noTabs=false: