summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoão Valverde <joao.valverde@tecnico.ulisboa.pt>2017-05-20 00:27:01 +0100
committerMichael Mann <mmann78@netscape.net>2017-05-25 11:31:58 +0000
commitda9363e202d7506674e232319d5fb6a7e05830ee (patch)
tree9165d5f41262a4570376828af46b52a4bf6d78e8
parentfd9f698ed332f94a8a452a420d8b211950f456b7 (diff)
downloadwireshark-da9363e202d7506674e232319d5fb6a7e05830ee.tar.gz
RADIUS: Add support for extended attributes (RFC 6929)
Bug: 13176 Change-Id: I22cdce01d8e7d5b69c2013684a98a9a48acc0d13 Reviewed-on: https://code.wireshark.org/review/21727 Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r--epan/dissectors/packet-radius.c131
-rw-r--r--epan/dissectors/packet-radius.h25
-rw-r--r--epan/radius_dict.l29
-rw-r--r--radius/dictionary25
4 files changed, 144 insertions, 66 deletions
diff --git a/epan/dissectors/packet-radius.c b/epan/dissectors/packet-radius.c
index 43f1149f94..9ea178e4a6 100644
--- a/epan/dissectors/packet-radius.c
+++ b/epan/dissectors/packet-radius.c
@@ -34,6 +34,7 @@
* RFC 2869 - RADIUS Extensions
* RFC 3162 - RADIUS and IPv6
* RFC 3576 - Dynamic Authorization Extensions to RADIUS
+ * RFC 6929 - Remote Authentication Dial-In User Service (RADIUS) Protocol Extensions
*
* See also
*
@@ -186,6 +187,8 @@ static int hf_radius_eap_fragment = -1;
static int hf_radius_avp = -1;
static int hf_radius_avp_length = -1;
static int hf_radius_avp_type = -1;
+static int hf_radius_avp_extended_type = -1;
+static int hf_radius_avp_extended_more = -1;
static int hf_radius_3gpp_ms_tmime_zone = -1;
static int hf_radius_egress_vlanid_tag = -1;
@@ -214,7 +217,7 @@ static int radius_tap = -1;
static radius_vendor_info_t no_vendor = {"Unknown Vendor", 0, NULL, -1, 1, 1, FALSE};
-static radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute", 0, FALSE, FALSE, radius_octets, NULL, NULL, -1, -1, -1, -1, -1, NULL };
+static radius_attr_info_t no_dictionary_entry = {"Unknown-Attribute", { { 0, 0 } }, FALSE, FALSE, radius_octets, NULL, NULL, -1, -1, -1, -1, -1, NULL };
static dissector_handle_t eap_handle;
static dissector_handle_t radius_handle;
@@ -1395,9 +1398,12 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
while (length > 0) {
radius_attr_info_t *dictionary_entry = NULL;
- guint32 avp_type;
+ guint32 avp_type0 = 0, avp_type1 = 0;
+ radius_attr_type_t avp_type;
guint32 avp_length;
guint32 vendor_id;
+ gboolean avp_is_extended = FALSE;
+ int avp_offset_start = offset;
proto_item *avp_item;
proto_item *avp_len_item;
@@ -1408,8 +1414,16 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
"Not enough room in packet for AVP header");
break; /* exit outer loop, then cleanup & return */
}
- avp_type = tvb_get_guint8(tvb, offset);
+
+ avp_type0 = tvb_get_guint8(tvb, offset);
avp_length = tvb_get_guint8(tvb, offset+1);
+ avp_is_extended = RADIUS_ATTR_TYPE_IS_EXTENDED(avp_type0);
+ if (avp_is_extended) {
+ avp_type1 = tvb_get_guint8(tvb, offset+2);
+ }
+ memset(&avp_type, 0, sizeof(avp_type));
+ avp_type.u8_code[0] = avp_type0;
+ avp_type.u8_code[1] = avp_type1;
if (avp_length < 2) {
proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
@@ -1417,6 +1431,12 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
break; /* exit outer loop, then cleanup & return */
}
+ if (avp_is_extended && avp_length < 3) {
+ proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
+ "Extended AVP too short: length %u < 3", avp_length);
+ break; /* exit outer loop, then cleanup & return */
+ }
+
if (length < avp_length) {
proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
"Not enough room in packet for AVP");
@@ -1425,20 +1445,32 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
length -= avp_length;
- dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(dict->attrs_by_id, GUINT_TO_POINTER(avp_type));
+ dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(dict->attrs_by_id, GUINT_TO_POINTER(avp_type.value));
if (!dictionary_entry) {
dictionary_entry = &no_dictionary_entry;
}
avp_item = proto_tree_add_bytes_format_value(tree, hf_radius_avp, tvb, offset, avp_length,
- NULL, "l=%u t=%s(%u)", avp_length,
- dictionary_entry->name, avp_type);
+ NULL, "l=%u t=%s", avp_length,
+ dictionary_entry->name);
+ if (avp_is_extended)
+ proto_item_append_text(avp_item, "(%u.%u)", avp_type0, avp_type1);
+ else
+ proto_item_append_text(avp_item, "(%u)", avp_type0);
avp_length -= 2;
offset += 2;
+ if (avp_is_extended) {
+ avp_length -= 1;
+ offset += 1;
+ }
+ if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
+ avp_length -= 1;
+ offset += 1;
+ }
- if (avp_type == RADIUS_ATTR_TYPE_VENDOR_SPECIFIC) {
+ if (avp_type0 == RADIUS_ATTR_TYPE_VENDOR_SPECIFIC || (avp_is_extended && avp_type1 == RADIUS_ATTR_TYPE_VENDOR_SPECIFIC)) {
radius_vendor_info_t *vendor;
proto_tree *vendor_tree;
gint max_offset = offset + avp_length;
@@ -1466,14 +1498,20 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
vendor_tree = proto_item_add_subtree(avp_item, vendor->ett);
- proto_tree_add_item(vendor_tree, hf_radius_avp_type, tvb, offset-6, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(vendor_tree, hf_radius_avp_length, tvb, offset-5, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(vendor_tree, hf_radius_avp_type, tvb, avp_offset_start, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(vendor_tree, hf_radius_avp_length, tvb, avp_offset_start+1, 1, ENC_BIG_ENDIAN);
+ if (avp_is_extended) {
+ proto_tree_add_item(vendor_tree, hf_radius_avp_extended_type, tvb, avp_offset_start+2, 1, ENC_BIG_ENDIAN);
+ }
+ if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
+ proto_tree_add_item(vendor_tree, hf_radius_avp_extended_more, tvb, avp_offset_start+3, 1, ENC_BIG_ENDIAN);
+ }
while (offset < max_offset) {
guint32 avp_vsa_type;
guint32 avp_vsa_len;
guint8 avp_vsa_flags = 0;
- guint32 avp_vsa_header_len = vendor->type_octets + vendor->length_octets + (vendor->has_flags ? 1 : 0);
+ guint32 avp_vsa_header_len;
switch (vendor->type_octets) {
case 1:
@@ -1491,19 +1529,25 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
avp_vsa_type = tvb_get_guint8(tvb, offset++);
}
- switch (vendor->length_octets) {
- case 1:
- avp_vsa_len = tvb_get_guint8(tvb, offset++);
- break;
- case 0:
- avp_vsa_len = avp_length;
- break;
- case 2:
- avp_vsa_len = tvb_get_ntohs(tvb, offset);
- offset += 2;
- break;
- default:
- avp_vsa_len = tvb_get_guint8(tvb, offset++);
+ if (!avp_is_extended) {
+ switch (vendor->length_octets) {
+ case 1:
+ avp_vsa_len = tvb_get_guint8(tvb, offset++);
+ break;
+ case 0:
+ avp_vsa_len = avp_length;
+ break;
+ case 2:
+ avp_vsa_len = tvb_get_ntohs(tvb, offset);
+ offset += 2;
+ break;
+ default:
+ avp_vsa_len = tvb_get_guint8(tvb, offset++);
+ }
+ avp_vsa_header_len = vendor->type_octets + vendor->length_octets + (vendor->has_flags ? 1 : 0);
+ } else {
+ avp_vsa_len = avp_length;
+ avp_vsa_header_len = vendor->type_octets + (vendor->has_flags ? 1 : 0);
}
if (vendor->has_flags) {
@@ -1603,8 +1647,8 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
avp_tree = proto_item_add_subtree(avp_item, dictionary_entry->ett);
- proto_tree_add_item(avp_tree, hf_radius_avp_type, tvb, offset-2, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(avp_tree, hf_radius_avp_length, tvb, offset-1, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(avp_tree, hf_radius_avp_type, tvb, avp_offset_start, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(avp_tree, hf_radius_avp_length, tvb, avp_offset_start+1, 1, ENC_BIG_ENDIAN);
if (show_length) {
avp_len_item = proto_tree_add_uint(avp_tree,
@@ -1613,7 +1657,14 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
PROTO_ITEM_SET_GENERATED(avp_len_item);
}
- if (avp_type == RADIUS_ATTR_TYPE_EAP_MESSAGE) {
+ if (avp_is_extended) {
+ proto_tree_add_item(avp_tree, hf_radius_avp_extended_type, tvb, avp_offset_start+2, 1, ENC_BIG_ENDIAN);
+ }
+ if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
+ proto_tree_add_item(avp_tree, hf_radius_avp_extended_more, tvb, avp_offset_start+3, 1, ENC_BIG_ENDIAN);
+ }
+
+ if (avp_type0 == RADIUS_ATTR_TYPE_EAP_MESSAGE) {
gint tvb_len;
eap_seg_num++;
@@ -1732,12 +1783,13 @@ dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tv
}
offset += avp_length;
- } else {
- add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry,
- avp_length, offset);
- offset += avp_length;
+ continue;
}
+ add_avp_to_tree(avp_tree, avp_item, pinfo, tvb, dictionary_entry,
+ avp_length, offset);
+ offset += avp_length;
+
} /* while (length > 0) */
CLEANUP_CALL_AND_POP_PFX(lb); /* vsa_buffer_table_destroy(vsa_buffer_table) */
@@ -2349,13 +2401,16 @@ register_vendors(gpointer k _U_, gpointer v, gpointer p)
}
extern void
-radius_register_avp_dissector(guint32 vendor_id, guint32 attribute_id, radius_avp_dissector_t radius_avp_dissector)
+radius_register_avp_dissector(guint32 vendor_id, guint32 _attribute_id, radius_avp_dissector_t radius_avp_dissector)
{
radius_vendor_info_t *vendor;
radius_attr_info_t *dictionary_entry;
GHashTable *by_id;
+ radius_attr_type_t attribute_id;
DISSECTOR_ASSERT(radius_avp_dissector != NULL);
+ memset(&attribute_id, 0, sizeof(attribute_id));
+ attribute_id.u8_code[0] = _attribute_id;
if (vendor_id) {
vendor = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(vendor_id));
@@ -2379,17 +2434,17 @@ radius_register_avp_dissector(guint32 vendor_id, guint32 attribute_id, radius_av
g_hash_table_insert(dict->vendors_by_name, (gpointer)(vendor->name), vendor);
}
- dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(vendor->attrs_by_id, GUINT_TO_POINTER(attribute_id));
+ dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(vendor->attrs_by_id, GUINT_TO_POINTER(attribute_id.value));
by_id = vendor->attrs_by_id;
} else {
- dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(dict->attrs_by_id, GUINT_TO_POINTER(attribute_id));
+ dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(dict->attrs_by_id, GUINT_TO_POINTER(attribute_id.value));
by_id = dict->attrs_by_id;
}
if (!dictionary_entry) {
dictionary_entry = (radius_attr_info_t *)g_malloc(sizeof(radius_attr_info_t));
- dictionary_entry->name = g_strdup_printf("Unknown-Attribute-%u", attribute_id);
+ dictionary_entry->name = g_strdup_printf("Unknown-Attribute-%u", attribute_id.value);
dictionary_entry->code = attribute_id;
dictionary_entry->encrypt = 0;
dictionary_entry->type = NULL;
@@ -2401,7 +2456,7 @@ radius_register_avp_dissector(guint32 vendor_id, guint32 attribute_id, radius_av
dictionary_entry->ett = no_dictionary_entry.ett;
dictionary_entry->tlvs_by_id = NULL;
- g_hash_table_insert(by_id, GUINT_TO_POINTER(dictionary_entry->code), dictionary_entry);
+ g_hash_table_insert(by_id, GUINT_TO_POINTER(dictionary_entry->code.value), dictionary_entry);
}
dictionary_entry->dissector = radius_avp_dissector;
@@ -2581,6 +2636,12 @@ register_radius_fields(const char *unused _U_)
{ &hf_radius_avp_type,
{ "AVP Type", "radius.avp.type", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
+ { &hf_radius_avp_extended_type,
+ { "AVP Extended Type", "radius.avp.extended_type", FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+ { &hf_radius_avp_extended_more,
+ { "AVP Extended More", "radius.avp.extended_more", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x80,
+ NULL, HFILL }},
{ &hf_radius_egress_vlanid_tag,
{ "Tag", "radius.egress_vlanid_tag", FT_UINT32, BASE_HEX, VALS(egress_vlan_tag_vals), 0xFF000000,
NULL, HFILL }},
diff --git a/epan/dissectors/packet-radius.h b/epan/dissectors/packet-radius.h
index 9ddf1054e5..93fed5b94c 100644
--- a/epan/dissectors/packet-radius.h
+++ b/epan/dissectors/packet-radius.h
@@ -78,6 +78,24 @@
*/
#define RADIUS_ATTR_TYPE_VENDOR_SPECIFIC 26
#define RADIUS_ATTR_TYPE_EAP_MESSAGE 79
+#define RADIUS_ATTR_TYPE_EXTENDED_1 241
+#define RADIUS_ATTR_TYPE_EXTENDED_2 242
+#define RADIUS_ATTR_TYPE_EXTENDED_3 243
+#define RADIUS_ATTR_TYPE_EXTENDED_4 244
+#define RADIUS_ATTR_TYPE_EXTENDED_5 245
+#define RADIUS_ATTR_TYPE_EXTENDED_6 246
+
+#define RADIUS_ATTR_TYPE_IS_EXTENDED(avp_type) \
+ ((avp_type) == RADIUS_ATTR_TYPE_EXTENDED_1 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_2 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_3 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_4 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_5 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_6)
+
+#define RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type) \
+ ((avp_type) == RADIUS_ATTR_TYPE_EXTENDED_5 || \
+ (avp_type) == RADIUS_ATTR_TYPE_EXTENDED_6)
typedef struct _radius_vendor_info_t {
@@ -95,9 +113,14 @@ typedef void (radius_attr_dissector_t)(radius_attr_info_t*, proto_tree*, packet_
typedef const gchar* (radius_avp_dissector_t)(proto_tree*,tvbuff_t*, packet_info*);
+typedef union _radius_attr_type_t {
+ guint8 u8_code[2];
+ guint value;
+} radius_attr_type_t;
+
struct _radius_attr_info_t {
gchar *name;
- guint code;
+ radius_attr_type_t code;
guint encrypt; /* 0 or value for "encrypt=" option */
gboolean tagged;
radius_attr_dissector_t* type;
diff --git a/epan/radius_dict.l b/epan/radius_dict.l
index 3dac0f7007..75553dff6d 100644
--- a/epan/radius_dict.l
+++ b/epan/radius_dict.l
@@ -271,7 +271,7 @@ static void add_value(Radius_scanner_state_t* state, const gchar* attrib_name, c
}
<ATTR>[0-9a-z_/.-]+ { yyextra->attr_name = g_strdup(yytext); yyextra->encrypted = 0; yyextra->has_tag = FALSE; BEGIN ATTR_W_NAME; }
-<ATTR_W_NAME>[0-9]+ { yyextra->attr_id = g_strdup(yytext); BEGIN ATTR_W_ID;}
+<ATTR_W_NAME>[0-9.]+ { yyextra->attr_id = g_strdup(yytext); BEGIN ATTR_W_ID;}
<ATTR_W_NAME>0x[0-9a-f]+ { yyextra->attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
<ATTR_W_ID>integer { yyextra->attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>string { yyextra->attr_type = radius_string; BEGIN ATTR_W_TYPE; }
@@ -449,7 +449,8 @@ static void add_vendor(Radius_scanner_state_t* state, const gchar* name, guint32
static gboolean add_attribute(Radius_scanner_state_t* state, const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* vendor, guint encrypted_flag, gboolean tagged, const gchar* attr) {
radius_attr_info_t* a;
GHashTable* by_id;
- guint32 code;
+ radius_attr_type_t code;
+ gchar *dot, *extcodestr = NULL;
if (attr){
return add_tlv(state, name, codestr, type, attr);
@@ -470,9 +471,18 @@ static gboolean add_attribute(Radius_scanner_state_t* state, const gchar* name,
by_id = state->dict->attrs_by_id;
}
- code= (guint32) strtoul(codestr, NULL, 10);
+ memset(&code, 0, sizeof(code));
+ dot = strchr(codestr, '.');
+ if (dot) {
+ *dot = '\0';
+ extcodestr = dot + 1;
+ }
+ code.u8_code[0] = (guint8) strtoul(codestr, NULL, 10);
+ if (extcodestr) {
+ code.u8_code[1] = (guint8) strtoul(extcodestr, NULL, 10);
+ }
- a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
+ a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code.value));
if (!a) {
/*
@@ -494,7 +504,7 @@ static gboolean add_attribute(Radius_scanner_state_t* state, const gchar* name,
a->hf_len = -1;
a->ett = -1;
a->tlvs_by_id = NULL;
- g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
+ g_hash_table_insert(by_id, GUINT_TO_POINTER(code.value),a);
g_hash_table_insert(state->dict->attrs_by_name,(gpointer) (a->name),a);
} else {
/*
@@ -537,7 +547,7 @@ static gboolean add_attribute(Radius_scanner_state_t* state, const gchar* name,
static gboolean add_tlv(Radius_scanner_state_t* state, const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* attr) {
radius_attr_info_t* a;
radius_attr_info_t* s;
- guint32 code;
+ radius_attr_type_t code;
a = (radius_attr_info_t*)g_hash_table_lookup(state->dict->attrs_by_name, attr);
@@ -556,9 +566,10 @@ static gboolean add_tlv(Radius_scanner_state_t* state, const gchar* name, const
a->tlvs_by_id = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_radius_attr_info);
}
- code = (guint32) strtoul(codestr, NULL, 10);
+ memset(&code, 0, sizeof(code));
+ code.u8_code[0] = (guint8) strtoul(codestr, NULL, 10);
- s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
+ s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code.value));
if (!s) {
/*
@@ -581,7 +592,7 @@ static gboolean add_tlv(Radius_scanner_state_t* state, const gchar* name, const
s->ett = -1;
s->tlvs_by_id = NULL;
- g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
+ g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code.value),s);
g_hash_table_insert(state->dict->tlvs_by_name,(gpointer) (s->name),s);
}
diff --git a/radius/dictionary b/radius/dictionary
index c642bf7179..b92b76fca3 100644
--- a/radius/dictionary
+++ b/radius/dictionary
@@ -115,30 +115,13 @@ $INCLUDE dictionary.rfc6519
$INCLUDE dictionary.rfc6572
$INCLUDE dictionary.rfc6677
$INCLUDE dictionary.rfc6911
-#
-# We do not support RFC 6929, so we comment this out.
-# See bug 13176.
-#
-#$INCLUDE dictionary.rfc6929
-#
-# We do not support RFC 6929, so we comment this out.
-# See bug 13176.
-#
-#$INCLUDE dictionary.rfc6930
+$INCLUDE dictionary.rfc6929
+$INCLUDE dictionary.rfc6930
$INCLUDE dictionary.rfc7055
#$INCLUDE dictionary.rfc7155
#$INCLUDE dictionary.rfc7268
-#
-# We do not support RFC 6929, so we comment these out. They cause
-#
-# radius: Vendor: 'integer', does not exist in {dictionary file}
-#
-# errors.
-#
-# See bug 13176.
-#
-#$INCLUDE dictionary.rfc7499
-#$INCLUDE dictionary.rfc7930
+$INCLUDE dictionary.rfc7499
+$INCLUDE dictionary.rfc7930
#