/epan/dissectors/packet-radius.c
C | 1551 lines | 1200 code | 258 blank | 93 comment | 218 complexity | 317b8ba479245924762f7e95f8a3caa2 MD5 | raw file
- /* packet-radius.c
- *
- * Routines for RADIUS packet disassembly
- * Copyright 1999 Johan Feyaerts
- * Changed 03/12/2003 Rui Carmo (http://the.taoofmac.com - added all 3GPP VSAs, some parsing)
- * Changed 07/2005 Luis Ontanon <luis@ontanon.org> - use FreeRADIUS' dictionary
- * Changed 10/2006 Alejandro Vaquero <alejandrovaquero@yahoo.com> - add Conversations support
- * Changed 08/2015 Didier Arenzana <darenzana@yahoo.fr> - add response authenticator validation
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- *
- * References:
- *
- * RFC 2865 - Remote Authentication Dial In User Service (RADIUS)
- * RFC 2866 - RADIUS Accounting
- * RFC 2867 - RADIUS Accounting Modifications for Tunnel Protocol Support
- * RFC 2868 - RADIUS Attributes for Tunnel Protocol Support
- * 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
- *
- * http://www.iana.org/assignments/radius-types
- *
- * and see
- *
- * http://freeradius.org/radiusd/man/dictionary.html
- *
- * for the dictionary file syntax.
- */
- /*
- TO (re)DO: (see svn rev 14786)
- - dissect_3gpp_ipv6_dns_servers()
- */
- #include "config.h"
- #include <stdlib.h>
- #include <errno.h>
- #include <epan/packet.h>
- #include <epan/exceptions.h>
- #include <epan/expert.h>
- #include <epan/prefs.h>
- #include <epan/sminmpec.h>
- #include <epan/conversation.h>
- #include <epan/tap.h>
- #include <epan/rtd_table.h>
- #include <epan/addr_resolv.h>
- #include <wsutil/filesystem.h>
- #include <wsutil/report_message.h>
- #include <wsutil/wsgcrypt.h>
- #include "packet-radius.h"
- #include "packet-e212.h"
- void proto_register_radius(void);
- void proto_reg_handoff_radius(void);
- typedef struct _e_radiushdr {
- guint8 rh_code;
- guint8 rh_ident;
- guint16 rh_pktlength;
- } e_radiushdr;
- typedef struct {
- wmem_array_t *hf;
- wmem_array_t *ett;
- wmem_array_t *vend_vs;
- } hfett_t;
- #define AUTHENTICATOR_LENGTH 16
- #define RD_HDR_LENGTH 4
- #define HDR_LENGTH (RD_HDR_LENGTH + AUTHENTICATOR_LENGTH)
- /* Item of request list */
- typedef struct _radius_call_t
- {
- guint code;
- guint ident;
- guint8 req_authenticator[AUTHENTICATOR_LENGTH];
- guint32 req_num; /* frame number request seen */
- guint32 rsp_num; /* frame number response seen */
- guint32 rspcode;
- nstime_t req_time;
- gboolean responded;
- } radius_call_t;
- /* Container for tapping relevant data */
- typedef struct _radius_info_t
- {
- guint code;
- guint ident;
- nstime_t req_time;
- gboolean is_duplicate;
- gboolean request_available;
- guint32 req_num; /* frame number request seen */
- guint32 rspcode;
- } radius_info_t;
- /*
- * Default RADIUS ports:
- * 1645 (Authentication, pre RFC 2865)
- * 1646 (Accounting, pre RFC 2866)
- * 1812 (Authentication, RFC 2865)
- * 1813 (Accounting, RFC 2866)
- * 1700 (Dynamic Authorization Extensions, pre RFC 3576)
- * 3799 (Dynamic Authorization Extensions, RFC 3576)
- */
- #define DEFAULT_RADIUS_PORT_RANGE "1645,1646,1700,1812,1813,3799"
- static radius_dictionary_t *dict = NULL;
- static int proto_radius = -1;
- static int hf_radius_req = -1;
- static int hf_radius_rsp = -1;
- static int hf_radius_req_frame = -1;
- static int hf_radius_rsp_frame = -1;
- static int hf_radius_time = -1;
- static int hf_radius_dup = -1;
- static int hf_radius_req_dup = -1;
- static int hf_radius_rsp_dup = -1;
- static int hf_radius_id = -1;
- static int hf_radius_code = -1;
- static int hf_radius_length = -1;
- static int hf_radius_authenticator = -1;
- static int hf_radius_authenticator_valid = -1;
- static int hf_radius_authenticator_invalid = -1;
- static int hf_radius_chap_password = -1;
- static int hf_radius_chap_ident = -1;
- static int hf_radius_chap_string = -1;
- static int hf_radius_framed_ip_address = -1;
- static int hf_radius_login_ip_host = -1;
- static int hf_radius_framed_ipx_network = -1;
- static int hf_radius_cosine_vpi = -1;
- static int hf_radius_cosine_vci = -1;
- static int hf_radius_ascend_data_filter = -1;
- static int hf_radius_ascend_data_filter_type = -1;
- static int hf_radius_ascend_data_filter_filteror = -1;
- static int hf_radius_ascend_data_filter_inout = -1;
- static int hf_radius_ascend_data_filter_spare = -1;
- static int hf_radius_ascend_data_filter_src_ipv4 = -1;
- static int hf_radius_ascend_data_filter_dst_ipv4 = -1;
- static int hf_radius_ascend_data_filter_src_ipv6 = -1;
- static int hf_radius_ascend_data_filter_dst_ipv6 = -1;
- static int hf_radius_ascend_data_filter_src_ip_prefix = -1;
- static int hf_radius_ascend_data_filter_dst_ip_prefix = -1;
- static int hf_radius_ascend_data_filter_protocol = -1;
- static int hf_radius_ascend_data_filter_established = -1;
- static int hf_radius_ascend_data_filter_src_port = -1;
- static int hf_radius_ascend_data_filter_dst_port = -1;
- static int hf_radius_ascend_data_filter_src_port_qualifier = -1;
- static int hf_radius_ascend_data_filter_dst_port_qualifier = -1;
- static int hf_radius_ascend_data_filter_reserved = -1;
- static int hf_radius_vsa_fragment = -1;
- 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_vendor_id = -1;
- static int hf_radius_avp_vendor_type = -1;
- static int hf_radius_avp_vendor_len = -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;
- static int hf_radius_egress_vlanid_pad = -1;
- static int hf_radius_egress_vlanid = -1;
- static int hf_radius_egress_vlan_name_tag = -1;
- static int hf_radius_egress_vlan_name = -1;
- static gint ett_radius = -1;
- static gint ett_radius_avp = -1;
- static gint ett_radius_authenticator = -1;
- static gint ett_radius_ascend = -1;
- static gint ett_eap = -1;
- static gint ett_chap = -1;
- static expert_field ei_radius_invalid_length = EI_INIT;
- /*
- * Define the tap for radius
- */
- 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, 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;
- static const gchar *shared_secret = "";
- static gboolean validate_authenticator = FALSE;
- static gboolean show_length = FALSE;
- static gboolean disable_extended_attributes = FALSE;
- static guint8 authenticator[AUTHENTICATOR_LENGTH];
- /* http://www.iana.org/assignments/radius-types */
- static const value_string radius_pkt_type_codes[] =
- {
- {RADIUS_PKT_TYPE_ACCESS_REQUEST, "Access-Request"}, /* 1 RFC2865 */
- {RADIUS_PKT_TYPE_ACCESS_ACCEPT, "Access-Accept"}, /* 2 RFC2865 */
- {RADIUS_PKT_TYPE_ACCESS_REJECT, "Access-Reject"}, /* 3 RFC2865 */
- {RADIUS_PKT_TYPE_ACCOUNTING_REQUEST, "Accounting-Request"}, /* 4 RFC2865 */
- {RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE, "Accounting-Response"}, /* 5 RFC2865 */
- {RADIUS_PKT_TYPE_ACCOUNTING_STATUS, "Accounting-Status"}, /* 6 RFC3575 */
- {RADIUS_PKT_TYPE_PASSWORD_REQUEST, "Password-Request"}, /* 7 RFC3575 */
- {RADIUS_PKT_TYPE_PASSWORD_ACK, "Password-Ack"}, /* 8 RFC3575 */
- {RADIUS_PKT_TYPE_PASSWORD_REJECT, "Password-Reject"}, /* 9 RFC3575 */
- {RADIUS_PKT_TYPE_ACCOUNTING_MESSAGE, "Accounting-Message"}, /* 10 RFC3575 */
- {RADIUS_PKT_TYPE_ACCESS_CHALLENGE, "Access-Challenge"}, /* 11 RFC2865 */
- {RADIUS_PKT_TYPE_STATUS_SERVER, "Status-Server"}, /* 12 RFC2865 */
- {RADIUS_PKT_TYPE_STATUS_CLIENT, "Status-Client"}, /* 13 RFC2865 */
- {RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST, "Resource-Free-Request"}, /* 21 RFC3575 */
- {RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE, "Resource-Free-Response"}, /* 22 RFC3575 */
- {RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST, "Resource-Query-Request"}, /* 23 RFC3575 */
- {RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE, "Query_Response"}, /* 24 RFC3575 */
- {RADIUS_PKT_TYPE_ALTERNATE_RESOURCE_RECLAIM_REQUEST, "Alternate-Resource-Reclaim-Request"}, /* 25 RFC3575 */
- {RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST, "NAS-Reboot-Request"}, /* 26 RFC3575 */
- {RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE, "NAS-Reboot-Response"}, /* 27 RFC3575 */
- {RADIUS_PKT_TYPE_NEXT_PASSCODE, "Next-Passcode"}, /* 29 RFC3575 */
- {RADIUS_PKT_TYPE_NEW_PIN, "New-Pin"}, /* 30 RFC3575 */
- {RADIUS_PKT_TYPE_TERMINATE_SESSION, "Terminate-Session"}, /* 31 RFC3575 */
- {RADIUS_PKT_TYPE_PASSWORD_EXPIRED, "Password-Expired"}, /* 32 RFC3575 */
- {RADIUS_PKT_TYPE_EVENT_REQUEST, "Event-Request"}, /* 33 RFC3575 */
- {RADIUS_PKT_TYPE_EVENT_RESPONSE, "Event-Response"}, /* 34 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_DISCONNECT_REQUEST, "Disconnect-Request"}, /* 40 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_DISCONNECT_ACK, "Disconnect-ACK"}, /* 41 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_DISCONNECT_NAK, "Disconnect-NAK"}, /* 42 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_COA_REQUEST, "CoA-Request"}, /* 43 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_COA_ACK, "CoA-ACK"}, /* 44 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_COA_NAK, "CoA-NAK"}, /* 45 RFC3575|RFC5176 */
- {RADIUS_PKT_TYPE_IP_ADDRESS_ALLOCATE, "IP-Address-Allocate"}, /* 50 RFC3575 */
- {RADIUS_PKT_TYPE_IP_ADDRESS_RELEASE, "IP-Address-Release"}, /* 51 RFC3575 */
- {RADIUS_PKT_TYPE_ALU_STATE_REQUEST, "ALU-State-Request"}, /* 129 ALU AAA */
- {RADIUS_PKT_TYPE_ALU_STATE_ACCEPT, "ALU-State-Accept"}, /* 130 ALU AAA */
- {RADIUS_PKT_TYPE_ALU_STATE_REJECT, "ALU-State-Reject"}, /* 131 ALU AAA */
- {RADIUS_PKT_TYPE_ALU_STATE_ERROR, "ALU-State-Error"}, /* 132 ALU AAA */
- /*
- 250-253 Experimental Use [RFC3575]
- 254-255 Reserved [RFC3575]
- */
- {0, NULL}
- };
- static value_string_ext radius_pkt_type_codes_ext = VALUE_STRING_EXT_INIT(radius_pkt_type_codes);
- typedef enum _radius_category {
- RADIUS_CAT_OVERALL = 0,
- RADIUS_CAT_ACCESS,
- RADIUS_CAT_ACCOUNTING,
- RADIUS_CAT_PASSWORD,
- RADIUS_CAT_RESOURCE_FREE,
- RADIUS_CAT_RESOURCE_QUERY,
- RADIUS_CAT_NAS_REBOOT,
- RADIUS_CAT_EVENT,
- RADIUS_CAT_DISCONNECT,
- RADIUS_CAT_COA,
- RADIUS_CAT_OTHERS,
- RADIUS_CAT_NUM_TIMESTATS
- } radius_category;
- static const value_string radius_message_code[] = {
- { RADIUS_CAT_OVERALL, "Overall"},
- { RADIUS_CAT_ACCESS, "Access"},
- { RADIUS_CAT_ACCOUNTING, "Accounting"},
- { RADIUS_CAT_PASSWORD, "Password"},
- { RADIUS_CAT_RESOURCE_FREE, "Resource Free"},
- { RADIUS_CAT_RESOURCE_QUERY, "Resource Query"},
- { RADIUS_CAT_NAS_REBOOT, "NAS Reboot"},
- { RADIUS_CAT_EVENT, "Event"},
- { RADIUS_CAT_DISCONNECT, "Disconnect"},
- { RADIUS_CAT_COA, "CoA"},
- { RADIUS_CAT_OTHERS, "Other"},
- { 0, NULL}
- };
- static tap_packet_status
- radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
- {
- rtd_data_t *rtd_data = (rtd_data_t *)prs;
- rtd_stat_table *rs = &rtd_data->stat_table;
- const radius_info_t *ri = (const radius_info_t *)pri;
- nstime_t delta;
- radius_category radius_cat = RADIUS_CAT_OTHERS;
- tap_packet_status ret = TAP_PACKET_DONT_REDRAW;
- switch (ri->code) {
- case RADIUS_PKT_TYPE_ACCESS_REQUEST:
- case RADIUS_PKT_TYPE_ACCESS_ACCEPT:
- case RADIUS_PKT_TYPE_ACCESS_REJECT:
- radius_cat = RADIUS_CAT_ACCESS;
- break;
- case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST:
- case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE:
- radius_cat = RADIUS_CAT_ACCOUNTING;
- break;
- case RADIUS_PKT_TYPE_PASSWORD_REQUEST:
- case RADIUS_PKT_TYPE_PASSWORD_ACK:
- case RADIUS_PKT_TYPE_PASSWORD_REJECT:
- radius_cat = RADIUS_CAT_PASSWORD;
- break;
- case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST:
- case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE:
- radius_cat = RADIUS_CAT_RESOURCE_FREE;
- break;
- case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST:
- case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE:
- radius_cat = RADIUS_CAT_RESOURCE_QUERY;
- break;
- case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST:
- case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE:
- radius_cat = RADIUS_CAT_NAS_REBOOT;
- break;
- case RADIUS_PKT_TYPE_EVENT_REQUEST:
- case RADIUS_PKT_TYPE_EVENT_RESPONSE:
- radius_cat = RADIUS_CAT_EVENT;
- break;
- case RADIUS_PKT_TYPE_DISCONNECT_REQUEST:
- case RADIUS_PKT_TYPE_DISCONNECT_ACK:
- case RADIUS_PKT_TYPE_DISCONNECT_NAK:
- radius_cat = RADIUS_CAT_DISCONNECT;
- break;
- case RADIUS_PKT_TYPE_COA_REQUEST:
- case RADIUS_PKT_TYPE_COA_ACK:
- case RADIUS_PKT_TYPE_COA_NAK:
- radius_cat = RADIUS_CAT_COA;
- break;
- }
- switch (ri->code) {
- case RADIUS_PKT_TYPE_ACCESS_REQUEST:
- case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST:
- case RADIUS_PKT_TYPE_PASSWORD_REQUEST:
- case RADIUS_PKT_TYPE_EVENT_REQUEST:
- case RADIUS_PKT_TYPE_DISCONNECT_REQUEST:
- case RADIUS_PKT_TYPE_COA_REQUEST:
- if (ri->is_duplicate) {
- /* Duplicate is ignored */
- rs->time_stats[RADIUS_CAT_OVERALL].req_dup_num++;
- rs->time_stats[radius_cat].req_dup_num++;
- } else {
- rs->time_stats[RADIUS_CAT_OVERALL].open_req_num++;
- rs->time_stats[radius_cat].open_req_num++;
- }
- break;
- case RADIUS_PKT_TYPE_ACCESS_ACCEPT:
- case RADIUS_PKT_TYPE_ACCESS_REJECT:
- case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE:
- case RADIUS_PKT_TYPE_PASSWORD_ACK:
- case RADIUS_PKT_TYPE_PASSWORD_REJECT:
- case RADIUS_PKT_TYPE_EVENT_RESPONSE:
- case RADIUS_PKT_TYPE_DISCONNECT_ACK:
- case RADIUS_PKT_TYPE_DISCONNECT_NAK:
- case RADIUS_PKT_TYPE_COA_ACK:
- case RADIUS_PKT_TYPE_COA_NAK:
- if (ri->is_duplicate) {
- /* Duplicate is ignored */
- rs->time_stats[RADIUS_CAT_OVERALL].rsp_dup_num++;
- rs->time_stats[radius_cat].rsp_dup_num++;
- } else if (!ri->request_available) {
- /* no request was seen */
- rs->time_stats[RADIUS_CAT_OVERALL].disc_rsp_num++;
- rs->time_stats[radius_cat].disc_rsp_num++;
- } else {
- rs->time_stats[RADIUS_CAT_OVERALL].open_req_num--;
- rs->time_stats[radius_cat].open_req_num--;
- /* calculate time delta between request and response */
- nstime_delta(&delta, &pinfo->abs_ts, &ri->req_time);
- time_stat_update(&(rs->time_stats[RADIUS_CAT_OVERALL].rtd[0]),&delta, pinfo);
- time_stat_update(&(rs->time_stats[radius_cat].rtd[0]),&delta, pinfo);
- ret = TAP_PACKET_REDRAW;
- }
- break;
- default:
- break;
- }
- return ret;
- }
- /*
- * Init Hash table stuff for conversation
- */
- typedef struct _radius_call_info_key
- {
- guint code;
- guint ident;
- conversation_t *conversation;
- nstime_t req_time;
- } radius_call_info_key;
- static wmem_map_t *radius_calls;
- typedef struct _radius_vsa_buffer_key
- {
- guint32 vendor_id;
- guint32 vsa_type;
- } radius_vsa_buffer_key;
- typedef struct _radius_vsa_buffer
- {
- radius_vsa_buffer_key key;
- guint8 *data;
- guint seg_num;
- guint len;
- } radius_vsa_buffer;
- static gint
- radius_vsa_equal(gconstpointer k1, gconstpointer k2)
- {
- const radius_vsa_buffer_key *key1 = (const radius_vsa_buffer_key *) k1;
- const radius_vsa_buffer_key *key2 = (const radius_vsa_buffer_key *) k2;
- return (((key1->vendor_id == key2->vendor_id) &&
- (key1->vsa_type == key2->vsa_type)
- ) ? TRUE : FALSE);
- }
- static guint
- radius_vsa_hash(gconstpointer k)
- {
- const radius_vsa_buffer_key *key = (const radius_vsa_buffer_key *) k;
- return key->vendor_id + key->vsa_type;
- }
- /* Compare 2 keys */
- static gboolean
- radius_call_equal(gconstpointer k1, gconstpointer k2)
- {
- const radius_call_info_key *key1 = (const radius_call_info_key *) k1;
- const radius_call_info_key *key2 = (const radius_call_info_key *) k2;
- if (key1->ident == key2->ident && key1->conversation == key2->conversation) {
- if (key1->code == key2->code)
- return TRUE;
- /* check the request and response are of the same code type */
- if ((key1->code == RADIUS_PKT_TYPE_ACCESS_REQUEST) &&
- ((key2->code == RADIUS_PKT_TYPE_ACCESS_ACCEPT) ||
- (key2->code == RADIUS_PKT_TYPE_ACCESS_REJECT) ||
- (key2->code == RADIUS_PKT_TYPE_ACCESS_CHALLENGE)))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_ACCESS_REQUEST) &&
- ((key1->code == RADIUS_PKT_TYPE_ACCESS_ACCEPT) ||
- (key1->code == RADIUS_PKT_TYPE_ACCESS_REJECT) ||
- (key1->code == RADIUS_PKT_TYPE_ACCESS_CHALLENGE)))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST) &&
- (key2->code == RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_ACCOUNTING_REQUEST) &&
- (key1->code == RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_PASSWORD_REQUEST) &&
- ((key2->code == RADIUS_PKT_TYPE_PASSWORD_ACK) ||
- (key2->code == RADIUS_PKT_TYPE_PASSWORD_REJECT)))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_PASSWORD_REQUEST) &&
- ((key1->code == RADIUS_PKT_TYPE_PASSWORD_ACK) ||
- (key1->code == RADIUS_PKT_TYPE_PASSWORD_REJECT)))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST) &&
- (key2->code == RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST) &&
- (key1->code == RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST) &&
- (key2->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST) &&
- (key1->code == RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST) &&
- (key2->code == RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST) &&
- (key1->code == RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_EVENT_REQUEST) &&
- (key2->code == RADIUS_PKT_TYPE_EVENT_RESPONSE))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_EVENT_REQUEST) &&
- (key1->code == RADIUS_PKT_TYPE_EVENT_RESPONSE))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_DISCONNECT_REQUEST) &&
- ((key2->code == RADIUS_PKT_TYPE_DISCONNECT_ACK) ||
- (key2->code == RADIUS_PKT_TYPE_DISCONNECT_NAK)))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_DISCONNECT_REQUEST) &&
- ((key1->code == RADIUS_PKT_TYPE_DISCONNECT_ACK) ||
- (key1->code == RADIUS_PKT_TYPE_DISCONNECT_NAK)))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_COA_REQUEST) &&
- ((key2->code == RADIUS_PKT_TYPE_COA_ACK) ||
- (key2->code == RADIUS_PKT_TYPE_COA_NAK)))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_COA_REQUEST) &&
- ((key1->code == RADIUS_PKT_TYPE_COA_ACK) ||
- (key1->code == RADIUS_PKT_TYPE_COA_NAK)))
- return TRUE;
- if ((key1->code == RADIUS_PKT_TYPE_ALU_STATE_REQUEST) &&
- ((key2->code == RADIUS_PKT_TYPE_ALU_STATE_ACCEPT) ||
- (key2->code == RADIUS_PKT_TYPE_ALU_STATE_REJECT) ||
- (key2->code == RADIUS_PKT_TYPE_ALU_STATE_ERROR)))
- return TRUE;
- if ((key2->code == RADIUS_PKT_TYPE_ALU_STATE_REQUEST) &&
- ((key1->code == RADIUS_PKT_TYPE_ALU_STATE_ACCEPT) ||
- (key1->code == RADIUS_PKT_TYPE_ALU_STATE_REJECT) ||
- (key1->code == RADIUS_PKT_TYPE_ALU_STATE_ERROR)))
- return TRUE;
- }
- return FALSE;
- }
- /* Calculate a hash key */
- static guint
- radius_call_hash(gconstpointer k)
- {
- const radius_call_info_key *key = (const radius_call_info_key *) k;
- return key->ident + key->conversation->conv_index;
- }
- static const gchar *
- dissect_chap_password(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- proto_item *ti;
- proto_tree *chap_tree;
- len = tvb_reported_length(tvb);
- if (len != 17)
- return "[wrong length for CHAP-Password]";
- ti = proto_tree_add_item(tree, hf_radius_chap_password, tvb, 0, len, ENC_NA);
- chap_tree = proto_item_add_subtree(ti, ett_chap);
- proto_tree_add_item(chap_tree, hf_radius_chap_ident, tvb, 0, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(chap_tree, hf_radius_chap_string, tvb, 1, 16, ENC_NA);
- return (tvb_bytes_to_str(wmem_packet_scope(), tvb, 0, len));
- }
- static const gchar *
- dissect_framed_ip_address(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- guint32 ip;
- guint32 ip_h;
- const gchar *str;
- len = tvb_reported_length(tvb);
- if (len != 4)
- return "[wrong length for IP address]";
- ip = tvb_get_ipv4(tvb, 0);
- ip_h = g_ntohl(ip);
- if (ip_h == 0xFFFFFFFF) {
- str = "Negotiated";
- proto_tree_add_ipv4_format_value(tree, hf_radius_framed_ip_address,
- tvb, 0, len, ip, "%s", str);
- } else if (ip_h == 0xFFFFFFFE) {
- str = "Assigned";
- proto_tree_add_ipv4_format_value(tree, hf_radius_framed_ip_address,
- tvb, 0, len, ip, "%s", str);
- } else {
- str = tvb_ip_to_str(pinfo->pool, tvb, 0);
- proto_tree_add_item(tree, hf_radius_framed_ip_address,
- tvb, 0, len, ENC_BIG_ENDIAN);
- }
- return str;
- }
- static const gchar *
- dissect_login_ip_host(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- guint32 ip;
- guint32 ip_h;
- const gchar *str;
- len = tvb_reported_length(tvb);
- if (len != 4)
- return "[wrong length for IP address]";
- ip = tvb_get_ipv4(tvb, 0);
- ip_h = g_ntohl(ip);
- if (ip_h == 0xFFFFFFFF) {
- str = "User-selected";
- proto_tree_add_ipv4_format_value(tree, hf_radius_login_ip_host,
- tvb, 0, len, ip, "%s", str);
- } else if (ip_h == 0) {
- str = "NAS-selected";
- proto_tree_add_ipv4_format_value(tree, hf_radius_login_ip_host,
- tvb, 0, len, ip, "%s", str);
- } else {
- str = tvb_ip_to_str(pinfo->pool, tvb, 0);
- proto_tree_add_item(tree, hf_radius_login_ip_host,
- tvb, 0, len, ENC_BIG_ENDIAN);
- }
- return str;
- }
- static const value_string ascenddf_filtertype[] = { {0, "generic"}, {1, "ipv4"}, {3, "ipv6"}, {0, NULL} };
- static const value_string ascenddf_filteror[] = { {0, "drop"}, {1, "forward"}, {0, NULL} };
- static const value_string ascenddf_inout[] = { {0, "out"}, {1, "in"}, {0, NULL} };
- static const value_string ascenddf_proto[] = { {1, "icmp"}, {6, "tcp"}, {17, "udp"}, {0, NULL} };
- static const value_string ascenddf_portq[] = { {1, "lt"}, {2, "eq"}, {3, "gt"}, {4, "ne"}, {0, NULL} };
- static const gchar *
- dissect_ascend_data_filter(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- wmem_strbuf_t *filterstr;
- proto_item *ti;
- proto_tree *ascend_tree;
- int len;
- guint8 type, proto, srclen, dstlen;
- address srcip, dstip;
- guint16 srcport, dstport;
- guint8 srcportq, dstportq;
- guint8 iplen = 4;
- guint offset = 0;
- len=tvb_reported_length(tvb);
- if (len != 24 && len != 48) {
- return wmem_strdup_printf(wmem_packet_scope(), "Wrong attribute length %d", len);
- }
- filterstr = wmem_strbuf_sized_new(wmem_packet_scope(), 128, 128);
- ti = proto_tree_add_item(tree, hf_radius_ascend_data_filter, tvb, 0, -1, ENC_NA);
- ascend_tree = proto_item_add_subtree(ti, ett_radius_ascend);
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_type, tvb, offset, 1, ENC_BIG_ENDIAN);
- type = tvb_get_guint8(tvb, 0);
- offset += 1;
- if (type == 3) { /* IPv6 */
- iplen = 16;
- }
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_filteror, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_inout, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_spare, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- if (type == 3) { /* IPv6 */
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ipv6, tvb, offset, 16, ENC_NA);
- offset += 16;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ipv6, tvb, offset, 16, ENC_NA);
- offset += 16;
- } else { /* IPv4 */
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
- offset += 4;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
- offset += 4;
- }
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_ip_prefix, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_ip_prefix, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_established, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_port, tvb, offset, 2, ENC_BIG_ENDIAN);
- offset += 2;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_port, tvb, offset, 2, ENC_BIG_ENDIAN);
- offset += 2;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_src_port_qualifier, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_dst_port_qualifier, tvb, offset, 1, ENC_BIG_ENDIAN);
- offset += 1;
- proto_tree_add_item(ascend_tree, hf_radius_ascend_data_filter_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
- wmem_strbuf_append_printf(filterstr, "%s %s %s",
- val_to_str(type, ascenddf_filtertype, "%u"),
- val_to_str(tvb_get_guint8(tvb, 2), ascenddf_inout, "%u"),
- val_to_str(tvb_get_guint8(tvb, 1), ascenddf_filteror, "%u"));
- proto = tvb_get_guint8(tvb, 6+iplen*2);
- if (proto) {
- wmem_strbuf_append_printf(filterstr, " %s",
- val_to_str(proto, ascenddf_proto, "%u"));
- }
- if (type == 3) { /* IPv6 */
- set_address_tvb(&srcip, AT_IPv6, 16, tvb, 4);
- } else {
- set_address_tvb(&srcip, AT_IPv4, 4, tvb, 4);
- }
- srclen = tvb_get_guint8(tvb, 4+iplen*2);
- srcport = tvb_get_ntohs(tvb, 9+iplen*2);
- srcportq = tvb_get_guint8(tvb, 12+iplen*2);
- if (srclen || srcportq) {
- wmem_strbuf_append_printf(filterstr, " srcip %s/%d", address_to_display(wmem_packet_scope(), &srcip), srclen);
- if (srcportq)
- wmem_strbuf_append_printf(filterstr, " srcport %s %d",
- val_to_str(srcportq, ascenddf_portq, "%u"), srcport);
- }
- if (type == 3) { /* IPv6-*/
- set_address_tvb(&dstip, AT_IPv6, 16, tvb, 4+iplen);
- } else {
- set_address_tvb(&dstip, AT_IPv4, 4, tvb, 4+iplen);
- }
- dstlen = tvb_get_guint8(tvb, 5+iplen*2);
- dstport = tvb_get_ntohs(tvb, 10+iplen*2);
- dstportq = tvb_get_guint8(tvb, 13+iplen*2);
- if (dstlen || dstportq) {
- wmem_strbuf_append_printf(filterstr, " dstip %s/%d", address_to_display(wmem_packet_scope(), &dstip), dstlen);
- if (dstportq)
- wmem_strbuf_append_printf(filterstr, " dstport %s %d",
- val_to_str(dstportq, ascenddf_portq, "%u"), dstport);
- }
- return wmem_strbuf_get_str(filterstr);
- }
- static const gchar *
- dissect_framed_ipx_network(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- guint32 net;
- const gchar *str;
- len = tvb_reported_length(tvb);
- if (len != 4)
- return "[wrong length for IPX network]";
- net = tvb_get_ntohl(tvb, 0);
- if (net == 0xFFFFFFFE)
- str = "NAS-selected";
- else
- str = wmem_strdup_printf(wmem_packet_scope(), "0x%08X", net);
- proto_tree_add_ipxnet_format_value(tree, hf_radius_framed_ipx_network, tvb, 0,
- len, net, "Framed-IPX-Network: %s", str);
- return str;
- }
- static const gchar *
- dissect_cosine_vpvc(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- guint vpi, vci;
- if (tvb_reported_length(tvb) != 4)
- return "[Wrong Length for VP/VC AVP]";
- vpi = tvb_get_ntohs(tvb, 0);
- vci = tvb_get_ntohs(tvb, 2);
- proto_tree_add_uint(tree, hf_radius_cosine_vpi, tvb, 0, 2, vpi);
- proto_tree_add_uint(tree, hf_radius_cosine_vci, tvb, 2, 2, vci);
- return wmem_strdup_printf(wmem_packet_scope(), "%u/%u", vpi, vci);
- }
- static const value_string daylight_saving_time_vals[] = {
- {0, "No adjustment"},
- {1, "+1 hour adjustment for Daylight Saving Time"},
- {2, "+2 hours adjustment for Daylight Saving Time"},
- {3, "Reserved"},
- {0, NULL}
- };
- static const gchar *
- dissect_radius_3gpp_imsi(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)
- {
- return dissect_e212_utf8_imsi(tvb, pinfo, tree, 0, tvb_reported_length(tvb));
- }
- static const gchar *
- dissect_radius_3gpp_ms_tmime_zone(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int offset = 0;
- guint8 oct, daylight_saving_time;
- char sign;
- /* 3GPP TS 23.040 version 6.6.0 Release 6
- * 9.2.3.11 TP-Service-Centre-Time-Stamp (TP-SCTS)
- * :
- * The Time Zone indicates the difference, expressed in quarters of an hour,
- * between the local time and GMT. In the first of the two semi-octets,
- * the first bit (bit 3 of the seventh octet of the TP-Service-Centre-Time-Stamp field)
- * represents the algebraic sign of this difference (0: positive, 1: negative).
- */
- oct = tvb_get_guint8(tvb, offset);
- sign = (oct & 0x08) ? '-' : '+';
- oct = (oct >> 4) + (oct & 0x07) * 10;
- daylight_saving_time = tvb_get_guint8(tvb, offset+1) & 0x3;
- proto_tree_add_bytes_format_value(tree, hf_radius_3gpp_ms_tmime_zone, tvb, offset, 2, NULL,
- "GMT %c%d hours %d minutes %s", sign, oct / 4, oct % 4 * 15,
- val_to_str_const(daylight_saving_time, daylight_saving_time_vals, "Unknown"));
- return wmem_strdup_printf(wmem_packet_scope(), "Timezone: GMT %c%d hours %d minutes %s ",
- sign, oct / 4, oct % 4 * 15, val_to_str_const(daylight_saving_time, daylight_saving_time_vals, "Unknown"));
- }
- static const value_string egress_vlan_tag_vals[] = {
- { 0x31, "Tagged"},
- { 0x32, "Untagged"},
- { 0, NULL}
- };
- static const gchar *
- dissect_rfc4675_egress_vlanid(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- guint32 vlanid;
- len = tvb_reported_length(tvb);
- if (len != 4)
- return "[wrong length for Egress-VLANID ]";
- proto_tree_add_item(tree, hf_radius_egress_vlanid_tag, tvb, 0, 4, ENC_BIG_ENDIAN);
- proto_tree_add_item(tree, hf_radius_egress_vlanid_pad, tvb, 0, 4, ENC_BIG_ENDIAN);
- proto_tree_add_item(tree, hf_radius_egress_vlanid, tvb, 0, 4, ENC_BIG_ENDIAN);
- vlanid = tvb_get_ntohl(tvb, 0);
- return wmem_strdup_printf(wmem_packet_scope(), "%s, Vlan ID: %u",
- val_to_str_const(((vlanid&0xFF000000)>>24), egress_vlan_tag_vals, "Unknown"), vlanid&0xFFF);
- }
- static const gchar *
- dissect_rfc4675_egress_vlan_name(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo _U_)
- {
- int len;
- guint8 tag;
- const guint8 *name;
- len = tvb_reported_length(tvb);
- if (len < 2)
- return "[wrong length for Egress-VLAN-Name ]";
- proto_tree_add_item(tree, hf_radius_egress_vlan_name_tag, tvb, 0, 1, ENC_BIG_ENDIAN);
- tag = tvb_get_guint8(tvb, 0);
- len -= 1;
- proto_tree_add_item_ret_string(tree, hf_radius_egress_vlan_name, tvb, 1, len, ENC_ASCII|ENC_NA, wmem_packet_scope(), &name);
- return wmem_strdup_printf(wmem_packet_scope(), "%s, Vlan Name: %s",
- val_to_str_const(tag, egress_vlan_tag_vals, "Unknown"), name);
- }
- static void
- radius_decrypt_avp(gchar *dest, int dest_len, tvbuff_t *tvb, int offset, int length)
- {
- gcry_md_hd_t md5_handle;
- guint8 digest[HASH_MD5_LENGTH];
- int i, j;
- gint totlen = 0, returned_length, padded_length;
- guint8 *pd;
- guchar c;
- DISSECTOR_ASSERT(dest_len > 0);
- dest[0] = '\0';
- if (length <= 0)
- return;
- /* The max avp length is 253 (255 - 2 for type & length), but only the
- * User-Password is marked with encrypt=1 in dictionary.rfc2865, and the
- * User-Password max length is only 128 (130 - 2 for type & length) per
- * tools.ietf.org/html/rfc2865#section-5.2, so enforce that limit here.
- */
- if (length > 128)
- length = 128;
- if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) {
- return;
- }
- gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
- gcry_md_write(md5_handle, authenticator, AUTHENTICATOR_LENGTH);
- memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
- padded_length = length + ((length % AUTHENTICATOR_LENGTH) ?
- (AUTHENTICATOR_LENGTH - (length % AUTHENTICATOR_LENGTH)) : 0);
- pd = (guint8 *)wmem_alloc0(wmem_packet_scope(), padded_length);
- tvb_memcpy(tvb, pd, offset, length);
- for (i = 0; i < padded_length; i += AUTHENTICATOR_LENGTH) {
- for (j = 0; j < AUTHENTICATOR_LENGTH; j++) {
- c = pd[i + j] ^ digest[j];
- if (g_ascii_isprint(c)) {
- returned_length = snprintf(&dest[totlen], dest_len - totlen,
- "%c", c);
- totlen += MIN(returned_length, dest_len - totlen - 1);
- }
- else if (c) {
- returned_length = snprintf(&dest[totlen], dest_len - totlen,
- "\\%03o", c);
- totlen += MIN(returned_length, dest_len - totlen - 1);
- }
- }
- gcry_md_reset(md5_handle);
- gcry_md_write(md5_handle, (const guint8 *)shared_secret, (int)strlen(shared_secret));
- gcry_md_write(md5_handle, &pd[i], AUTHENTICATOR_LENGTH);
- memcpy(digest, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
- }
- gcry_md_close(md5_handle);
- }
- static void
- add_avp_to_tree_with_dissector(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_avp_dissector_t *avp_dissector, guint32 avp_length, guint32 offset);
- void
- radius_integer(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- guint32 uintv;
- switch (len) {
- case 1:
- uintv = tvb_get_guint8(tvb, offset);
- break;
- case 2:
- uintv = tvb_get_ntohs(tvb, offset);
- break;
- case 3:
- uintv = tvb_get_ntoh24(tvb, offset);
- break;
- case 4:
- uintv = tvb_get_ntohl(tvb, offset);
- break;
- case 8: {
- guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
- proto_tree_add_uint64(tree, a->hf_alt, tvb, offset, len, uintv64);
- proto_item_append_text(avp_item, "%" PRIu64, uintv64);
- return;
- }
- default:
- proto_item_append_text(avp_item, "[unhandled integer length(%u)]", len);
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
- if (a->vs) {
- proto_item_append_text(avp_item, "%s(%u)", val_to_str_const(uintv, a->vs, "Unknown"), uintv);
- } else {
- proto_item_append_text(avp_item, "%u", uintv);
- }
- }
- void
- radius_signed(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- guint32 uintv;
- switch (len) {
- case 1:
- uintv = tvb_get_guint8(tvb, offset);
- break;
- case 2:
- uintv = tvb_get_ntohs(tvb, offset);
- break;
- case 3:
- uintv = tvb_get_ntoh24(tvb, offset);
- break;
- case 4:
- uintv = tvb_get_ntohl(tvb, offset);
- break;
- case 8: {
- guint64 uintv64 = tvb_get_ntoh64(tvb, offset);
- proto_tree_add_int64(tree, a->hf_alt, tvb, offset, len, uintv64);
- proto_item_append_text(avp_item, "%" PRIu64, uintv64);
- return;
- }
- default:
- proto_item_append_text(avp_item, "[unhandled signed integer length(%u)]", len);
- return;
- }
- proto_tree_add_int(tree, a->hf, tvb, offset, len, uintv);
- if (a->vs) {
- proto_item_append_text(avp_item, "%s(%d)", val_to_str_const(uintv, a->vs, "Unknown"), uintv);
- } else {
- proto_item_append_text(avp_item, "%d", uintv);
- }
- }
- void
- radius_string(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- switch (a->encrypt) {
- case 0: /* not encrypted */
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_UTF_8|ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_format_text(pinfo->pool, tvb, offset, len));
- break;
- case 1: /* encrypted like User-Password as defined in RFC 2865 */
- if (*shared_secret == '\0') {
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- } else {
- gchar *buffer;
- buffer = (gchar *)wmem_alloc(wmem_packet_scope(), 1024); /* an AVP value can be at most 253 bytes */
- radius_decrypt_avp(buffer, 1024, tvb, offset, len);
- proto_item_append_text(avp_item, "Decrypted: %s", buffer);
- proto_tree_add_string(tree, a->hf, tvb, offset, len, buffer);
- }
- break;
- case 2: /* encrypted like Tunnel-Password as defined in RFC 2868 */
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- break;
- case 3: /* encrypted like Ascend-Send-Secret as defined by Ascend^WLucent^WAlcatel-Lucent */
- proto_item_append_text(avp_item, "Encrypted");
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- break;
- }
- }
- void
- radius_octets(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (len == 0) {
- proto_item_append_text(avp_item, "[wrong length]");
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
- }
- void
- radius_ipaddr(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (len != 4) {
- proto_item_append_text(avp_item, "[wrong length for IP address]");
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
- proto_item_append_text(avp_item, "%s", tvb_ip_to_str(pinfo->pool, tvb, offset));
- }
- void
- radius_ipv6addr(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (len != 16) {
- proto_item_append_text(avp_item, "[wrong length for IPv6 address]");
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_ip6_to_str(pinfo->pool, tvb, offset));
- }
- void
- radius_ipv6prefix(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- ws_in6_addr ipv6_buff;
- gchar txtbuf[256];
- guint8 n;
- if ((len < 2) || (len > 18)) {
- proto_item_append_text(avp_item, "[wrong length for IPv6 prefix]");
- return;
- }
- /* first byte is reserved == 0x00 */
- if (tvb_get_guint8(tvb, offset)) {
- proto_item_append_text(avp_item, "[invalid reserved byte for IPv6 prefix]");
- return;
- }
- /* this is the prefix length */
- n = tvb_get_guint8(tvb, offset + 1);
- if (n > 128) {
- proto_item_append_text(avp_item, "[invalid IPv6 prefix length]");
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- /* cannot use tvb_get_ipv6() here, since the prefix most likely is truncated */
- memset(&ipv6_buff, 0, sizeof ipv6_buff);
- tvb_memcpy(tvb, &ipv6_buff, offset + 2, len - 2);
- ip6_to_str_buf(&ipv6_buff, txtbuf, sizeof(txtbuf));
- proto_item_append_text(avp_item, "%s/%u", txtbuf, n);
- }
- void
- radius_combo_ip(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (len == 4) {
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_BIG_ENDIAN);
- proto_item_append_text(avp_item, "%s", tvb_ip_to_str(pinfo->pool, tvb, offset));
- } else if (len == 16) {
- proto_tree_add_item(tree, a->hf_alt, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_ip6_to_str(pinfo->pool, tvb, offset));
- } else {
- proto_item_append_text(avp_item, "[wrong length for both of IPv4 and IPv6 address]");
- return;
- }
- }
- void
- radius_ipxnet(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- guint32 net;
- if (len != 4) {
- proto_item_append_text(avp_item, "[wrong length for IPX network]");
- return;
- }
- net = tvb_get_ntohl(tvb, offset);
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "0x%08X", net);
- }
- void
- radius_date(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- nstime_t time_ptr;
- if (len != 4) {
- proto_item_append_text(avp_item, "[wrong length for timestamp]");
- return;
- }
- time_ptr.secs = tvb_get_ntohl(tvb, offset);
- time_ptr.nsecs = 0;
- proto_tree_add_time(tree, a->hf, tvb, offset, len, &time_ptr);
- proto_item_append_text(avp_item, "%s", abs_time_to_str(wmem_packet_scope(), &time_ptr, ABSOLUTE_TIME_LOCAL, TRUE));
- }
- /*
- * "abinary" is Ascend's binary format for filters. See dissect_ascend_data_filter().
- */
- void
- radius_abinary(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (a->code.u8_code[0] == 242) {
- add_avp_to_tree_with_dissector(tree, avp_item, pinfo, tvb, dissect_ascend_data_filter, len, offset);
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
- }
- void
- radius_ether(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- if (len != 6) {
- proto_item_append_text(avp_item, "[wrong length for ethernet address]");
- return;
- }
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_ether_to_str(pinfo->pool, tvb, offset));
- }
- void
- radius_ifid(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- proto_tree_add_item(tree, a->hf, tvb, offset, len, ENC_NA);
- proto_item_append_text(avp_item, "%s", tvb_bytes_to_str(wmem_packet_scope(), tvb, offset, len));
- }
- static void
- add_tlv_to_tree(proto_tree *tlv_tree, proto_item *tlv_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 tlv_length, guint32 offset)
- {
- proto_item_append_text(tlv_item, ": ");
- dictionary_entry->type(dictionary_entry, tlv_tree, pinfo, tvb, offset, tlv_length, tlv_item);
- }
- void
- radius_tlv(radius_attr_info_t *a, proto_tree *tree, packet_info *pinfo _U_, tvbuff_t *tvb, int offset, int len, proto_item *avp_item)
- {
- gint tlv_num = 0;
- while (len > 0) {
- radius_attr_info_t *dictionary_entry = NULL;
- guint32 tlv_type;
- guint32 tlv_length;
- proto_item *tlv_item;
- proto_item *tlv_len_item;
- proto_tree *tlv_tree;
- if (len < 2) {
- proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
- "Not enough room in packet for TLV header");
- return;
- }
- tlv_type = tvb_get_guint8(tvb, offset);
- tlv_length = tvb_get_guint8(tvb, offset+1);
- if (tlv_length < 2) {
- proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
- "TLV too short: length %u < 2", tlv_length);
- return;
- }
- if (len < (gint)tlv_length) {
- proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
- "Not enough room in packet for TLV");
- return;
- }
- len -= tlv_length;
- dictionary_entry = (radius_attr_info_t *)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(tlv_type));
- if (!dictionary_entry) {
- dictionary_entry = &no_dictionary_entry;
- }
- tlv_tree = proto_tree_add_subtree_format(tree, tvb, offset, tlv_length,
- dictionary_entry->ett, &tlv_item, "TLV: t=%s(%u) l=%u ", dictionary_entry->name, tlv_type,
- tlv_length);
- tlv_length -= 2;
- offset += 2;
- if (show_length) {
- tlv_len_item = proto_tree_add_uint(tlv_tree,
- dictionary_entry->hf_len,
- tvb, 0, 0, tlv_length);
- proto_item_set_generated(tlv_len_item);
- }
- add_tlv_to_tree(tlv_tree, tlv_item, pinfo, tvb, dictionary_entry,
- tlv_length, offset);
- offset += tlv_length;
- tlv_num++;
- }
- proto_item_append_text(avp_item, "%d TLV(s) inside", tlv_num);
- }
- static void
- add_avp_to_tree_with_dissector(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_avp_dissector_t *avp_dissector, guint32 avp_length, guint32 offset)
- {
- tvbuff_t *tvb_value;
- const gchar *str;
- tvb_value = tvb_new_subset_length(tvb, offset, avp_length);
- str = avp_dissector(avp_tree, tvb_value, pinfo);
- proto_item_append_text(avp_item, "%s", str);
- }
- static void
- add_avp_to_tree(proto_tree *avp_tree, proto_item *avp_item, packet_info *pinfo, tvbuff_t *tvb, radius_attr_info_t *dictionary_entry, guint32 avp_length, guint32 offset)
- {
- if (dictionary_entry->tagged) {
- guint tag;
- if (avp_length == 0) {
- proto_tree_add_expert_format(avp_tree, pinfo, &ei_radius_invalid_length, tvb, offset,
- 0, "AVP too short for tag");
- return;
- }
- tag = tvb_get_guint8(tvb, offset);
- if (tag <= 0x1f) {
- proto_tree_add_uint(avp_tree,
- dictionary_entry->hf_tag,
- tvb, offset, 1, tag);
- proto_item_append_text(avp_item,
- " Tag=0x%.2x", tag);
- offset++;
- avp_length--;
- }
- }
- proto_item_append_text(avp_item, " val=");
- if (dictionary_entry->dissector) {
- add_avp_to_tree_with_dissector(avp_tree, avp_item, pinfo, tvb, dictionary_entry->dissector, avp_length, offset);
- return;
- }
- dictionary_entry->type(dictionary_entry, avp_tree, pinfo, tvb, offset, avp_length, avp_item);
- }
- static gboolean
- vsa_buffer_destroy(gpointer k _U_, gpointer v, gpointer p _U_)
- {
- radius_vsa_buffer *vsa_buffer = (radius_vsa_buffer *)v;
- g_free((gpointer)vsa_buffer->data);
- g_free(v);
- return TRUE;
- }
- static void
- eap_buffer_free_indirect(void *context)
- {
- guint8 *eap_buffer = *(guint8 **)context;
- g_free(eap_buffer);
- }
- static void
- vsa_buffer_table_destroy_indirect(void *context)
- {
- GHashTable *vsa_buffer_table = *(GHashTable **)context;
- if (vsa_buffer_table) {
- g_hash_table_foreach_remove(vsa_buffer_table, vsa_buffer_destroy, NULL);
- g_hash_table_destroy(vsa_buffer_table);
- }
- }
- void
- dissect_attribute_value_pairs(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, guint length)
- {
- gboolean last_eap = FALSE;
- guint8 *eap_buffer = NULL;
- guint eap_seg_num = 0;
- guint eap_tot_len_captured = 0;
- guint eap_tot_len = 0;
- proto_tree *eap_tree = NULL;
- tvbuff_t *eap_tvb = NULL;
- GHashTable *vsa_buffer_table = NULL;
- if (hf_radius_code == -1)
- proto_registrar_get_byname("radius.code");
- /*
- * In case we throw an exception, clean up whatever stuff we've
- * allocated (if any).
- */
- CLEANUP_PUSH_PFX(la, eap_buffer_free_indirect, &eap_buffer);
- CLEANUP_PUSH_PFX(lb, vsa_buffer_table_destroy_indirect, &vsa_buffer_table);
- while (length > 0) {
- radius_attr_info_t *dictionary_entry = NULL;
- 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;
- proto_tree *avp_tree;
- if (length < 2) {
- proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
- "Not enough room in packet for AVP header");
- break; /* exit outer loop, then cleanup & return */
- }
- 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 (disable_extended_attributes) {
- avp_is_extended = FALSE;
- avp_type.u8_code[1] = 0;
- }
- if (avp_length < 2) {
- proto_tree_add_expert_format(tree, pinfo, &ei_radius_invalid_length, tvb, offset, 0,
- "AVP too short: length %u < 2", avp_length);
- 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");
- break; /* exit outer loop, then cleanup & return */
- }
- length -= avp_length;
- 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, "t=%s", 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);
- proto_item_append_text(avp_item, " l=%u", avp_length);
- 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_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;
- const gchar *vendor_str;
- int vendor_offset;
- /* XXX TODO: handle 2 byte codes for USR */
- if (avp_length < 4) {
- expert_add_info_format(pinfo, avp_item, &ei_radius_invalid_length, "AVP too short; no room for vendor ID");
- offset += avp_length;
- continue; /* while (length > 0) */
- }
- vendor_id = tvb_get_ntohl(tvb, offset);
- avp_length -= 4;
- offset += 4;
- vendor = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(vendor_id));
- vendor_str = enterprises_lookup(vendor_id, "Unknown");
- if (!vendor) {
- vendor = &no_vendor;
- }
- proto_item_append_text(avp_item, " vnd=%s(%u)", vendor_str,
- vendor_id);
- vendor_tree = proto_item_add_subtree(avp_item, vendor->ett);
- vendor_offset = avp_offset_start;
- proto_tree_add_item(vendor_tree, hf_radius_avp_type, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(vendor_tree, hf_radius_avp_length, tvb, vendor_offset+1, 1, ENC_BIG_ENDIAN);
- vendor_offset += 2;
- if (avp_is_extended) {
- proto_tree_add_item(vendor_tree, hf_radius_avp_extended_type, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
- vendor_offset += 1;
- if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0)) {
- proto_tree_add_item(vendor_tree, hf_radius_avp_extended_more, tvb, vendor_offset, 1, ENC_BIG_ENDIAN);
- vendor_offset += 1;
- }
- }
- proto_tree_add_uint_format_value(vendor_tree, hf_radius_avp_vendor_id, tvb, vendor_offset, 4, vendor_id, "%s (%u)", vendor_str, vendor_id);
- vendor_offset += 4;
- while (offset < max_offset) {
- radius_attr_type_t vendor_type;
- guint32 avp_vsa_type;
- guint32 avp_vsa_len;
- guint8 avp_vsa_flags = 0;
- guint32 avp_vsa_header_len;
- guint32 vendor_attribute_len;
- switch (vendor->type_octets) {
- case 1:
- avp_vsa_type = tvb_get_guint8(tvb, offset++);
- break;
-