HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-teredo.c
blob4296be66cb5af689223563c6a5e344a12464cc9b
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 * $Id$
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.
30 #include "config.h"
32 #include <glib.h>
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"
40 #include <epan/tap.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;
62 typedef struct {
63 guint16 th_indtyp;
64 guint8 th_cidlen;
65 guint8 th_authdlen;
66 guint8 th_nonce[8];
67 guint8 th_conf;
69 guint8 th_ip_v_hl;
70 guint16 th_header;
71 guint16 th_orgport;
72 guint32 th_iporgaddr;
73 } e_teredohdr;
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;
82 static int
83 parse_teredo_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
84 int offset, e_teredohdr *teredoh)
86 guint idlen, aulen;
88 col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
89 "Authentication header");
91 teredoh->th_indtyp = 1;
92 offset += 2;
94 idlen = tvb_get_guint8(tvb, offset);
95 teredoh->th_cidlen = idlen;
96 offset++;
98 aulen = tvb_get_guint8(tvb, offset);
99 teredoh->th_authdlen = aulen;
100 offset++;
102 if (tree) {
103 proto_item *ti;
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 */
115 if (idlen) {
116 proto_tree_add_item(tree, hf_teredo_auth_id, tvb,
117 offset, idlen, ENC_NA);
118 offset += idlen;
121 /* aulen is usually zero */
122 if (aulen) {
123 proto_tree_add_item(tree, hf_teredo_auth_value, tvb,
124 offset, aulen, ENC_NA);
125 offset += aulen;
128 proto_tree_add_item(tree, hf_teredo_auth_nonce, tvb,
129 offset, 8, ENC_NA);
130 offset += 8;
132 proto_tree_add_item(tree, hf_teredo_auth_conf, tvb,
133 offset, 1, ENC_NA);
134 offset++;
136 else
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);
142 return offset;
146 static int
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");
155 if (tree) {
156 ti = proto_tree_add_item(tree, hf_teredo_orig, tvb, offset,
157 8, ENC_NA);
158 tree = proto_item_add_subtree(ti, ett_teredo_orig);
160 offset += 2;
162 teredoh->th_orgport = tvb_get_ntohs(tvb, offset);
163 if (tree) {
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,
177 offset, 2,
178 (guint16)~teredoh->th_orgport);
180 offset += 2;
182 teredoh->th_iporgaddr = tvb_get_ipv4(tvb, offset);
183 if (tree) {
184 proto_tree_add_ipv4(tree, hf_teredo_orig_addr, tvb,
185 offset, 4, ~teredoh->th_iporgaddr);
187 offset += 4;
189 return offset;
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 */
198 static void
199 decode_teredo_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,proto_tree *tree, int th_header)
201 tvbuff_t *next_tvb;
203 next_tvb = tvb_new_subset_remaining(tvb, offset);
205 if (dissector_try_uint(teredo_dissector_table, th_header, next_tvb, pinfo, tree))
206 return;
208 call_dissector(data_handle,next_tvb, pinfo, tree);
211 static void
212 dissect_teredo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
214 proto_tree *teredo_tree;
215 proto_item *ti;
216 int offset = 0;
217 static e_teredohdr teredohstruct[4], *teredoh;
218 static int teredoh_count = 0;
220 teredoh_count++;
221 if(teredoh_count>=4){
222 teredoh_count=0;
224 teredoh = &teredohstruct[teredoh_count];
226 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Teredo");
227 col_clear(pinfo->cinfo, COL_INFO);
229 if (tree) {
230 ti = proto_tree_add_item(tree, proto_teredo, tvb, 0, -1, ENC_NA);
231 teredo_tree = proto_item_add_subtree(ti, ett_teredo);
233 else
234 teredo_tree = NULL;
236 teredoh->th_header = tvb_get_ntohs(tvb, offset);
238 if (teredoh->th_header == 1) {
239 offset = parse_teredo_auth(tvb, pinfo, teredo_tree,
240 offset, teredoh);
241 teredoh->th_header = tvb_get_ntohs(tvb, offset);
243 else
244 teredoh->th_indtyp = 0;
246 if ( teredoh->th_header == 0 ) {
247 offset = parse_teredo_orig(tvb, pinfo, teredo_tree,
248 offset, teredoh);
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);
258 static gboolean
259 dissect_teredo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
261 guint16 val;
262 int offset = 0;
264 if (!global_teredo_heur)
265 return FALSE;
267 if (tvb_length_remaining(tvb, offset) < 40)
268 return FALSE;
270 val = tvb_get_ntohs(tvb, offset);
272 if (val == 1) /* possible auth header */
274 guint8 idlen, aulen;
276 offset += 2;
278 idlen = tvb_get_guint8(tvb, offset);
279 offset++;
281 aulen = tvb_get_guint8(tvb, offset);
282 offset += 10;
284 if (tvb_length_remaining(tvb, offset) < idlen + aulen + 40)
285 return FALSE;
287 offset += idlen + aulen;
289 val = tvb_get_ntohs(tvb, offset);
292 if (val == 0) /* origin indication */
294 offset += 8;
296 if (tvb_length_remaining(tvb, offset) < 40)
297 return FALSE;
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);
313 offset += 40;
315 if (val > 65467)
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);
322 return TRUE;
325 return FALSE; /* not an IPv6 packet */
329 void
330 proto_register_teredo(void)
332 static hf_register_info hf[] = {
333 /* Authentication header */
334 { &hf_teredo_auth,
335 { "Teredo Authentication header", "teredo.auth",
336 FT_NONE, BASE_NONE, NULL, 0x0,
337 NULL, HFILL }},
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.",
363 HFILL }},
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.",
369 HFILL }},
371 /* Origin indication */
372 { &hf_teredo_orig,
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,
380 NULL, HFILL }},
382 { &hf_teredo_orig_addr,
383 { "Origin IPv4 address", "teredo.orig.addr",
384 FT_IPv4, BASE_NONE, NULL, 0x0,
385 NULL, HFILL }},
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 "
407 "relays",
408 &global_teredo_heur);
412 void
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);