Wireshark-dev: [Wireshark-dev] [PATCH] draft-ietf-behave-rfc3489bis-05
From: Marc Petit-Huguenin <marc@xxxxxxxxxxxxxxxxxx>
Date: Mon, 27 Nov 2006 20:12:44 -0800
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

This is a new dissector for STUN v2, that is currently in WGLC at the IETF.

The packet-stun.c file must be copied into packet-stun2.c before
applying this patch.

I also attached a capture file that contains various STUN and STUN v2
packets.

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

iD8DBQFFa7c79RoMZyVa61cRAlHYAKCG0MGdxDc2+IM+Cd4EJ44MEbXeQwCfQT1j
sjLDLhp43gxwU/wqzZJCmg4=
=+333
-----END PGP SIGNATURE-----
Index: epan/dissectors/packet-stun2.c
===================================================================
--- epan/dissectors/packet-stun2.c	(revision 19966)
+++ epan/dissectors/packet-stun2.c	(working copy)
@@ -1,29 +1,29 @@
-/* packet-stun.c
- * Routines for Simple Traversal of UDP Through NAT dissection
+/* packet-stun2.c
+ * Routines for Simple Traversal Underneath NAT dissection
  * Copyright 2003, Shiang-Ming Huang <smhuang@xxxxxxxxxxxxxxxxxxxx>
+ * Copyright 2006, Marc Petit-Huguenin <marc@xxxxxxxxxxxxxxxxxx>
  *
  * $Id$
  *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@xxxxxxxxxxxxx>
  * Copyright 1998 Gerald Combs
- * 
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * 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 RFC 3489 for protocol detail.
- * (supports extra message attributes described in draft-ietf-behave-rfc3489bis-00)
+ * Please refer to draft-ietf-behave-rfc3489bis-05 for protocol detail.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -41,144 +41,104 @@
 /* Initialize the protocol and registered fields */
 static int proto_stun = -1;
 
-static int hf_stun_type = -1;		/* STUN message header */
+static int hf_stun_class = -1;
+static int hf_stun_method = -1;
 static int hf_stun_length = -1;
+static int hf_stun_cookie = -1;
 static int hf_stun_id = -1;
 static int hf_stun_att = -1;
 
 static int stun_att_type = -1;		/* STUN attribute fields */
 static int stun_att_length = -1;
-static int stun_att_value = -1;
 static int stun_att_family = -1;
 static int stun_att_ipv4 = -1;
 static int stun_att_ipv6 = -1;
 static int stun_att_port = -1;
-static int stun_att_change_ip = -1;
-static int stun_att_change_port = -1;
-static int stun_att_unknown = -1;
+static int stun_att_username = -1;
+static int stun_att_padding = -1;
+static int stun_att_password = -1;
+static int stun_att_hmac = -1;
+static int stun_att_crc32 = -1;
 static int stun_att_error_class = -1;
 static int stun_att_error_number = -1;
 static int stun_att_error_reason = -1;
-static int stun_att_server_string = -1;
+static int stun_att_realm = -1;
+static int stun_att_nonce = -1;
+static int stun_att_unknown = -1;
 static int stun_att_xor_ipv4 = -1;
 static int stun_att_xor_ipv6 = -1;
 static int stun_att_xor_port = -1;
-static int stun_att_lifetime = -1;
-static int stun_att_magic_cookie = -1;
-static int stun_att_bandwidth = -1;
-static int stun_att_data = -1;
+static int stun_att_server = -1;
+static int stun_att_refresh_interval = -1;
+static int stun_att_value = -1;
 
+/* Message classes */
+#define CLASS_MASK	0xC110
+#define REQUEST		0x0000
+#define INDICATION	0x0001
+#define RESPONSE	0x0010
+#define ERROR		0x0011
 
+/* Message methods */
+#define METHOD_MASK		0xCEEF
+#define BINDING			0x0001
+#define SHARED_SECRET	0x0002
 
-/* Message Types */
-#define BINDING_REQUEST			0x0001
-#define BINDING_RESPONSE		0x0101
-#define BINDING_ERROR_RESPONSE		0x0111
-#define SHARED_SECRET_REQUEST		0x0002
-#define SHARED_SECRET_RESPONSE		0x0102
-#define SHARED_SECRET_ERROR_RESPONSE	0x1112
-#define ALLOCATE_REQUEST		0x0003
-#define ALLOCATE_RESPONSE		0x0103
-#define ALLOCATE_ERROR_RESPONSE		0x0113
-#define SEND_REQUEST			0x0004
-#define SEND_RESPONSE			0x0104
-#define SEND_ERROR_RESPONSE		0x0114
-#define DATA_INDICATION			0x0115
-#define SET_ACTIVE_DESTINATION_REQUEST	0x0006
-#define SET_ACTIVE_DESTINATION_RESPONSE	0x0106
-#define SET_ACTIVE_DESTINATION_ERROR_RESPONSE	0x0116
-
 /* Attribute Types */
 #define MAPPED_ADDRESS		0x0001
-#define RESPONSE_ADDRESS	0x0002
-#define CHANGE_REQUEST		0x0003
-#define SOURCE_ADDRESS		0x0004
-#define CHANGED_ADDRESS		0x0005
-#define USERNAME		0x0006
-#define PASSWORD		0x0007
+#define USERNAME			0x0006
+#define PASSWORD			0x0007
 #define MESSAGE_INTEGRITY	0x0008
-#define ERROR_CODE		0x0009
+#define ERROR_CODE			0x0009
 #define UNKNOWN_ATTRIBUTES	0x000a
-#define REFLECTED_FROM		0x000b
-#define LIFETIME		0x000d
-#define ALTERNATE_SERVER	0x000e
-#define MAGIC_COOKIE		0x000f
-#define BANDWIDTH		0x0010
-#define DESTINATION_ADDRESS	0x0011
-#define REMOTE_ADDRESS		0x0012
-#define DATA			0x0013
-#define NONCE			0x0014
-#define REALM			0x0015
-#define REQUESTED_ADDRESS_TYPE	0x0016
-#define XOR_MAPPED_ADDRESS	0x8020
-#define XOR_ONLY		0x0021
-#define SERVER			0x8022
+#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
 
-
-
 /* Initialize the subtree pointers */
 static gint ett_stun = -1;
 static gint ett_stun_att_type = -1;
 static gint ett_stun_att = -1;
 
-
 #define UDP_PORT_STUN 	3478
 #define TCP_PORT_STUN	3478
 
-
 #define STUN_HDR_LEN	20	/* STUN message header length */
 #define ATTR_HDR_LEN	4	/* STUN attribute header length */
 
 
-static const true_false_string set_flag = {
-	"SET",
-	"NOT SET"
+static const value_string classes[] = {
+	{REQUEST, "Request"},
+	{INDICATION, "Indication"},
+	{RESPONSE, "Response"},
+	{ERROR, "Error Response"},
+	{0x00, NULL}
 };
 
-static const value_string messages[] = {
-	{BINDING_REQUEST, "Binding Request"},
-	{BINDING_RESPONSE, "Binding Response"},
-	{BINDING_ERROR_RESPONSE, "Binding Error Response"},
-	{SHARED_SECRET_REQUEST, "Shared Secret Request"},
-	{SHARED_SECRET_RESPONSE, "Shared Secret Response"},
-	{SHARED_SECRET_ERROR_RESPONSE, "Shared Secret Error Response"},
-	{ALLOCATE_REQUEST, "Allocate Request"},
-	{ALLOCATE_RESPONSE, "Allocate Response"},
-	{ALLOCATE_ERROR_RESPONSE, "Allocate Error Response"},
-	{SEND_REQUEST, "Send Request"},
-	{SEND_RESPONSE, "Send Response"},
-	{SEND_ERROR_RESPONSE, "Send Error Response"},
-	{DATA_INDICATION, "Data Indication"},
-	{SET_ACTIVE_DESTINATION_REQUEST, "Set Active Destination Request"},
-	{SET_ACTIVE_DESTINATION_RESPONSE, "Set Active Destination Response"},
-	{SET_ACTIVE_DESTINATION_ERROR_RESPONSE, "Set Active Destination Error Response"},
+static const value_string methods[] = {
+	{BINDING, "Binding"},
+	{SHARED_SECRET, "Shared Secret"},
 	{0x00, NULL}
 };
 
 static const value_string attributes[] = {
 	{MAPPED_ADDRESS, "MAPPED-ADDRESS"},
-	{RESPONSE_ADDRESS, "RESPONSE-ADDRESS"},
-	{CHANGE_REQUEST, "CHANGE-REQUEST"},
-	{SOURCE_ADDRESS, "SOURCE-ADDRESS"},
-	{CHANGED_ADDRESS, "CHANGED-ADDRESS"},
 	{USERNAME, "USERNAME"},
 	{PASSWORD, "PASSWORD"},
 	{MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY"},
 	{ERROR_CODE, "ERROR-CODE"},
-	{REFLECTED_FROM, "REFLECTED-FROM"},
-	{LIFETIME, "LIFETIME"},
-	{ALTERNATE_SERVER, "ALTERNATE_SERVER"},
-	{MAGIC_COOKIE, "MAGIC_COOKIE"},
-	{BANDWIDTH, "BANDWIDTH"},
-	{DESTINATION_ADDRESS, "DESTINATION_ADDRESS"},
-	{REMOTE_ADDRESS, "REMOTE_ADDRESS"},
-	{DATA, "DATA"},
-	{NONCE, "NONCE"},
+	{UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES"},
 	{REALM, "REALM"},
-	{REQUESTED_ADDRESS_TYPE, "REQUESTED_ADDRESS_TYPE"},
-	{XOR_MAPPED_ADDRESS, "XOR_MAPPED_ADDRESS"},
-	{XOR_ONLY, "XOR_ONLY"},
+	{NONCE, "NONCE"},
+	{XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS"},
 	{SERVER, "SERVER"},
+	{ALTERNATE_SERVER, "ALTERNATE-SERVER"},
+	{REFRESH_INTERVAL, "REFRESH-INTERVAL"},
+	{FINGERPRINT, "FINGERPRINT"},
 	{0x00, NULL}
 };
 
@@ -191,7 +151,6 @@
 static int
 dissect_stun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-
 	proto_item *ti;
 	proto_item *ta;
 	proto_tree *stun_tree;
@@ -199,7 +158,8 @@
 	proto_tree *att_tree;
 	guint16 msg_type;
 	guint16 msg_length;
-	const char *msg_type_str;
+	const char *msg_class_str;
+	const char *msg_method_str;
 	guint16 att_type;
 	guint16 att_length;
 	guint16 offset;
@@ -212,16 +172,14 @@
 	/* First, make sure we have enough data to do the check. */
 	if (!tvb_bytes_exist(tvb, 0, STUN_HDR_LEN))
 		return 0;
-	
+
 	msg_type = tvb_get_ntohs(tvb, 0);
-	
-	/* check if message type is correct */
-	msg_type_str = match_strval(msg_type, messages);
-	if (msg_type_str == NULL)
-		return 0;
-	
 	msg_length = tvb_get_ntohs(tvb, 2);
-	
+
+	/* Check if it is really a STUN message */
+	if (msg_type & 0xC000 || tvb_get_ntohl(tvb, 4) != 0x2112a442)
+		return 0;
+
 	/* check if payload enough */
 	if (!tvb_bytes_exist(tvb, 0, STUN_HDR_LEN+msg_length))
 		return 0;
@@ -232,26 +190,32 @@
 
 	/* The message seems to be a valid STUN message! */
 
-	if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
-		col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUN");
-    
-	if (check_col(pinfo->cinfo, COL_INFO)) {
-		col_add_fstr(pinfo->cinfo, COL_INFO, "Message: %s",
-		    msg_type_str);
-	}
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUNv2");
 
+	msg_class_str = match_strval((msg_type & CLASS_MASK) >> 4, classes);
+	msg_method_str = match_strval(msg_type & METHOD_MASK, methods);
+	if (msg_method_str == NULL)
+		msg_method_str = "Unknown";
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+		    msg_method_str, msg_class_str);
+
 	if (tree) {
 		guint transaction_id_first_word;
 
 		ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
-			    
+
 		stun_tree = proto_item_add_subtree(ti, ett_stun);
 
-		proto_tree_add_uint(stun_tree, hf_stun_type, tvb, 0, 2, msg_type);
+		proto_tree_add_uint(stun_tree, hf_stun_class, tvb, 0, 2, msg_type);
+		proto_tree_add_uint(stun_tree, hf_stun_method, tvb, 0, 2, msg_type);
 		proto_tree_add_uint(stun_tree, hf_stun_length, tvb, 2, 2, msg_length);
-		proto_tree_add_item(stun_tree, hf_stun_id, tvb, 4, 16, FALSE);
+		proto_tree_add_item(stun_tree, hf_stun_cookie, tvb, 4, 4, FALSE);
+		proto_tree_add_item(stun_tree, hf_stun_id, tvb, 8, 12, FALSE);
 
 		/* Remember this (in host order) so we can show clear xor'd addresses */
+		/* TODO IPv6 support */
 		transaction_id_first_word = tvb_get_ntohl(tvb, 4);
 
 		if (msg_length > 0) {
@@ -260,174 +224,174 @@
 
 		    offset = STUN_HDR_LEN;
 
-		    while( msg_length > 0) {
-			att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
-			att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
-			
-			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)"));
-			att_tree = proto_item_add_subtree(ta, ett_stun_att);
-			
-			proto_tree_add_uint(att_tree, stun_att_type, tvb,
-			    offset, 2, att_type);
-			offset += 2;
-			if (ATTR_HDR_LEN+att_length > msg_length) {
-				proto_tree_add_uint_format(att_tree,
-				    stun_att_length, tvb, offset, 2,
-				    att_length,
-				    "Attribute Length: %u (bogus, goes past the end of the message)",
-				    att_length);
-				break;
-			}
-			proto_tree_add_uint(att_tree, stun_att_length, tvb,
-			    offset, 2, att_length);
-			offset += 2;
-			switch( att_type ){
-				case MAPPED_ADDRESS:
-				case RESPONSE_ADDRESS:
-				case SOURCE_ADDRESS:
-				case CHANGED_ADDRESS:
-				case REFLECTED_FROM:
-				case ALTERNATE_SERVER:
-				case DESTINATION_ADDRESS:
-				case REMOTE_ADDRESS:
-					if (att_length < 2)
-						break;
-					proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
-					if (att_length < 4)
-						break;
-					proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
-					switch( tvb_get_guint8(tvb, offset+1) ){
-						case 1:
-							if (att_length < 8)
-								break;
-							proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
+		    while (msg_length > 0) {
+				att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
+				att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
+
+				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)"));
+				att_tree = proto_item_add_subtree(ta, ett_stun_att);
+
+				proto_tree_add_uint(att_tree, stun_att_type, tvb,
+					offset, 2, att_type);
+				offset += 2;
+				if (ATTR_HDR_LEN+att_length > msg_length) {
+					proto_tree_add_uint_format(att_tree,
+						stun_att_length, tvb, offset, 2,
+						att_length,
+						"Attribute Length: %u (bogus, goes past the end of the message)",
+						att_length);
+					break;
+				}
+				proto_tree_add_uint(att_tree, stun_att_length, tvb,
+					offset, 2, att_length);
+				offset += 2;
+				switch (att_type) {
+					case MAPPED_ADDRESS:
+					case ALTERNATE_SERVER:
+						if (att_length < 2)
 							break;
+						proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
+						if (att_length < 4)
+							break;
+						proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
+						switch (tvb_get_guint8(tvb, offset+1)) {
+							case 1:
+								if (att_length < 8)
+									break;
+								proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
+								break;
 
-						case 2:
-							if (att_length < 20)
+							case 2:
+								if (att_length < 20)
+									break;
+								proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
 								break;
-							proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
-							break;
-						}
-					break;
-					
-				case CHANGE_REQUEST:
-					if (att_length < 4)
+							}
 						break;
-					proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset, 4, FALSE);
-					proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset, 4, FALSE);
-					break;					
-					
-				case USERNAME:
-				case PASSWORD:
-				case MESSAGE_INTEGRITY:
-				case NONCE:
-				case REALM:
-					if (att_length < 1)
+
+					case USERNAME:
+						proto_tree_add_item(att_tree, stun_att_username, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
-					break;
-					
-				case ERROR_CODE:
-					if (att_length < 3)
+
+					case PASSWORD:
+						proto_tree_add_item(att_tree, stun_att_password, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
-					if (att_length < 4)
+
+					case NONCE:
+						proto_tree_add_item(att_tree, stun_att_nonce, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
-					if (att_length < 5)
+
+					case REALM:
+						proto_tree_add_item(att_tree, stun_att_realm, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, (att_length-4), FALSE);
-					break;
-				
-				case LIFETIME:
-					if (att_length < 4)
+
+					case MESSAGE_INTEGRITY:
+						if (att_length < 20)
+							break;
+						proto_tree_add_item(att_tree, stun_att_hmac, tvb, offset, att_length, FALSE);
 						break;
-					proto_tree_add_item(att_tree, stun_att_lifetime, tvb, offset, 4, FALSE);
-					break;
 
-				case MAGIC_COOKIE:
-					if (att_length < 4)
+					case FINGERPRINT:
+						if (att_length < 4)
+							break;
+						proto_tree_add_item(att_tree, stun_att_crc32, tvb, offset, att_length, FALSE);
 						break;
-					proto_tree_add_item(att_tree, stun_att_magic_cookie, tvb, offset, 4, FALSE);
-					break;
 
-				case BANDWIDTH:
-					if (att_length < 4)
+					case ERROR_CODE:
+						if (att_length < 3)
+							break;
+						proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
+						if (att_length < 4)
+							break;
+						proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
+						if (att_length < 5)
+							break;
+						proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, att_length-4, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_bandwidth, tvb, offset, 4, FALSE);
-					break;
 
-				case DATA:
-					proto_tree_add_item(att_tree, stun_att_data, tvb, offset, att_length, FALSE);
-					break;
+					case UNKNOWN_ATTRIBUTES:
+						for (i = 0; i < att_length; i += 2)
+							proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+						break;
 
-				case UNKNOWN_ATTRIBUTES:
-					for (i = 0; i < att_length; i += 4) {
-						proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
-						proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i+2, 2, FALSE);
-					}
-					break;
-					
-				case SERVER:
-					proto_tree_add_item(att_tree, stun_att_server_string, tvb, offset, att_length, FALSE);
-					break;
-
-				case XOR_MAPPED_ADDRESS:
-					if (att_length < 2)
+					case SERVER:
+						proto_tree_add_item(att_tree, stun_att_server, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
 						break;
-					proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
-					if (att_length < 4)
-						break;
-					proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
 
-					/* Show the port 'in the clear'
-						XOR (host order) transid with (host order) xor-port.
-						Add host-order port into tree. */
-					ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
-					                         tvb_get_ntohs(tvb, offset+2) ^
-					                         (transaction_id_first_word >> 16));
-					PROTO_ITEM_SET_GENERATED(ti);
+					case XOR_MAPPED_ADDRESS:
+						if (att_length < 2)
+							break;
+						proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
+						if (att_length < 4)
+							break;
+						proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
 
-					if (att_length < 8)
-						break;
-					switch( tvb_get_guint8(tvb, offset+1) ){
-						case 1:
-							if (att_length < 8)
-								break;
-							proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
+						/* Show the port 'in the clear'
+						   XOR (host order) transid with (host order) xor-port.
+						   Add host-order port into tree. */
+						ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
+												 tvb_get_ntohs(tvb, offset+2) ^
+												 (transaction_id_first_word >> 16));
+						PROTO_ITEM_SET_GENERATED(ti);
 
-							/* Show the address 'in the clear'.
-							   XOR (host order) transid with (host order) xor-address.
-							   Add in network order tree. */
-							ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
-													 g_htonl(tvb_get_ntohl(tvb, offset+4) ^
-													 transaction_id_first_word));
-							PROTO_ITEM_SET_GENERATED(ti);
+						if (att_length < 8)
 							break;
+						switch (tvb_get_guint8(tvb, offset+1) ){
+							case 1:
+								if (att_length < 8)
+									break;
+								proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
 
-						case 2:
-							if (att_length < 20)
+								/* Show the address 'in the clear'.
+								   XOR (host order) transid with (host order) xor-address.
+								   Add in network order tree. */
+								ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
+														 g_htonl(tvb_get_ntohl(tvb, offset+4) ^
+														 transaction_id_first_word));
+								PROTO_ITEM_SET_GENERATED(ti);
 								break;
-							proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
-							break;
-						}
-					break;
 
-				case REQUESTED_ADDRESS_TYPE:
-					if (att_length < 2)
+							case 2:
+								if (att_length < 20)
+									break;
+								/* TODO add IPv6 */
+								proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
+								break;
+							}
 						break;
-					proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
-					break;
 
-				default:
-					break;
-			}
-			offset += att_length;
-			msg_length -= ATTR_HDR_LEN+att_length;
+					case REFRESH_INTERVAL:
+						if (att_length < 4)
+							break;
+						proto_tree_add_item(att_tree, stun_att_refresh_interval, tvb, offset, 4, FALSE);
+						break;
+
+					default:
+						if (att_length > 0)
+							proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
+						if (att_length % 4 != 0)
+							proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+						break;
+				}
+				offset += (att_length+3) & -4;
+				msg_length -= (ATTR_HDR_LEN+att_length+3) & -4;
 		    }
 		}
 	}
@@ -444,21 +408,26 @@
 	return TRUE;
 }
 
-
-
-
 void
-proto_register_stun(void)
+proto_register_stun2(void)
 {
 	static hf_register_info hf[] = {
-		{ &hf_stun_type,
-			{ "Message Type",	"stun.type", 	FT_UINT16, 
-			BASE_HEX, 	VALS(messages),	0x0, 	"", 	HFILL }
+		{ &hf_stun_class,
+			{ "Message Class",	"stun.class", 	FT_UINT16,
+			BASE_HEX, 	VALS(classes),	0x0110, 	"", 	HFILL }
 		},
+		{ &hf_stun_method,
+			{ "Message Method",	"stun.method", 	FT_UINT16,
+			BASE_HEX, 	VALS(methods),	0x3EEF, 	"", 	HFILL }
+		},
 		{ &hf_stun_length,
-			{ "Message Length",	"stun.length",	FT_UINT16, 
+			{ "Message Length",	"stun.length",	FT_UINT16,
 			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
 		},
+		{ &hf_stun_cookie,
+			{ "Message Cookie",	"stun.cookie",	FT_BYTES,
+			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
+		},
 		{ &hf_stun_id,
 			{ "Message Transaction ID",	"stun.id",	FT_BYTES,
 			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
@@ -476,10 +445,6 @@
 			{ "Attribute Length",	"stun.att.length",	FT_UINT16,
 			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun_att_value,
-			{ "Value",	"stun.att.value",	FT_BYTES,
-			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
-		},
 		{ &stun_att_family,
 			{ "Protocol Family",	"stun.att.family",	FT_UINT16,
 			BASE_HEX,	VALS(attributes_family),	0x0, 	"",	HFILL }
@@ -496,18 +461,26 @@
 			{ "Port",	"stun.att.port",	FT_UINT16,
 			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun_att_change_ip,
-			{ "Change IP","stun.att.change.ip",	FT_BOOLEAN,
-			16, 	TFS(&set_flag),	0x0004,	"",	HFILL}
+		{ &stun_att_username,
+			{ "Username",	"stun.att.username",	FT_STRING,
+			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun_att_change_port,
-			{ "Change Port","stun.att.change.port",	FT_BOOLEAN,
-			16, 	TFS(&set_flag),	0x0002,	"",	HFILL}
-		},		
-		{ &stun_att_unknown,
-			{ "Unknown Attribute","stun.att.unknown",	FT_UINT16,
-			BASE_HEX, 	NULL,	0x0,	"",	HFILL}
+		{ &stun_att_padding,
+			{ "Padding",	"stun.att.padding",	FT_UINT16,
+			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
+		{ &stun_att_password,
+			{ "Password",	"stun.att.password",	FT_STRING,
+			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
+		},
+		{ &stun_att_hmac,
+			{ "HMAC-SHA1",	"stun.att.hmac",	FT_BYTES,
+			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
+		},
+		{ &stun_att_crc32,
+			{ "CRC-32",	"stun.att.crc32",	FT_UINT32,
+			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
+		},
 		{ &stun_att_error_class,
 			{ "Error Class","stun.att.error.class",	FT_UINT8,
 			BASE_DEC, 	NULL,	0x07,	"",	HFILL}
@@ -520,6 +493,18 @@
 			{ "Error Reason Phase","stun.att.error.reason",	FT_STRING,
 			BASE_NONE, 	NULL,	0x0,	"",	HFILL}
 		},
+		{ &stun_att_realm,
+			{ "Realm",	"stun.att.realm",	FT_STRING,
+			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
+		},
+		{ &stun_att_nonce,
+			{ "Nonce",	"stun.att.nonce",	FT_STRING,
+			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
+		},
+		{ &stun_att_unknown,
+			{ "Unknown Attribute","stun.att.unknown",	FT_UINT16,
+			BASE_HEX, 	NULL,	0x0,	"",	HFILL}
+		},
 		{ &stun_att_xor_ipv4,
 			{ "IP (XOR-d)",		"stun.att.ipv4-xord",	FT_IPv4,
 			BASE_NONE,	NULL,	0x0, 	"",	HFILL }
@@ -532,26 +517,18 @@
 			{ "Port (XOR-d)",	"stun.att.port-xord",	FT_UINT16,
 			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun_att_server_string,
-			{ "Server version","stun.att.server",	FT_STRING,
+		{ &stun_att_server,
+			{ "Server software","stun.att.server",	FT_STRING,
 			BASE_NONE, 	NULL,	0x0,	"",	HFILL}
  		},
-		{ &stun_att_lifetime,
-			{ "Lifetime",	"stun.att.lifetime",	FT_UINT32,
-			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
-		},
-		{ &stun_att_magic_cookie,
-			{ "Magic Cookie",	"stun.att.magic.cookie",	FT_UINT32,
+		{ &stun_att_refresh_interval,
+			{ "Refresh Interval","stun.att.refresh-interval",	FT_UINT16,
+			BASE_DEC, 	NULL,	0x0,	"",	HFILL}
+ 		},
+		{ &stun_att_value,
+			{ "Value",	"stun.value",	FT_BYTES,
 			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
 		},
-		{ &stun_att_bandwidth,
-			{ "Bandwidth",	"stun.att.bandwidth",	FT_UINT32,
-			BASE_DEC,	NULL,	0x0, 	"",	HFILL }
-		},
-		{ &stun_att_data,
-			{ "Data",	"stun.att.data",	FT_BYTES,
-			BASE_HEX,	NULL,	0x0, 	"",	HFILL }
-		},
 	};
 
 /* Setup protocol subtree array */
@@ -562,23 +539,23 @@
 	};
 
 /* Register the protocol name and description */
-	proto_stun = proto_register_protocol("Simple Traversal of UDP Through NAT",
-	    "STUN", "stun");
+	proto_stun = proto_register_protocol("Simple Traversal Underneath NAT",
+	    "STUNv2", "stun2");
 
 /* Required function calls to register the header fields and subtrees used */
 	proto_register_field_array(proto_stun, hf, array_length(hf));
 	proto_register_subtree_array(ett, array_length(ett));
 
-	new_register_dissector("stun", dissect_stun, proto_stun);
+	new_register_dissector("stun2", dissect_stun, proto_stun);
 }
 
 
 void
-proto_reg_handoff_stun(void)
+proto_reg_handoff_stun2(void)
 {
 	dissector_handle_t stun_handle;
 
-	stun_handle = find_dissector("stun");
+	stun_handle = find_dissector("stun2");
 
 	dissector_add("tcp.port", TCP_PORT_STUN, stun_handle);
 	dissector_add("udp.port", UDP_PORT_STUN, stun_handle);
@@ -586,3 +563,4 @@
 	heur_dissector_add("udp", dissect_stun_heur, proto_stun);
 	heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
 }
+
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 20006)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -639,6 +639,7 @@
 	packet-stat-notify.c	\
 	packet-stat.c	\
 	packet-stun.c	\
+	packet-stun2.c	\
 	packet-sua.c	\
 	packet-symantec.c	\
 	packet-synergy.c \

Attachment: stun2.pcap.gz
Description: application/gzip