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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <epan/packet.h>
35 #include <epan/addr_resolv.h>
36 #include <epan/ipproto.h>
37 #include <epan/prefs.h>
39 #include "packet-ip.h"
42 #define UDP_PORT_TEREDO 3544
44 static int teredo_tap
= -1;
46 static int proto_teredo
= -1;
48 static int hf_teredo_auth
= -1;
49 static int hf_teredo_auth_idlen
= -1;
50 static int hf_teredo_auth_aulen
= -1;
51 static int hf_teredo_auth_id
= -1;
52 static int hf_teredo_auth_value
= -1;
53 static int hf_teredo_auth_nonce
= -1;
54 static int hf_teredo_auth_conf
= -1;
55 static int hf_teredo_orig
= -1;
56 static int hf_teredo_orig_port
= -1;
57 static int hf_teredo_orig_addr
= -1;
59 static gint ett_teredo
= -1;
60 static gint ett_teredo_auth
= -1, ett_teredo_orig
= -1;
75 static dissector_table_t teredo_dissector_table
;
76 /*static heur_dissector_list_t heur_subdissector_list;*/
77 static dissector_handle_t data_handle
;
79 static gboolean global_teredo_heur
= FALSE
;
83 parse_teredo_auth(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
84 int offset
, e_teredohdr
*teredoh
)
88 col_append_sep_str (pinfo
->cinfo
, COL_INFO
, ", ",
89 "Authentication header");
91 teredoh
->th_indtyp
= 1;
94 idlen
= tvb_get_guint8(tvb
, offset
);
95 teredoh
->th_cidlen
= idlen
;
98 aulen
= tvb_get_guint8(tvb
, offset
);
99 teredoh
->th_authdlen
= aulen
;
105 ti
= proto_tree_add_item(tree
, hf_teredo_auth
, tvb
, offset
-4,
106 13 + idlen
+ aulen
, ENC_NA
);
107 tree
= proto_item_add_subtree(ti
, ett_teredo_auth
);
109 proto_tree_add_item(tree
, hf_teredo_auth_idlen
, tvb
,
110 offset
- 2, 1, ENC_BIG_ENDIAN
);
111 proto_tree_add_item(tree
, hf_teredo_auth_aulen
, tvb
,
112 offset
- 1, 1, ENC_BIG_ENDIAN
);
114 /* idlen is usually zero */
116 proto_tree_add_item(tree
, hf_teredo_auth_id
, tvb
,
117 offset
, idlen
, ENC_NA
);
121 /* aulen is usually zero */
123 proto_tree_add_item(tree
, hf_teredo_auth_value
, tvb
,
124 offset
, aulen
, ENC_NA
);
128 proto_tree_add_item(tree
, hf_teredo_auth_nonce
, tvb
,
132 proto_tree_add_item(tree
, hf_teredo_auth_conf
, tvb
,
137 offset
+= idlen
+ aulen
+ 9;
139 tvb_memcpy(tvb
, teredoh
->th_nonce
, offset
- 9, 8);
140 teredoh
->th_conf
= tvb_get_guint8(tvb
, offset
- 1);
147 parse_teredo_orig(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
148 int offset
, e_teredohdr
*teredoh
)
150 proto_item
*ti
= NULL
;
152 col_append_sep_str (pinfo
->cinfo
, COL_INFO
, ", ",
153 "Origin indication");
156 ti
= proto_tree_add_item(tree
, hf_teredo_orig
, tvb
, offset
,
158 tree
= proto_item_add_subtree(ti
, ett_teredo_orig
);
162 teredoh
->th_orgport
= tvb_get_ntohs(tvb
, offset
);
165 * The "usual arithmetic conversions" will convert
166 * "teredoh->th_orgport" to an "int" (because all
167 * "unsigned short" values will fit in an "int"),
168 * which will zero-extend it. This means that
169 * complementing it will turn all the zeroes in
170 * the upper 16 bits into ones; we just want the
171 * lower 16 bits (containing the port number)
172 * complemented, with the result zero-extended.
174 * That's what the cast is for.
176 proto_tree_add_uint(tree
, hf_teredo_orig_port
, tvb
,
178 (guint16
)~teredoh
->th_orgport
);
182 teredoh
->th_iporgaddr
= tvb_get_ipv4(tvb
, offset
);
184 proto_tree_add_ipv4(tree
, hf_teredo_orig_addr
, tvb
,
185 offset
, 4, ~teredoh
->th_iporgaddr
);
193 /* Determine if there is a sub-dissector and call it. This has been */
194 /* separated into a stand alone routine to other protocol dissectors */
195 /* can call to it, ie. socks */
199 decode_teredo_ports(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,proto_tree
*tree
, int th_header
)
203 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
205 if (dissector_try_uint(teredo_dissector_table
, th_header
, next_tvb
, pinfo
, tree
))
208 call_dissector(data_handle
,next_tvb
, pinfo
, tree
);
212 dissect_teredo(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
214 proto_tree
*teredo_tree
;
217 static e_teredohdr teredohstruct
[4], *teredoh
;
218 static int teredoh_count
= 0;
221 if(teredoh_count
>=4){
224 teredoh
= &teredohstruct
[teredoh_count
];
226 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Teredo");
227 col_clear(pinfo
->cinfo
, COL_INFO
);
230 ti
= proto_tree_add_item(tree
, proto_teredo
, tvb
, 0, -1, ENC_NA
);
231 teredo_tree
= proto_item_add_subtree(ti
, ett_teredo
);
236 teredoh
->th_header
= tvb_get_ntohs(tvb
, offset
);
238 if (teredoh
->th_header
== 1) {
239 offset
= parse_teredo_auth(tvb
, pinfo
, teredo_tree
,
241 teredoh
->th_header
= tvb_get_ntohs(tvb
, offset
);
244 teredoh
->th_indtyp
= 0;
246 if ( teredoh
->th_header
== 0 ) {
247 offset
= parse_teredo_orig(tvb
, pinfo
, teredo_tree
,
251 teredoh
->th_ip_v_hl
= tvb_get_guint8(tvb
, offset
);
253 decode_teredo_ports(tvb
, offset
, pinfo
, tree
, teredoh
->th_header
/* , teredoh->th_orgport*/);
254 tap_queue_packet(teredo_tap
, pinfo
, teredoh
);
259 dissect_teredo_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
264 if (!global_teredo_heur
)
267 if (tvb_length_remaining(tvb
, offset
) < 40)
270 val
= tvb_get_ntohs(tvb
, offset
);
272 if (val
== 1) /* possible auth header */
278 idlen
= tvb_get_guint8(tvb
, offset
);
281 aulen
= tvb_get_guint8(tvb
, offset
);
284 if (tvb_length_remaining(tvb
, offset
) < idlen
+ aulen
+ 40)
287 offset
+= idlen
+ aulen
;
289 val
= tvb_get_ntohs(tvb
, offset
);
292 if (val
== 0) /* origin indication */
296 if (tvb_length_remaining(tvb
, offset
) < 40)
299 val
= tvb_get_ntohs(tvb
, offset
);
303 * We have to check upper-layer packet a little bit otherwise we will
304 * match -almost- *ANY* packet.
305 * These checks are in the Teredo specification by the way.
306 * Unfortunately, that will cause false-negative if the snaplen is too
307 * short to get the packet entirely.
309 if ((val
>> 12) == 6) /* IPv6 header */
311 /* checks IPv6 payload length */
312 val
= tvb_get_ntohs(tvb
, offset
+ 4);
316 return FALSE
; /* length too big for Teredo */
318 if (tvb_length_remaining(tvb
, offset
) != val
)
319 return FALSE
; /* length mismatch */
321 dissect_teredo (tvb
, pinfo
, tree
);
325 return FALSE
; /* not an IPv6 packet */
330 proto_register_teredo(void)
332 static hf_register_info hf
[] = {
333 /* Authentication header */
335 { "Teredo Authentication header", "teredo.auth",
336 FT_NONE
, BASE_NONE
, NULL
, 0x0,
339 { &hf_teredo_auth_idlen
,
340 { "Client identifier length", "teredo.auth.idlen",
341 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
342 "Client identifier length (ID-len)", HFILL
}},
344 { &hf_teredo_auth_aulen
,
345 { "Authentication value length", "teredo.auth.aulen",
346 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
347 "Authentication value length (AU-len)", HFILL
}},
349 { &hf_teredo_auth_id
,
350 { "Client identifier", "teredo.auth.id",
351 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
352 "Client identifier (ID)", HFILL
}},
354 { &hf_teredo_auth_value
,
355 { "Authentication value", "teredo.auth.value",
356 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
357 "Authentication value (hash)", HFILL
}},
359 { &hf_teredo_auth_nonce
,
360 { "Nonce value", "teredo.auth.nonce",
361 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
362 "Nonce value prevents spoofing Teredo server.",
365 { &hf_teredo_auth_conf
,
366 { "Confirmation byte", "teredo.auth.conf",
367 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
368 "Confirmation byte is zero upon successful authentication.",
371 /* Origin indication */
373 { "Teredo Origin Indication header", "teredo.orig",
374 FT_NONE
, BASE_NONE
, NULL
, 0x0,
375 "Teredo Origin Indication", HFILL
}},
377 { &hf_teredo_orig_port
,
378 { "Origin UDP port", "teredo.orig.port",
379 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
382 { &hf_teredo_orig_addr
,
383 { "Origin IPv4 address", "teredo.orig.addr",
384 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
388 static gint
*ett
[] = {
389 &ett_teredo
, &ett_teredo_auth
, &ett_teredo_orig
392 module_t
*teredo_module
;
394 proto_teredo
= proto_register_protocol(
395 "Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
396 proto_register_field_array(proto_teredo
, hf
, array_length(hf
));
397 proto_register_subtree_array(ett
, array_length(ett
));
399 /* subdissector code */
400 teredo_dissector_table
= register_dissector_table("teredo","Teredo ", FT_UINT16
, BASE_DEC
);
402 teredo_module
= prefs_register_protocol(proto_teredo
, NULL
);
404 prefs_register_bool_preference(teredo_module
, "heuristic_teredo",
405 "Try to decode UDP packets as Teredo IPv6",
406 "Check this to decode IPv6 traffic between Teredo clients and "
408 &global_teredo_heur
);
413 proto_reg_handoff_teredo(void)
415 dissector_handle_t teredo_handle
;
417 teredo_handle
= create_dissector_handle(dissect_teredo
, proto_teredo
);
418 data_handle
= find_dissector("ipv6");
419 teredo_tap
= register_tap("teredo");
421 dissector_add_uint("udp.port", UDP_PORT_TEREDO
, teredo_handle
);
422 heur_dissector_add("udp", dissect_teredo_heur
, proto_teredo
);