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
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include <epan/packet.h>
40 #include <epan/addr_resolv.h>
41 #include <epan/ipproto.h>
42 #include <epan/prefs.h>
44 #include "packet-ip.h"
47 #define UDP_PORT_TEREDO 3544
49 static int teredo_tap = -1;
51 static int proto_teredo = -1;
53 static int hf_teredo_auth = -1;
54 static int hf_teredo_auth_idlen = -1;
55 static int hf_teredo_auth_aulen = -1;
56 static int hf_teredo_auth_id = -1;
57 static int hf_teredo_auth_value = -1;
58 static int hf_teredo_auth_nonce = -1;
59 static int hf_teredo_auth_conf = -1;
60 static int hf_teredo_orig = -1;
61 static int hf_teredo_orig_port = -1;
62 static int hf_teredo_orig_addr = -1;
64 static gint ett_teredo = -1;
65 static gint ett_teredo_auth = -1, ett_teredo_orig = -1;
80 static dissector_table_t teredo_dissector_table;
81 /*static heur_dissector_list_t heur_subdissector_list;*/
82 static dissector_handle_t data_handle;
84 static gboolean global_teredo_heur = FALSE;
88 parse_teredo_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
89 int offset, e_teredohdr *teredoh)
91 unsigned idlen, aulen;
93 if (check_col(pinfo->cinfo, COL_INFO))
94 col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
95 "Authentication header");
97 teredoh->th_indtyp = 1;
100 idlen = tvb_get_guint8(tvb, offset);
101 teredoh->th_cidlen = idlen;
104 aulen = tvb_get_guint8(tvb, offset);
105 teredoh->th_authdlen = aulen;
111 ti = proto_tree_add_item(tree, hf_teredo_auth, tvb, offset-4,
112 13 + idlen + aulen, FALSE);
113 tree = proto_item_add_subtree(ti, ett_teredo_auth);
115 proto_tree_add_item(tree, hf_teredo_auth_idlen, tvb,
116 offset - 2, 1, FALSE);
117 proto_tree_add_item(tree, hf_teredo_auth_aulen, tvb,
118 offset - 1, 1, FALSE);
120 /* idlen is usually zero */
122 proto_tree_add_item(tree, hf_teredo_auth_id, tvb,
123 offset, idlen, FALSE);
127 /* aulen is usually zero */
129 proto_tree_add_item(tree, hf_teredo_auth_value, tvb,
130 offset, aulen, FALSE);
134 proto_tree_add_item(tree, hf_teredo_auth_nonce, tvb,
138 proto_tree_add_item(tree, hf_teredo_auth_conf, tvb,
143 offset += idlen + aulen + 9;
145 tvb_memcpy(tvb, teredoh->th_nonce, offset - 9, 8);
146 teredoh->th_conf = tvb_get_guint8(tvb, offset - 1);
153 parse_teredo_orig(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
154 int offset, e_teredohdr *teredoh)
156 proto_item *ti = NULL;
158 if (check_col(pinfo->cinfo, COL_INFO))
159 col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
160 "Origin indication");
163 ti = proto_tree_add_item(tree, hf_teredo_orig, tvb, offset,
165 tree = proto_item_add_subtree(ti, ett_teredo_orig);
169 teredoh->th_orgport = tvb_get_ntohs(tvb, offset);
172 * The "usual arithmetic conversions" will convert
173 * "teredoh->th_orgport" to an "int" (because all
174 * "unsigned short" values will fit in an "int"),
175 * which will zero-extend it. This means that
176 * complementing it will turn all the zeroes in
177 * the upper 16 bits into ones; we just want the
178 * lower 16 bits (containing the port number)
179 * complemented, with the result zero-extended.
181 * That's what the cast is for.
183 proto_tree_add_uint(tree, hf_teredo_orig_port, tvb,
185 (guint16)~teredoh->th_orgport);
189 teredoh->th_iporgaddr = tvb_get_ipv4(tvb, offset);
191 proto_tree_add_ipv4(tree, hf_teredo_orig_addr, tvb,
192 offset, 4, ~teredoh->th_iporgaddr);
200 /* Determine if there is a sub-dissector and call it. This has been */
201 /* separated into a stand alone routine to other protocol dissectors */
202 /* can call to it, ie. socks */
206 decode_teredo_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,proto_tree *tree, int th_header)
210 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
212 if (dissector_try_port(teredo_dissector_table, th_header, next_tvb, pinfo, tree))
215 call_dissector(data_handle,next_tvb, pinfo, tree);
219 dissect_teredo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
221 proto_tree *teredo_tree;
224 static e_teredohdr teredohstruct[4], *teredoh;
225 static int teredoh_count = 0;
228 if(teredoh_count>=4){
231 teredoh = &teredohstruct[teredoh_count];
233 if (check_col(pinfo->cinfo, COL_PROTOCOL))
234 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Teredo");
235 if (check_col(pinfo->cinfo, COL_INFO))
236 col_clear(pinfo->cinfo, COL_INFO);
239 ti = proto_tree_add_item(tree, proto_teredo, tvb, 0, -1, FALSE);
240 teredo_tree = proto_item_add_subtree(ti, ett_teredo);
245 teredoh->th_header = tvb_get_ntohs(tvb, offset);
247 if (teredoh->th_header == 1) {
248 offset = parse_teredo_auth(tvb, pinfo, teredo_tree,
250 teredoh->th_header = tvb_get_ntohs(tvb, offset);
253 teredoh->th_indtyp = 0;
255 if ( teredoh->th_header == 0 ) {
256 offset = parse_teredo_orig(tvb, pinfo, teredo_tree,
260 teredoh->th_ip_v_hl = tvb_get_guint8(tvb, offset);
262 decode_teredo_ports(tvb, offset, pinfo, tree, teredoh->th_header /* , teredoh->th_orgport*/);
263 tap_queue_packet(teredo_tap, pinfo, teredoh);
268 dissect_teredo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
273 if (!global_teredo_heur)
276 if (tvb_length_remaining(tvb, offset) < 40)
279 val = tvb_get_ntohs(tvb, offset);
281 if (val == 1) /* possible auth header */
287 idlen = tvb_get_guint8(tvb, offset);
290 aulen = tvb_get_guint8(tvb, offset);
293 if (tvb_length_remaining(tvb, offset) < idlen + aulen + 40)
296 offset += idlen + aulen;
298 val = tvb_get_ntohs(tvb, offset);
301 if (val == 0) /* origin indication */
305 if (tvb_length_remaining(tvb, offset) < 40)
308 val = tvb_get_ntohs(tvb, offset);
312 * We have to check upper-layer packet a little bit otherwise we will
313 * match -almost- *ANY* packet.
314 * These checks are in the Teredo specification by the way.
315 * Unfortunately, that will cause false-negative if the snaplen is too
316 * short to get the packet entirely.
318 if ((val >> 12) == 6) /* IPv6 header */
320 /* checks IPv6 payload length */
321 val = tvb_get_ntohs(tvb, offset + 4);
325 return FALSE; /* length too big for Teredo */
327 if (tvb_length_remaining(tvb, offset) != val)
328 return FALSE; /* length mismatch */
330 dissect_teredo (tvb, pinfo, tree);
334 return FALSE; /* not an IPv6 packet */
339 proto_register_teredo(void)
341 static hf_register_info hf[] = {
342 /* Authentication header */
344 { "Teredo Authentication header", "teredo.auth",
345 FT_NONE, BASE_NONE, NULL, 0x0,
346 "Teredo Authentication header", HFILL }},
348 { &hf_teredo_auth_idlen,
349 { "Client identifier length", "teredo.auth.idlen",
350 FT_UINT8, BASE_DEC, NULL, 0x0,
351 "Client identifier length (ID-len)", HFILL }},
353 { &hf_teredo_auth_aulen,
354 { "Authentication value length", "teredo.auth.aulen",
355 FT_UINT8, BASE_DEC, NULL, 0x0,
356 "Authentication value length (AU-len)", HFILL }},
358 { &hf_teredo_auth_id,
359 { "Client identifier", "teredo.auth.id",
360 FT_BYTES, BASE_NONE, NULL, 0x0,
361 "Client identifier (ID)", HFILL }},
363 { &hf_teredo_auth_value,
364 { "Authentication value", "teredo.auth.value",
365 FT_BYTES, BASE_NONE, NULL, 0x0,
366 "Authentication value (hash)", HFILL }},
368 { &hf_teredo_auth_nonce,
369 { "Nonce value", "teredo.auth.nonce",
370 FT_BYTES, BASE_NONE, NULL, 0x0,
371 "Nonce value prevents spoofing Teredo server.",
374 { &hf_teredo_auth_conf,
375 { "Confirmation byte", "teredo.auth.conf",
376 FT_BYTES, BASE_NONE, NULL, 0x0,
377 "Confirmation byte is zero upon successful authentication.",
380 /* Origin indication */
382 { "Teredo Origin Indication header", "teredo.orig",
383 FT_NONE, BASE_NONE, NULL, 0x0,
384 "Teredo Origin Indication", HFILL }},
386 { &hf_teredo_orig_port,
387 { "Origin UDP port", "teredo.orig.port",
388 FT_UINT16, BASE_DEC, NULL, 0x0,
389 "Origin UDP port", HFILL }},
391 { &hf_teredo_orig_addr,
392 { "Origin IPv4 address", "teredo.orig.addr",
393 FT_IPv4, BASE_NONE, NULL, 0x0,
394 "Origin IPv4 address", HFILL }},
397 static gint *ett[] = {
398 &ett_teredo, &ett_teredo_auth, &ett_teredo_orig
401 module_t *teredo_module;
403 proto_teredo = proto_register_protocol(
404 "Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
405 proto_register_field_array(proto_teredo, hf, array_length(hf));
406 proto_register_subtree_array(ett, array_length(ett));
408 /* subdissector code */
409 teredo_dissector_table = register_dissector_table("teredo","Teredo ", FT_UINT16, BASE_DEC);
411 teredo_module = prefs_register_protocol(proto_teredo, NULL);
413 prefs_register_bool_preference(teredo_module, "heuristic_teredo",
414 "Try to decode UDP packets as Teredo IPv6",
415 "Check this to decode IPv6 traffic between Teredo clients and "
417 &global_teredo_heur);
422 proto_reg_handoff_teredo(void)
424 dissector_handle_t teredo_handle;
426 teredo_handle = create_dissector_handle(dissect_teredo, proto_teredo);
427 data_handle = find_dissector("ipv6");
428 teredo_tap = register_tap("teredo");
430 dissector_add("udp.port", UDP_PORT_TEREDO, teredo_handle);
431 heur_dissector_add("udp", dissect_teredo_heur, proto_teredo);