diff options
author | João Valverde <joao.valverde@tecnico.ulisboa.pt> | 2017-05-20 00:27:01 +0100 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2017-05-25 11:31:58 +0000 |
commit | da9363e202d7506674e232319d5fb6a7e05830ee (patch) | |
tree | 9165d5f41262a4570376828af46b52a4bf6d78e8 /epan | |
parent | fd9f698ed332f94a8a452a420d8b211950f456b7 (diff) |
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>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-radius.c | 131 | ||||
-rw-r--r-- | epan/dissectors/packet-radius.h | 25 | ||||
-rw-r--r-- | epan/radius_dict.l | 29 |
3 files changed, 140 insertions, 45 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); } |