Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: [Wireshark-dev] [PATCH] draft-ietf-behave-rfc3489bis-07

From: Marc Petit-Huguenin <marc@xxxxxxxxxxxxxxxxxx>
Date: Mon, 09 Jul 2007 14:05:45 -0700
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

This is an update to the STUN2 dissector using the last draft,
draft-ietf-behave-rfc3489bis-07.

Here is the changelog:

* My employer is now sponsoring this work, so added a copyright line.
* Added a comment for each method/attribute with the RFC/I-D where is
  it defined, so it will be easier to add new STUN usages.
* Removed the SHARED-SECRET method.
* Removed the PASSWORD and REFRESH-INTERVAL attributes.
* Changed "Response" to "Success Response".
* Changed "Error Reason Phase" to "Error Reason Phrase".
* Added reassembly for TCP segments on STUN2.
* Updated STUN acronym expansion.
* Renamed STUN2_ERROR to ERROR_RESPONSE.
* Changed the value of attribute FINGERPRINT from 0x8025 to 0x8028.
* Display if an unknown attribute is comprehension-optional or
  comprehension-required.
* Reorganized order of attributes in the dissector code.
* The message length is now displayed in decimal.


I will update the Wiki page accordingly.

- --
Marc Petit-Huguenin           [                                 ]
Home: marc@xxxxxxxxxxxxxxxxxx [RFC1855-compliant space for rent ]
Work: marc@xxxxxxx            [                                 ]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGkqMp9RoMZyVa61cRAqVfAJ0RoNN8GDFXW/KlNqOcA0ncbRhdxACgjfAJ
QknuNq6Sc35RDLj6AJLlFKs=
=3qRQ
-----END PGP SIGNATURE-----
Index: epan/dissectors/packet-stun2.c
===================================================================
--- epan/dissectors/packet-stun2.c	(revision 22276)
+++ epan/dissectors/packet-stun2.c	(working copy)
@@ -1,7 +1,8 @@
 /* packet-stun2.c
- * Routines for Simple Traversal Underneath NAT dissection
+ * Routines for Session Traversal Utilities for NAT (STUN) dissection
  * Copyright 2003, Shiang-Ming Huang <smhuang@xxxxxxxxxxxxxxxxxxxx>
  * Copyright 2006, Marc Petit-Huguenin <marc@xxxxxxxxxxxxxxxxxx>
+ * Copyright 2007, 8x8 Inc. <petithug@xxxxxxx>
  *
  * $Id$
  *
@@ -23,7 +24,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Please refer to draft-ietf-behave-rfc3489bis-05 for protocol detail.
+ * Please refer to draft-ietf-behave-rfc3489bis-07 for protocol detail.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -77,27 +78,24 @@
 #define REQUEST		0x0000
 #define INDICATION	0x0001
 #define RESPONSE	0x0010
-#define STUN2_ERROR	0x0011  /* use prefix to prevent redefinition from wingdi.h */
+#define ERROR_RESPONSE	0x0011
 
-/* Message methods */
-#define METHOD_MASK	0xCEEF
-#define BINDING		0x0001
-#define SHARED_SECRET	0x0002
+/* Request/Response Transactions */
+#define METHOD_MASK		0xCEEF
+#define BINDING			0x0001	/* draft-ietf-behave-rfc3489bis-07 */
 
 /* Attribute Types */
-#define MAPPED_ADDRESS		0x0001
-#define USERNAME		0x0006
-#define PASSWORD		0x0007
-#define MESSAGE_INTEGRITY	0x0008
-#define ERROR_CODE		0x0009
-#define UNKNOWN_ATTRIBUTES	0x000a
-#define REALM			0x0014
-#define NONCE			0x0015
-#define XOR_MAPPED_ADDRESS	0x0020
-#define SERVER			0x8022
-#define ALTERNATE_SERVER	0x8023
-#define REFRESH_INTERVAL	0x8024
-#define FINGERPRINT		0x8025
+#define MAPPED_ADDRESS		0x0001	/* draft-ietf-behave-rfc3489bis-07 */
+#define USERNAME		0x0006	/* draft-ietf-behave-rfc3489bis-07 */
+#define MESSAGE_INTEGRITY	0x0008	/* draft-ietf-behave-rfc3489bis-07 */
+#define ERROR_CODE		0x0009	/* draft-ietf-behave-rfc3489bis-07 */
+#define UNKNOWN_ATTRIBUTES	0x000a	/* draft-ietf-behave-rfc3489bis-07 */
+#define REALM			0x0014	/* draft-ietf-behave-rfc3489bis-07 */
+#define NONCE			0x0015	/* draft-ietf-behave-rfc3489bis-07 */
+#define XOR_MAPPED_ADDRESS	0x0020	/* draft-ietf-behave-rfc3489bis-07 */
+#define SERVER			0x8022	/* draft-ietf-behave-rfc3489bis-07 */
+#define ALTERNATE_SERVER	0x8023	/* draft-ietf-behave-rfc3489bis-07 */
+#define FINGERPRINT		0x8028	/* draft-ietf-behave-rfc3489bis-07 */
 
 /* Initialize the subtree pointers */
 static gint ett_stun2 = -1;
@@ -114,21 +112,19 @@
 static const value_string classes[] = {
 	{REQUEST, "Request"},
 	{INDICATION, "Indication"},
-	{RESPONSE, "Response"},
-	{STUN2_ERROR, "Error Response"},
+	{RESPONSE, "Success Response"},
+	{ERROR_RESPONSE, "Error Response"},
 	{0x00, NULL}
 };
 
 static const value_string methods[] = {
 	{BINDING, "Binding"},
-	{SHARED_SECRET, "Shared Secret"},
 	{0x00, NULL}
 };
 
 static const value_string attributes[] = {
 	{MAPPED_ADDRESS, "MAPPED-ADDRESS"},
 	{USERNAME, "USERNAME"},
-	{PASSWORD, "PASSWORD"},
 	{MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY"},
 	{ERROR_CODE, "ERROR-CODE"},
 	{UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES"},
@@ -137,7 +133,6 @@
 	{XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS"},
 	{SERVER, "SERVER"},
 	{ALTERNATE_SERVER, "ALTERNATE-SERVER"},
-	{REFRESH_INTERVAL, "REFRESH-INTERVAL"},
 	{FINGERPRINT, "FINGERPRINT"},
 	{0x00, NULL}
 };
@@ -148,8 +143,13 @@
 	{0x00, NULL}
 };
 
+static guint get_stun2_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
+{
+	return (guint)tvb_get_ntohs(tvb, offset+2) + 20;
+}
+
 static int
-dissect_stun2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_stun2_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
 	proto_item *ti;
 	proto_item *ta;
@@ -231,7 +231,7 @@
 				ta = proto_tree_add_text(att_type_tree, tvb, offset,
 					ATTR_HDR_LEN+att_length,
 					"Attribute: %s",
-					val_to_str(att_type, attributes, "Unknown (0x%04x)"));
+					val_to_str(att_type, attributes, att_type & 0x8000 ? "Unknown (0x%4x) - Comprehension-optional" : "Unknown (0x%04x)- Comprehension-required"));
 				att_tree = proto_item_add_subtree(ta, ett_stun2_att);
 
 				proto_tree_add_uint(att_tree, stun2_att_type, tvb,
@@ -278,36 +278,12 @@
 							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
 
-					case PASSWORD:
-						proto_tree_add_item(att_tree, stun2_att_password, tvb, offset, att_length, FALSE);
-						if (att_length % 4 != 0)
-							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
-						break;
-
-					case NONCE:
-						proto_tree_add_item(att_tree, stun2_att_nonce, tvb, offset, att_length, FALSE);
-						if (att_length % 4 != 0)
-							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
-						break;
-
-					case REALM:
-						proto_tree_add_item(att_tree, stun2_att_realm, tvb, offset, att_length, FALSE);
-						if (att_length % 4 != 0)
-							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
-						break;
-
 					case MESSAGE_INTEGRITY:
 						if (att_length < 20)
 							break;
 						proto_tree_add_item(att_tree, stun2_att_hmac, tvb, offset, att_length, FALSE);
 						break;
 
-					case FINGERPRINT:
-						if (att_length < 4)
-							break;
-						proto_tree_add_item(att_tree, stun2_att_crc32, tvb, offset, att_length, FALSE);
-						break;
-
 					case ERROR_CODE:
 						if (att_length < 3)
 							break;
@@ -329,12 +305,18 @@
 							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
 
-					case SERVER:
-						proto_tree_add_item(att_tree, stun2_att_server, tvb, offset, att_length, FALSE);
+					case REALM:
+						proto_tree_add_item(att_tree, stun2_att_realm, tvb, offset, att_length, FALSE);
 						if (att_length % 4 != 0)
 							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
 
+					case NONCE:
+						proto_tree_add_item(att_tree, stun2_att_nonce, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+						break;
+
 					case XOR_MAPPED_ADDRESS:
 						if (att_length < 2)
 							break;
@@ -377,10 +359,16 @@
 							}
 						break;
 
-					case REFRESH_INTERVAL:
+					case SERVER:
+						proto_tree_add_item(att_tree, stun2_att_server, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun2_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+						break;
+
+					case FINGERPRINT:
 						if (att_length < 4)
 							break;
-						proto_tree_add_item(att_tree, stun2_att_refresh_interval, tvb, offset, 4, FALSE);
+						proto_tree_add_item(att_tree, stun2_att_crc32, tvb, offset, att_length, FALSE);
 						break;
 
 					default:
@@ -398,11 +386,23 @@
 	return tvb_length(tvb);
 }
 
+static int
+dissect_stun2_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	dissect_stun2_message(tvb, pinfo, tree);
+}
 
+static int
+dissect_stun2_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	tcp_dissect_pdus(tvb, pinfo, tree, TRUE, STUN2_HDR_LEN,
+			get_stun2_message_len, dissect_stun2_message);
+}
+
 static gboolean
 dissect_stun2_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-	if (dissect_stun2(tvb, pinfo, tree) == 0)
+	if (dissect_stun2_message(tvb, pinfo, tree) == 0)
 		return FALSE;
 
 	return TRUE;
@@ -422,7 +422,7 @@
 		},
 		{ &hf_stun2_length,
 			{ "Message Length",	"stun2.length",	FT_UINT16,
-			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
+			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
 		{ &hf_stun2_cookie,
 			{ "Message Cookie",	"stun2.cookie",	FT_BYTES,
@@ -469,10 +469,6 @@
 			{ "Padding",	"stun2.att.padding",	FT_UINT16,
 			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun2_att_password,
-			{ "Password",	"stun2.att.password",	FT_STRING,
-			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
-		},
 		{ &stun2_att_hmac,
 			{ "HMAC-SHA1",	"stun2.att.hmac",	FT_BYTES,
 			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
@@ -490,7 +486,7 @@
 			BASE_DEC, 	NULL,	0x0,	"",	HFILL}
 		},
 		{ &stun2_att_error_reason,
-			{ "Error Reason Phase","stun2.att.error.reason",	FT_STRING,
+			{ "Error Reason Phrase","stun2.att.error.reason",	FT_STRING,
 			BASE_NONE, 	NULL,	0x0,	"",	HFILL}
 		},
 		{ &stun2_att_realm,
@@ -521,10 +517,6 @@
 			{ "Server software","stun2.att.server",	FT_STRING,
 			BASE_NONE, 	NULL,	0x0,	"",	HFILL}
  		},
-		{ &stun2_att_refresh_interval,
-			{ "Refresh Interval","stun2.att.refresh-interval",	FT_UINT16,
-			BASE_DEC, 	NULL,	0x0,	"",	HFILL}
- 		},
 		{ &stun2_att_value,
 			{ "Value",	"stun2.value",	FT_BYTES,
 			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
@@ -539,26 +531,25 @@
 	};
 
 /* Register the protocol name and description */
-	proto_stun2 = proto_register_protocol("Simple Traversal Underneath NAT",
+	proto_stun2 = proto_register_protocol("Session Traversal Utilities for NAT",
 	    "STUN2", "stun2");
 
 /* Required function calls to register the header fields and subtrees used */
 	proto_register_field_array(proto_stun2, hf, array_length(hf));
 	proto_register_subtree_array(ett, array_length(ett));
-
-	new_register_dissector("stun2", dissect_stun2, proto_stun2);
 }
 
-
 void
 proto_reg_handoff_stun2(void)
 {
-	dissector_handle_t stun2_handle;
+	dissector_handle_t stun2_tcp_handle;
+	dissector_handle_t stun2_udp_handle;
 
-	stun2_handle = find_dissector("stun2");
+	stun2_tcp_handle = create_dissector_handle(dissect_stun2_tcp, proto_stun2);
+	stun2_udp_handle = create_dissector_handle(dissect_stun2_udp, proto_stun2);
 
-	dissector_add("tcp.port", TCP_PORT_STUN2, stun2_handle);
-	dissector_add("udp.port", UDP_PORT_STUN2, stun2_handle);
+	dissector_add("tcp.port", TCP_PORT_STUN2, stun2_tcp_handle);
+	dissector_add("udp.port", UDP_PORT_STUN2, stun2_udp_handle);
 
 	heur_dissector_add("udp", dissect_stun2_heur, proto_stun2);
 	heur_dissector_add("tcp", dissect_stun2_heur, proto_stun2);