aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-stun.c201
1 files changed, 130 insertions, 71 deletions
diff --git a/epan/dissectors/packet-stun.c b/epan/dissectors/packet-stun.c
index 797de4359f..7dd2c8bc3f 100644
--- a/epan/dissectors/packet-stun.c
+++ b/epan/dissectors/packet-stun.c
@@ -41,6 +41,14 @@
* MS-ICE2BWN: Interactive Connectivity Establishment (ICE) 2.0 Bandwidth Management Extensions https://docs.microsoft.com/en-us/openspecs/office_protocols/ms-ice2bwm
*/
+/* TODO
+ * Add protocol version auto detection
+ * Add information about different versions to table as we find it
+ * Add/Implement missing attributes
+ * Add/Implement missing message classes/methods
+ * Add missing error codes
+ */
+
#include "config.h"
#include <epan/packet.h>
@@ -50,6 +58,47 @@
void proto_register_stun(void);
void proto_reg_handoff_stun(void);
+/* Dissection relevant differences between STUN/TURN specification documents
+ *
+ * Aspect | MS-TURN 15.1 | RFC 3489 |RFC 5389 |
+ * ==========================================================================
+ * Message | 0b00+14-bit | 16-bit | 0b00+14-bit, type= |
+ * Type | No class or method | No class or method | class+method |
+ * --------------------------------------------------------------------------
+ * Transac- | 128 bits, seen | 128 bits | 32 bit Magic + |
+ * tion ID | with MAGIC as well | | 96 bit Trans ID |
+ * --------------------------------------------------------------------------
+ * Padding | No Attribute Pad | No Attribute Pad | Pad to 32 bits |
+ * | | | Att. Len excl. Pad |
+ * | | | Msg. Len incl. Pad |
+ * | | | -> MLen & 3 == 0 |
+ * --------------------------------------------------------------------------
+ * Username | Opaque | Opaque | UTF-8 String |
+ * --------------------------------------------------------------------------
+ * Password | Opaque | Deprecated | Deprecated |
+ * --------------------------------------------------------------------------
+ * NONCE & | 0x0014 | 0x0015 | 0x0015 |
+ * REALM | 0x0015 | 0x0014 | 0x0014 |
+ * --------------------------------------------------------------------------
+ */
+
+enum {
+ /* NET_VER_AUTO, */
+ NET_VER_MS_TURN,
+ NET_VER_3489,
+ NET_VER_5389
+};
+
+static gint stun_network_version = NET_VER_5389;
+
+static const enum_val_t stun_network_version_vals[] = {
+ /* { "Auto", "Auto", NET_VER_AUTO}, */
+ { "MS-TURN", "MS-TURN", NET_VER_MS_TURN },
+ { "RFC3489 and earlier", "RFC3489 and earlier", NET_VER_3489},
+ { "RFC5389 and later", "RFC5389 and later", NET_VER_5389 },
+ { NULL, NULL, 0 }
+};
+
/* heuristic subdissectors */
static heur_dissector_list_t heur_subdissector_list;
@@ -88,6 +137,7 @@ static int hf_stun_att_ipv4 = -1;
static int hf_stun_att_ipv6 = -1;
static int hf_stun_att_port = -1;
static int hf_stun_att_username = -1;
+static int hf_stun_att_username_opaque = -1;
static int hf_stun_att_password = -1;
static int hf_stun_att_padding = -1;
static int hf_stun_att_hmac = -1;
@@ -481,33 +531,41 @@ static const value_string attributes_family[] = {
{0x0002, "IPv6"},
{0x00, NULL}
};
-/* https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml#stun-parameters-6 (2015-06-12)*/
+/* https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml#stun-parameters-6 (2020-08-05)*/
static const value_string error_code[] = {
{274, "Disable Candidate"}, /* MS-ICE2BWN */
{275, "Disable Candidate Pair"}, /* MS-ICE2BWN */
- {300, "Try Alternate"}, /* rfc3489bis-15 */
- {400, "Bad Request"}, /* rfc3489bis-15 */
- {401, "Unauthorized"}, /* rfc3489bis-15 */
- {403, "Forbidden"}, /* rfc5766 */
- {420, "Unknown Attribute"}, /* rfc3489bis-15 */
- {437, "Allocation Mismatch"}, /* turn-07 */
- {438, "Stale Nonce"}, /* rfc3489bis-15 */
- {439, "Wrong Credentials"}, /* turn-07 - collision 38=>39 */
- {440, "Address Family not Supported"}, /* turn-ipv6-04 */
- {441, "Wrong Credentials"}, /* rfc5766 */
- {442, "Unsupported Transport Protocol"}, /* turn-07 */
- {443, "Peer Address Family Mismatch"}, /* rfc6156 */
- {446, "Connection Already Exists"}, /* rfc6062 */
- {447, "Connection Timeout or Failure"}, /* rfc6062 */
- {481, "Connection does not exist"}, /* nat-behavior-discovery-03 */
- {486, "Allocation Quota Reached"}, /* turn-07 */
- {487, "Role Conflict"}, /* rfc5245 */
- {500, "Server Error"}, /* rfc3489bis-15 */
- {503, "Service Unavailable"}, /* nat-behavior-discovery-03 */
- {507, "Insufficient Bandwidth Capacity"}, /* turn-07 */
- {508, "Insufficient Port Capacity"}, /* turn-07 */
- {600, "Global Failure"},
+ {300, "Try Alternate"}, /* RFC8489 */
+ {400, "Bad Request"}, /* RFC8489 */
+ {401, "Unauthenticated"}, /* RFC8489, RFC3489+MS-TURN: Unauthorized */
+ {403, "Forbidden"}, /* RFC8656 */
+ {405, "Mobility Forbidden"}, /* RFC8016 */
+ {420, "Unknown Attribute"}, /* RFC8489 */
+ {430, "Stale Credentials (legacy)"}, /* RFC3489 */
+ {431, "Integrity Check Failure (legacy)"}, /* RFC3489 */
+ {432, "Missing Username (legacy)"}, /* RFC3489 */
+ {433, "Use TLS (legacy)"}, /* RFC3489 */
+ {434, "Missing Realm (legacy)"}, /* MS-TURN */
+ {435, "Missing Nonce (legacy)"}, /* MS-TURN */
+ {436, "Unknown User (legacy)"}, /* MS-TURN */
+ {437, "Allocation Mismatch"}, /* RFC8656 */
+ {438, "Stale Nonce"}, /* RFC8489 */
+ {439, "Wrong Credentials (legacy)"}, /* turn-07 */
+ {440, "Address Family not Supported"}, /* RFC8656 */
+ {441, "Wrong Credentials"}, /* RFC8656 */
+ {442, "Unsupported Transport Protocol"}, /* RFC8656 */
+ {443, "Peer Address Family Mismatch"}, /* RFC8656 */
+ {446, "Connection Already Exists"}, /* RFC6062 */
+ {447, "Connection Timeout or Failure"}, /* RFC6062 */
+ {481, "Connection does not exist (legacy)"}, /* nat-behavior-discovery-03 */
+ {486, "Allocation Quota Reached"}, /* RFC8656 */
+ {487, "Role Conflict"}, /* RFC8445 */
+ {500, "Server Error"}, /* RFC8489 */
+ {503, "Service Unavailable (legacy)"}, /* nat-behavior-discovery-03 */
+ {507, "Insufficient Bandwidth Capacity (legacy)"}, /* turn-07 */
+ {508, "Insufficient Port Capacity"}, /* RFC8656 */
+ {600, "Global Failure"}, /* RFC8656 */
{0x00, NULL}
};
static value_string_ext error_code_ext = VALUE_STRING_EXT_INIT(error_code);
@@ -654,8 +712,8 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
guint16 msg_type_class;
const char *msg_class_str;
const char *msg_method_str;
- guint16 att_type;
- guint16 att_length, clear_port;
+ guint16 att_type, att_type_display;
+ guint16 att_length, att_length_pad, clear_port;
guint32 clear_ip;
guint i;
guint offset;
@@ -922,12 +980,20 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
att_all_tree = proto_item_add_subtree(ti, ett_stun_att_all);
while (offset < (STUN_HDR_LEN + msg_length)) {
- 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 */
- attribute_name_str = val_to_str_ext_const(att_type, &attributes_ext, "Unknown");
+ att_type = tvb_get_ntohs(tvb, offset); /* Attribute type field in attribute header */
+ att_length = tvb_get_ntohs(tvb, offset+2); /* Attribute length field in attribute header */
+ if (stun_network_version >= NET_VER_5389)
+ att_length_pad = (att_length + 3) & ~3; /* Attribute length including padding */
+ else
+ att_length_pad = att_length;
+ att_type_display = att_type;
+ /* Early drafts and MS-TURN use swapped numbers to later versions */
+ if ((stun_network_version < NET_VER_3489) && (att_type == 0x0014 || att_type == 0x0015))
+ att_type_display ^= 1;
+ attribute_name_str = val_to_str_ext_const(att_type_display, &attributes_ext, "Unknown");
if(att_all_tree){
ti = proto_tree_add_uint_format(att_all_tree, hf_stun_attr,
- tvb, offset, ATTR_HDR_LEN+att_length,
+ tvb, offset, ATTR_HDR_LEN+att_length_pad,
att_type, "%s", attribute_name_str);
att_tree = proto_item_add_subtree(ti, ett_stun_att);
ti = proto_tree_add_uint(att_tree, hf_stun_att_type, tvb,
@@ -936,12 +1002,12 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
proto_tree_add_uint(att_type_tree, hf_stun_att_type_comprehension, tvb, offset, 2, att_type);
proto_tree_add_uint(att_type_tree, hf_stun_att_type_assignment, tvb, offset, 2, att_type);
- if ((offset+ATTR_HDR_LEN+att_length) > (STUN_HDR_LEN+msg_length+tcp_framing_offset)) {
+ if ((offset+ATTR_HDR_LEN+att_length_pad) > (STUN_HDR_LEN+msg_length+tcp_framing_offset)) {
proto_tree_add_uint_format_value(att_tree,
hf_stun_att_length, tvb, offset+2, 2,
- att_length,
+ att_length_pad,
"%u (bogus, goes past the end of the message)",
- att_length);
+ att_length_pad);
break;
}
}
@@ -951,7 +1017,7 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
offset, 2, att_length);
offset += 2;
- switch (att_type) {
+ switch (att_type_display) {
/* Deprecated STUN RFC3489 attributes */
case RESPONSE_ADDRESS:
@@ -989,11 +1055,7 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
/* Deprecated STUN RFC3489 attributes */
case PASSWORD:
{
- const guint8* dep_password;
- proto_tree_add_item_ret_string(att_tree, hf_stun_att_password, tvb, offset, att_length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &dep_password);
- proto_item_append_text(att_tree, " (Deprecated): %s", dep_password);
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+ proto_tree_add_item(att_tree, hf_stun_att_password, tvb, offset, att_length, ENC_NA);
}
break;
@@ -1059,17 +1121,15 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
case USERNAME:
{
- const guint8 *user_name_str;
-
- proto_tree_add_item_ret_string(att_tree, hf_stun_att_username, tvb, offset, att_length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &user_name_str);
- proto_item_append_text(att_tree, ": %s", user_name_str);
- col_append_fstr(
- pinfo->cinfo, COL_INFO,
- " user: %s",
- user_name_str);
-
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
+ if (stun_network_version > NET_VER_3489) {
+ const guint8 *user_name_str;
+
+ proto_tree_add_item_ret_string(att_tree, hf_stun_att_username, tvb, offset, att_length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &user_name_str);
+ proto_item_append_text(att_tree, ": %s", user_name_str);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " user: %s", user_name_str);
+ } else {
+ proto_tree_add_item(att_tree, hf_stun_att_username_opaque, tvb, offset, att_length, ENC_NA);
+ }
break;
}
case MESSAGE_INTEGRITY:
@@ -1113,16 +1173,11 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
proto_item_append_text(att_tree, ": %s", error_reas_str);
col_append_fstr(pinfo->cinfo, COL_INFO, " %s", error_reas_str);
}
-
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_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 += 2)
proto_tree_add_item(att_tree, hf_stun_att_unknown, tvb, offset+i, 2, ENC_BIG_ENDIAN);
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
break;
case REALM:
@@ -1131,8 +1186,6 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
proto_tree_add_item_ret_string(att_tree, hf_stun_att_realm, tvb, offset, att_length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &realm_str);
proto_item_append_text(att_tree, ": %s", realm_str);
col_append_fstr(pinfo->cinfo, COL_INFO, " realm: %s", realm_str);
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
break;
}
case NONCE:
@@ -1141,8 +1194,6 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
proto_tree_add_item_ret_string(att_tree, hf_stun_att_nonce, tvb, offset, att_length, ENC_UTF_8|ENC_NA, wmem_packet_scope(), &nonce_str);
proto_item_append_text(att_tree, ": %s", nonce_str);
col_append_str(pinfo->cinfo, COL_INFO, " with nonce");
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
break;
}
@@ -1281,8 +1332,6 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
case SOFTWARE:
proto_tree_add_item(att_tree, hf_stun_att_software, tvb, offset, att_length, ENC_UTF_8|ENC_NA);
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
break;
case CACHE_TIMEOUT:
@@ -1308,11 +1357,6 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
if (att_length > 0) {
tvbuff_t *next_tvb;
proto_tree_add_item(att_tree, hf_stun_att_value, tvb, offset, att_length, ENC_NA);
- if (att_length % 4 != 0) {
- guint pad;
- pad = 4-(att_length % 4);
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, pad, pad);
- }
next_tvb = tvb_new_subset_length(tvb, offset, att_length);
@@ -1449,12 +1493,12 @@ dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboole
default:
if (att_length > 0)
proto_tree_add_item(att_tree, hf_stun_att_value, tvb, offset, att_length, ENC_NA);
- if (att_length % 4 != 0)
- proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb,
- offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
break;
}
- offset += (att_length+3) & ~0x3;
+
+ if ((stun_network_version >= NET_VER_5389) && (att_length < att_length_pad))
+ proto_tree_add_uint(att_tree, hf_stun_att_padding, tvb, offset+att_length, att_length_pad-att_length, att_length_pad-att_length);
+ offset += att_length_pad;
}
}
@@ -1623,8 +1667,12 @@ proto_register_stun(void)
{ "Username", "stun.att.username", FT_STRING,
BASE_NONE, NULL, 0x0, NULL, HFILL }
},
+ { &hf_stun_att_username_opaque,
+ { "Username", "stun.att.username", FT_BYTES,
+ BASE_NONE, NULL, 0x0, NULL, HFILL }
+ },
{ &hf_stun_att_password,
- { "Password", "stun.att.password", FT_STRING,
+ { "Password", "stun.att.password", FT_BYTES,
BASE_NONE, NULL, 0x0, NULL, HFILL }
},
{ &hf_stun_att_padding,
@@ -1697,7 +1745,7 @@ proto_register_stun(void)
},
{ &hf_stun_att_lifetime,
{ "Lifetime", "stun.att.lifetime", FT_UINT32,
- BASE_DEC, NULL, 0x0, "Session time remaining (seconds)", HFILL}
+ BASE_DEC, NULL, 0x0, "Session idle time remaining (seconds)", HFILL}
},
{ &hf_stun_att_change_ip,
{ "Change IP","stun.att.change-ip", FT_BOOLEAN,
@@ -1847,6 +1895,8 @@ proto_register_stun(void)
&ett_stun_att_type,
};
+ module_t *stun_module;
+
/* Register the protocol name and description */
proto_stun = proto_register_protocol("Session Traversal Utilities for NAT", "STUN", "stun");
@@ -1860,6 +1910,15 @@ proto_register_stun(void)
register_dissector("stun-tcp", dissect_stun_tcp, proto_stun);
register_dissector("stun-udp", dissect_stun_udp, proto_stun);
register_dissector("stun-heur", dissect_stun_heur_udp, proto_stun);
+
+ /* Register preferences */
+ stun_module = prefs_register_protocol(proto_stun, NULL);
+ prefs_register_enum_preference(stun_module,
+ "stunversion", "Stun Version", "Stun Version on the Network",
+ &stun_network_version,
+ stun_network_version_vals,
+ FALSE);
+
}
void