Ethereal-dev: [Ethereal-dev] Heuristic Teredo packet dissection

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Rémi Denis-Courmont <courmisch@xxxxxxxxxx>
Date: Tue, 7 Sep 2004 18:39:34 +0200
 Hello,

A large chunk of Teredo traffic do not use the standard Teredo UDP port 
3544. I've made a patch against Ethereal's SVN trunk to add heuristic 
dissection for Teredo. Because I feared it could catch too much 
traffic, it's disabled by default and can be enabled as a preference as 
some other heuristic dissectors.

If you're looking for sample Teredo packets capture to test with, you 
can find one example there:
http://people.via.ecp.fr/~rem/miredo/dump/hotmail-restricted-nat.pcap

Sincerely,

-- 
Rémi Denis-Courmont
http://www.simphalempin.com/home/infos/cv.shtml.fr
Index: epan/dissectors/packet-teredo.c
===================================================================
--- epan/dissectors/packet-teredo.c	(revision 11820)
+++ epan/dissectors/packet-teredo.c	(working copy)
@@ -81,6 +81,9 @@
 /*static heur_dissector_list_t heur_subdissector_list;*/
 static dissector_handle_t data_handle;
 
+static gboolean global_teredo_heur = FALSE;
+
+
 static int
 parse_teredo_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 			int offset, e_teredohdr *teredoh)
@@ -250,6 +253,78 @@
 	tap_queue_packet(teredo_tap, pinfo, teredoh);    
 }
 
+
+static gboolean
+dissect_teredo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	guint16 val;
+	int offset = 0;
+
+	if (!global_teredo_heur)
+		return FALSE;
+
+	if (tvb_length_remaining(tvb, offset) < 40)
+		return FALSE;
+
+	val = tvb_get_ntohs(tvb, offset);
+
+	if (val == 1) /* possible auth header */
+	{
+		guint8 idlen, aulen;
+
+		offset += 2;
+
+		idlen = tvb_get_guint8(tvb, offset);
+		offset++;
+
+		aulen = tvb_get_guint8(tvb, offset);
+		offset += 10;
+
+		if (tvb_length_remaining(tvb, offset) < idlen + aulen + 40)
+			return FALSE;
+
+		offset += idlen + aulen;
+
+		val = tvb_get_ntohs(tvb, offset);
+	}
+
+	if (val == 0) /* origin indication */
+	{
+		offset += 8;
+
+		if (tvb_length_remaining(tvb, offset) < 40)
+			return FALSE;
+
+		val = tvb_get_ntohs(tvb, offset);
+	}
+
+	/* 
+	 * We have to check upper-layer packet a little bit otherwise we will
+	 * match -almost- *ANY* packet.
+	 * These checks are in the Teredo specification by the way.
+	 * Unfortunately, that will cause false-negative if the snaplen is too
+	 * short to get the packet entirely.
+	 */
+	if ((val >> 12) == 6) /* IPv6 header */
+	{
+		/* checks IPv6 payload length */
+		val = tvb_get_ntohs(tvb, offset + 4);
+		offset += 40;
+
+		if (val > 65467)
+			return FALSE; /* length too big for Teredo */
+
+		if (tvb_length_remaining(tvb, offset) != val)
+			return FALSE; /* length mismatch */
+
+		dissect_teredo (tvb, pinfo, tree);
+		return TRUE;
+	}
+
+	return FALSE; /* not an IPv6 packet */
+}
+
+
 void
 proto_register_teredo(void)
 {
@@ -313,6 +388,8 @@
 		&ett_teredo, &ett_teredo_auth, &ett_teredo_orig
 	};
 
+	module_t *teredo_module;
+
 	proto_teredo = proto_register_protocol(
 		"Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
 	proto_register_field_array(proto_teredo, hf, array_length(hf));
@@ -320,8 +397,15 @@
 
 /* subdissector code */
 	teredo_dissector_table = register_dissector_table("teredo","Teredo ", FT_UINT16, BASE_DEC);
-/*	register_heur_dissector_list("teredo.heur", &heur_subdissector_list); */
 
+	teredo_module = prefs_register_protocol(proto_teredo, NULL);
+
+	prefs_register_bool_preference(teredo_module, "heuristic_teredo",
+		"Try to decode UDP packets as Teredo IPv6",
+		"Check this to decode IPv6 traffic between Teredo clients and "
+		"relays",
+		&global_teredo_heur);
+
 }
 
 void
@@ -334,5 +418,6 @@
 	teredo_tap    = register_tap("teredo");
 
 	dissector_add("udp.port", UDP_PORT_TEREDO, teredo_handle);
+	heur_dissector_add("udp", dissect_teredo_heur, proto_teredo);
 }