3 * Routines for RADIUS packet disassembly
4 * Copyright 1999 Johan Feyaerts
5 * Changed 03/12/2003 Rui Carmo (http://the.taoofmac.com - added all 3GPP VSAs, some parsing)
6 * Changed 07/2005 Luis Ontanon <luis@ontanon.org> - use FreeRADIUS' dictionary
7 * Changed 10/2006 Alejandro Vaquero <alejandrovaquero@yahoo.com> - add Conversations support
8 * Changed 08/2015 Didier Arenzana <darenzana@yahoo.fr> - add response authenticator validation
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
18 * RFC 2865 - Remote Authentication Dial In User Service (RADIUS)
19 * RFC 2866 - RADIUS Accounting
20 * RFC 2867 - RADIUS Accounting Modifications for Tunnel Protocol Support
21 * RFC 2868 - RADIUS Attributes for Tunnel Protocol Support
22 * RFC 2869 - RADIUS Extensions
23 * RFC 3162 - RADIUS and IPv6
24 * RFC 3576 - Dynamic Authorization Extensions to RADIUS
25 * RFC 6929 - Remote Authentication Dial-In User Service (RADIUS) Protocol Extensions
29 * http://www.iana.org/assignments/radius-types
33 * http://freeradius.org/radiusd/man/dictionary.html
35 * for the dictionary file syntax.
40 TO (re)DO: (see svn rev 14786)
41 - dissect_3gpp_ipv6_dns_servers()
49 #include <epan/packet.h>
50 #include <epan/exceptions.h>
51 #include <epan/expert.h>
52 #include <epan/prefs.h>
53 #include <epan/sminmpec.h>
54 #include <epan/conversation.h>
56 #include <epan/rtd_table.h>
57 #include <epan/addr_resolv.h>
58 #include <wsutil/filesystem.h>
59 #include <wsutil/report_message.h>
60 #include <wsutil/wsgcrypt.h>
63 #include "packet-radius.h"
64 #include "packet-e212.h"
66 void proto_register_radius(void);
67 void proto_reg_handoff_radius(void);
69 typedef struct _e_radiushdr
{
72 uint16_t rh_pktlength
;
78 wmem_array_t
*vend_vs
;
81 #define AUTHENTICATOR_LENGTH 16
82 #define RD_HDR_LENGTH 4
83 #define HDR_LENGTH (RD_HDR_LENGTH + AUTHENTICATOR_LENGTH)
86 /* Container for tapping relevant data */
87 typedef struct _radius_info_t
93 bool request_available
;
94 uint32_t req_num
; /* frame number request seen */
100 * Default RADIUS ports:
101 * 1645 (Authentication, pre RFC 2865)
102 * 1646 (Accounting, pre RFC 2866)
103 * 1812 (Authentication, RFC 2865)
104 * 1813 (Accounting, RFC 2866)
105 * 1700 (Dynamic Authorization Extensions, pre RFC 3576)
106 * 3799 (Dynamic Authorization Extensions, RFC 3576)
108 #define DEFAULT_RADIUS_PORT_RANGE "1645,1646,1700,1812,1813,3799"
110 static radius_dictionary_t
*dict
;
112 static int proto_radius
;
114 static int hf_radius_req
;
115 static int hf_radius_rsp
;
116 static int hf_radius_req_frame
;
117 static int hf_radius_rsp_frame
;
118 static int hf_radius_time
;
120 static int hf_radius_dup
;
121 static int hf_radius_req_dup
;
122 static int hf_radius_rsp_dup
;
124 static int hf_radius_id
;
125 static int hf_radius_code
;
126 static int hf_radius_length
;
127 static int hf_radius_authenticator
;
128 static int hf_radius_authenticator_valid
;
129 static int hf_radius_authenticator_invalid
;
130 static int hf_radius_message_authenticator_valid
;
131 static int hf_radius_message_authenticator_invalid
;
133 static int hf_radius_chap_password
;
134 static int hf_radius_chap_ident
;
135 static int hf_radius_chap_string
;
136 static int hf_radius_framed_ip_address
;
138 static int hf_radius_login_ip_host
;
139 static int hf_radius_framed_ipx_network
;
141 static int hf_radius_cosine_vpi
;
142 static int hf_radius_cosine_vci
;
144 static int hf_radius_ascend_data_filter
;
145 static int hf_radius_ascend_data_filter_type
;
146 static int hf_radius_ascend_data_filter_filteror
;
147 static int hf_radius_ascend_data_filter_inout
;
148 static int hf_radius_ascend_data_filter_spare
;
149 static int hf_radius_ascend_data_filter_src_ipv4
;
150 static int hf_radius_ascend_data_filter_dst_ipv4
;
151 static int hf_radius_ascend_data_filter_src_ipv6
;
152 static int hf_radius_ascend_data_filter_dst_ipv6
;
153 static int hf_radius_ascend_data_filter_src_ip_prefix
;
154 static int hf_radius_ascend_data_filter_dst_ip_prefix
;
155 static int hf_radius_ascend_data_filter_protocol
;
156 static int hf_radius_ascend_data_filter_established
;
157 static int hf_radius_ascend_data_filter_src_port
;
158 static int hf_radius_ascend_data_filter_dst_port
;
159 static int hf_radius_ascend_data_filter_src_port_qualifier
;
160 static int hf_radius_ascend_data_filter_dst_port_qualifier
;
161 static int hf_radius_ascend_data_filter_reserved
;
163 static int hf_radius_vsa_fragment
;
164 static int hf_radius_eap_fragment
;
165 static int hf_radius_avp
;
166 static int hf_radius_avp_length
;
167 static int hf_radius_avp_type
;
168 static int hf_radius_avp_vendor_id
;
169 static int hf_radius_avp_vendor_type
;
170 static int hf_radius_avp_vendor_len
;
171 static int hf_radius_avp_extended_type
;
172 static int hf_radius_avp_extended_more
;
173 static int hf_radius_3gpp_ms_tmime_zone
;
175 static int hf_radius_egress_vlanid_tag
;
176 static int hf_radius_egress_vlanid_pad
;
177 static int hf_radius_egress_vlanid
;
179 static int hf_radius_egress_vlan_name_tag
;
180 static int hf_radius_egress_vlan_name
;
183 static int ett_radius
;
184 static int ett_radius_avp
;
186 static int ett_radius_authenticator
;
187 static int ett_radius_ascend
;
192 static expert_field ei_radius_invalid_length
;
195 * Define the tap for radius
197 static int radius_tap
;
199 static radius_vendor_info_t no_vendor
= {"Unknown Vendor", 0, NULL
, -1, 1, 1, false};
201 static radius_attr_info_t no_dictionary_entry
= {"Unknown-Attribute", { { 0, 0 } }, false, false, false, radius_octets
, NULL
, NULL
, -1, -1, -1, -1, -1, -1, NULL
};
203 static dissector_handle_t eap_handle
;
204 static dissector_handle_t radius_handle
;
207 static const char *shared_secret
= "";
208 static bool validate_authenticator
;
209 static bool show_length
;
210 static bool disable_extended_attributes
;
212 static uint8_t authenticator
[AUTHENTICATOR_LENGTH
];
214 /* http://www.iana.org/assignments/radius-types */
215 static const value_string radius_pkt_type_codes
[] =
217 {RADIUS_PKT_TYPE_ACCESS_REQUEST
, "Access-Request"}, /* 1 RFC2865 */
218 {RADIUS_PKT_TYPE_ACCESS_ACCEPT
, "Access-Accept"}, /* 2 RFC2865 */
219 {RADIUS_PKT_TYPE_ACCESS_REJECT
, "Access-Reject"}, /* 3 RFC2865 */
220 {RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
, "Accounting-Request"}, /* 4 RFC2865 */
221 {RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
, "Accounting-Response"}, /* 5 RFC2865 */
222 {RADIUS_PKT_TYPE_ACCOUNTING_STATUS
, "Accounting-Status"}, /* 6 RFC3575 */
223 {RADIUS_PKT_TYPE_PASSWORD_REQUEST
, "Password-Request"}, /* 7 RFC3575 */
224 {RADIUS_PKT_TYPE_PASSWORD_ACK
, "Password-Ack"}, /* 8 RFC3575 */
225 {RADIUS_PKT_TYPE_PASSWORD_REJECT
, "Password-Reject"}, /* 9 RFC3575 */
226 {RADIUS_PKT_TYPE_ACCOUNTING_MESSAGE
, "Accounting-Message"}, /* 10 RFC3575 */
227 {RADIUS_PKT_TYPE_ACCESS_CHALLENGE
, "Access-Challenge"}, /* 11 RFC2865 */
228 {RADIUS_PKT_TYPE_STATUS_SERVER
, "Status-Server"}, /* 12 RFC2865 */
229 {RADIUS_PKT_TYPE_STATUS_CLIENT
, "Status-Client"}, /* 13 RFC2865 */
231 {RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST
, "Resource-Free-Request"}, /* 21 RFC3575 */
232 {RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE
, "Resource-Free-Response"}, /* 22 RFC3575 */
233 {RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST
, "Resource-Query-Request"}, /* 23 RFC3575 */
234 {RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE
, "Query_Response"}, /* 24 RFC3575 */
235 {RADIUS_PKT_TYPE_ALTERNATE_RESOURCE_RECLAIM_REQUEST
, "Alternate-Resource-Reclaim-Request"}, /* 25 RFC3575 */
236 {RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST
, "NAS-Reboot-Request"}, /* 26 RFC3575 */
237 {RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE
, "NAS-Reboot-Response"}, /* 27 RFC3575 */
239 {RADIUS_PKT_TYPE_NEXT_PASSCODE
, "Next-Passcode"}, /* 29 RFC3575 */
240 {RADIUS_PKT_TYPE_NEW_PIN
, "New-Pin"}, /* 30 RFC3575 */
241 {RADIUS_PKT_TYPE_TERMINATE_SESSION
, "Terminate-Session"}, /* 31 RFC3575 */
242 {RADIUS_PKT_TYPE_PASSWORD_EXPIRED
, "Password-Expired"}, /* 32 RFC3575 */
243 {RADIUS_PKT_TYPE_EVENT_REQUEST
, "Event-Request"}, /* 33 RFC3575 */
244 {RADIUS_PKT_TYPE_EVENT_RESPONSE
, "Event-Response"}, /* 34 RFC3575|RFC5176 */
246 {RADIUS_PKT_TYPE_DISCONNECT_REQUEST
, "Disconnect-Request"}, /* 40 RFC3575|RFC5176 */
247 {RADIUS_PKT_TYPE_DISCONNECT_ACK
, "Disconnect-ACK"}, /* 41 RFC3575|RFC5176 */
248 {RADIUS_PKT_TYPE_DISCONNECT_NAK
, "Disconnect-NAK"}, /* 42 RFC3575|RFC5176 */
249 {RADIUS_PKT_TYPE_COA_REQUEST
, "CoA-Request"}, /* 43 RFC3575|RFC5176 */
250 {RADIUS_PKT_TYPE_COA_ACK
, "CoA-ACK"}, /* 44 RFC3575|RFC5176 */
251 {RADIUS_PKT_TYPE_COA_NAK
, "CoA-NAK"}, /* 45 RFC3575|RFC5176 */
253 {RADIUS_PKT_TYPE_IP_ADDRESS_ALLOCATE
, "IP-Address-Allocate"}, /* 50 RFC3575 */
254 {RADIUS_PKT_TYPE_IP_ADDRESS_RELEASE
, "IP-Address-Release"}, /* 51 RFC3575 */
256 {RADIUS_PKT_TYPE_ALU_STATE_REQUEST
, "ALU-State-Request"}, /* 129 ALU AAA */
257 {RADIUS_PKT_TYPE_ALU_STATE_ACCEPT
, "ALU-State-Accept"}, /* 130 ALU AAA */
258 {RADIUS_PKT_TYPE_ALU_STATE_REJECT
, "ALU-State-Reject"}, /* 131 ALU AAA */
259 {RADIUS_PKT_TYPE_ALU_STATE_ERROR
, "ALU-State-Error"}, /* 132 ALU AAA */
261 250-253 Experimental Use [RFC3575]
262 254-255 Reserved [RFC3575]
266 static value_string_ext radius_pkt_type_codes_ext
= VALUE_STRING_EXT_INIT(radius_pkt_type_codes
);
268 typedef enum _radius_category
{
269 RADIUS_CAT_OVERALL
= 0,
271 RADIUS_CAT_ACCOUNTING
,
273 RADIUS_CAT_RESOURCE_FREE
,
274 RADIUS_CAT_RESOURCE_QUERY
,
275 RADIUS_CAT_NAS_REBOOT
,
277 RADIUS_CAT_DISCONNECT
,
280 RADIUS_CAT_NUM_TIMESTATS
283 static const value_string radius_message_code
[] = {
284 { RADIUS_CAT_OVERALL
, "Overall"},
285 { RADIUS_CAT_ACCESS
, "Access"},
286 { RADIUS_CAT_ACCOUNTING
, "Accounting"},
287 { RADIUS_CAT_PASSWORD
, "Password"},
288 { RADIUS_CAT_RESOURCE_FREE
, "Resource Free"},
289 { RADIUS_CAT_RESOURCE_QUERY
, "Resource Query"},
290 { RADIUS_CAT_NAS_REBOOT
, "NAS Reboot"},
291 { RADIUS_CAT_EVENT
, "Event"},
292 { RADIUS_CAT_DISCONNECT
, "Disconnect"},
293 { RADIUS_CAT_COA
, "CoA"},
294 { RADIUS_CAT_OTHERS
, "Other"},
298 static tap_packet_status
299 radiusstat_packet(void *prs
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *pri
, tap_flags_t flags _U_
)
301 rtd_data_t
*rtd_data
= (rtd_data_t
*)prs
;
302 rtd_stat_table
*rs
= &rtd_data
->stat_table
;
303 const radius_info_t
*ri
= (const radius_info_t
*)pri
;
305 radius_category radius_cat
= RADIUS_CAT_OTHERS
;
306 tap_packet_status ret
= TAP_PACKET_DONT_REDRAW
;
309 case RADIUS_PKT_TYPE_ACCESS_REQUEST
:
310 case RADIUS_PKT_TYPE_ACCESS_ACCEPT
:
311 case RADIUS_PKT_TYPE_ACCESS_REJECT
:
312 radius_cat
= RADIUS_CAT_ACCESS
;
314 case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
:
315 case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
:
316 radius_cat
= RADIUS_CAT_ACCOUNTING
;
318 case RADIUS_PKT_TYPE_PASSWORD_REQUEST
:
319 case RADIUS_PKT_TYPE_PASSWORD_ACK
:
320 case RADIUS_PKT_TYPE_PASSWORD_REJECT
:
321 radius_cat
= RADIUS_CAT_PASSWORD
;
323 case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST
:
324 case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE
:
325 radius_cat
= RADIUS_CAT_RESOURCE_FREE
;
327 case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST
:
328 case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE
:
329 radius_cat
= RADIUS_CAT_RESOURCE_QUERY
;
331 case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST
:
332 case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE
:
333 radius_cat
= RADIUS_CAT_NAS_REBOOT
;
335 case RADIUS_PKT_TYPE_EVENT_REQUEST
:
336 case RADIUS_PKT_TYPE_EVENT_RESPONSE
:
337 radius_cat
= RADIUS_CAT_EVENT
;
339 case RADIUS_PKT_TYPE_DISCONNECT_REQUEST
:
340 case RADIUS_PKT_TYPE_DISCONNECT_ACK
:
341 case RADIUS_PKT_TYPE_DISCONNECT_NAK
:
342 radius_cat
= RADIUS_CAT_DISCONNECT
;
344 case RADIUS_PKT_TYPE_COA_REQUEST
:
345 case RADIUS_PKT_TYPE_COA_ACK
:
346 case RADIUS_PKT_TYPE_COA_NAK
:
347 radius_cat
= RADIUS_CAT_COA
;
353 case RADIUS_PKT_TYPE_ACCESS_REQUEST
:
354 case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
:
355 case RADIUS_PKT_TYPE_PASSWORD_REQUEST
:
356 case RADIUS_PKT_TYPE_EVENT_REQUEST
:
357 case RADIUS_PKT_TYPE_DISCONNECT_REQUEST
:
358 case RADIUS_PKT_TYPE_COA_REQUEST
:
359 if (ri
->is_duplicate
) {
360 /* Duplicate is ignored */
361 rs
->time_stats
[RADIUS_CAT_OVERALL
].req_dup_num
++;
362 rs
->time_stats
[radius_cat
].req_dup_num
++;
364 rs
->time_stats
[RADIUS_CAT_OVERALL
].open_req_num
++;
365 rs
->time_stats
[radius_cat
].open_req_num
++;
369 case RADIUS_PKT_TYPE_ACCESS_ACCEPT
:
370 case RADIUS_PKT_TYPE_ACCESS_REJECT
:
371 case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
:
372 case RADIUS_PKT_TYPE_PASSWORD_ACK
:
373 case RADIUS_PKT_TYPE_PASSWORD_REJECT
:
374 case RADIUS_PKT_TYPE_EVENT_RESPONSE
:
375 case RADIUS_PKT_TYPE_DISCONNECT_ACK
:
376 case RADIUS_PKT_TYPE_DISCONNECT_NAK
:
377 case RADIUS_PKT_TYPE_COA_ACK
:
378 case RADIUS_PKT_TYPE_COA_NAK
:
379 if (ri
->is_duplicate
) {
380 /* Duplicate is ignored */
381 rs
->time_stats
[RADIUS_CAT_OVERALL
].rsp_dup_num
++;
382 rs
->time_stats
[radius_cat
].rsp_dup_num
++;
383 } else if (!ri
->request_available
) {
384 /* no request was seen */
385 rs
->time_stats
[RADIUS_CAT_OVERALL
].disc_rsp_num
++;
386 rs
->time_stats
[radius_cat
].disc_rsp_num
++;
388 rs
->time_stats
[RADIUS_CAT_OVERALL
].open_req_num
--;
389 rs
->time_stats
[radius_cat
].open_req_num
--;
390 /* calculate time delta between request and response */
391 nstime_delta(&delta
, &pinfo
->abs_ts
, &ri
->req_time
);
393 time_stat_update(&(rs
->time_stats
[RADIUS_CAT_OVERALL
].rtd
[0]),&delta
, pinfo
);
394 time_stat_update(&(rs
->time_stats
[radius_cat
].rtd
[0]),&delta
, pinfo
);
396 ret
= TAP_PACKET_REDRAW
;
410 * Init Hash table stuff for conversation
413 typedef struct _radius_call_info_key
417 conversation_t
*conversation
;
419 } radius_call_info_key
;
421 static wmem_map_t
*radius_calls
;
423 typedef struct _radius_vsa_buffer_key
427 } radius_vsa_buffer_key
;
429 typedef struct _radius_vsa_buffer
431 radius_vsa_buffer_key key
;
438 radius_vsa_equal(const void *k1
, const void *k2
)
440 const radius_vsa_buffer_key
*key1
= (const radius_vsa_buffer_key
*) k1
;
441 const radius_vsa_buffer_key
*key2
= (const radius_vsa_buffer_key
*) k2
;
443 return (((key1
->vendor_id
== key2
->vendor_id
) &&
444 (key1
->vsa_type
== key2
->vsa_type
)
449 radius_vsa_hash(const void *k
)
451 const radius_vsa_buffer_key
*key
= (const radius_vsa_buffer_key
*) k
;
453 return key
->vendor_id
+ key
->vsa_type
;
458 radius_call_equal(const void *k1
, const void *k2
)
460 const radius_call_info_key
*key1
= (const radius_call_info_key
*) k1
;
461 const radius_call_info_key
*key2
= (const radius_call_info_key
*) k2
;
463 if (key1
->ident
== key2
->ident
&& key1
->conversation
== key2
->conversation
) {
464 if (key1
->code
== key2
->code
)
467 /* check the request and response are of the same code type */
468 if ((key1
->code
== RADIUS_PKT_TYPE_ACCESS_REQUEST
) &&
469 ((key2
->code
== RADIUS_PKT_TYPE_ACCESS_ACCEPT
) ||
470 (key2
->code
== RADIUS_PKT_TYPE_ACCESS_REJECT
) ||
471 (key2
->code
== RADIUS_PKT_TYPE_ACCESS_CHALLENGE
)))
473 if ((key2
->code
== RADIUS_PKT_TYPE_ACCESS_REQUEST
) &&
474 ((key1
->code
== RADIUS_PKT_TYPE_ACCESS_ACCEPT
) ||
475 (key1
->code
== RADIUS_PKT_TYPE_ACCESS_REJECT
) ||
476 (key1
->code
== RADIUS_PKT_TYPE_ACCESS_CHALLENGE
)))
479 if ((key1
->code
== RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
) &&
480 (key2
->code
== RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
))
482 if ((key2
->code
== RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
) &&
483 (key1
->code
== RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
))
486 if ((key1
->code
== RADIUS_PKT_TYPE_PASSWORD_REQUEST
) &&
487 ((key2
->code
== RADIUS_PKT_TYPE_PASSWORD_ACK
) ||
488 (key2
->code
== RADIUS_PKT_TYPE_PASSWORD_REJECT
)))
490 if ((key2
->code
== RADIUS_PKT_TYPE_PASSWORD_REQUEST
) &&
491 ((key1
->code
== RADIUS_PKT_TYPE_PASSWORD_ACK
) ||
492 (key1
->code
== RADIUS_PKT_TYPE_PASSWORD_REJECT
)))
495 if ((key1
->code
== RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST
) &&
496 (key2
->code
== RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE
))
498 if ((key2
->code
== RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST
) &&
499 (key1
->code
== RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE
))
502 if ((key1
->code
== RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST
) &&
503 (key2
->code
== RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE
))
505 if ((key2
->code
== RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST
) &&
506 (key1
->code
== RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE
))
509 if ((key1
->code
== RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST
) &&
510 (key2
->code
== RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE
))
512 if ((key2
->code
== RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST
) &&
513 (key1
->code
== RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE
))
516 if ((key1
->code
== RADIUS_PKT_TYPE_EVENT_REQUEST
) &&
517 (key2
->code
== RADIUS_PKT_TYPE_EVENT_RESPONSE
))
519 if ((key2
->code
== RADIUS_PKT_TYPE_EVENT_REQUEST
) &&
520 (key1
->code
== RADIUS_PKT_TYPE_EVENT_RESPONSE
))
523 if ((key1
->code
== RADIUS_PKT_TYPE_DISCONNECT_REQUEST
) &&
524 ((key2
->code
== RADIUS_PKT_TYPE_DISCONNECT_ACK
) ||
525 (key2
->code
== RADIUS_PKT_TYPE_DISCONNECT_NAK
)))
527 if ((key2
->code
== RADIUS_PKT_TYPE_DISCONNECT_REQUEST
) &&
528 ((key1
->code
== RADIUS_PKT_TYPE_DISCONNECT_ACK
) ||
529 (key1
->code
== RADIUS_PKT_TYPE_DISCONNECT_NAK
)))
532 if ((key1
->code
== RADIUS_PKT_TYPE_COA_REQUEST
) &&
533 ((key2
->code
== RADIUS_PKT_TYPE_COA_ACK
) ||
534 (key2
->code
== RADIUS_PKT_TYPE_COA_NAK
)))
536 if ((key2
->code
== RADIUS_PKT_TYPE_COA_REQUEST
) &&
537 ((key1
->code
== RADIUS_PKT_TYPE_COA_ACK
) ||
538 (key1
->code
== RADIUS_PKT_TYPE_COA_NAK
)))
541 if ((key1
->code
== RADIUS_PKT_TYPE_ALU_STATE_REQUEST
) &&
542 ((key2
->code
== RADIUS_PKT_TYPE_ALU_STATE_ACCEPT
) ||
543 (key2
->code
== RADIUS_PKT_TYPE_ALU_STATE_REJECT
) ||
544 (key2
->code
== RADIUS_PKT_TYPE_ALU_STATE_ERROR
)))
546 if ((key2
->code
== RADIUS_PKT_TYPE_ALU_STATE_REQUEST
) &&
547 ((key1
->code
== RADIUS_PKT_TYPE_ALU_STATE_ACCEPT
) ||
548 (key1
->code
== RADIUS_PKT_TYPE_ALU_STATE_REJECT
) ||
549 (key1
->code
== RADIUS_PKT_TYPE_ALU_STATE_ERROR
)))
555 /* Calculate a hash key */
557 radius_call_hash(const void *k
)
559 const radius_call_info_key
*key
= (const radius_call_info_key
*) k
;
561 return key
->ident
+ key
->conversation
->conv_index
;
566 dissect_chap_password(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
570 proto_tree
*chap_tree
;
572 len
= tvb_reported_length(tvb
);
574 return "[wrong length for CHAP-Password]";
576 ti
= proto_tree_add_item(tree
, hf_radius_chap_password
, tvb
, 0, len
, ENC_NA
);
577 chap_tree
= proto_item_add_subtree(ti
, ett_chap
);
578 proto_tree_add_item(chap_tree
, hf_radius_chap_ident
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
579 proto_tree_add_item(chap_tree
, hf_radius_chap_string
, tvb
, 1, 16, ENC_NA
);
580 return (tvb_bytes_to_str(pinfo
->pool
, tvb
, 0, len
));
584 dissect_framed_ip_address(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
)
591 len
= tvb_reported_length(tvb
);
593 return "[wrong length for IP address]";
595 ip
= tvb_get_ipv4(tvb
, 0);
598 if (ip_h
== 0xFFFFFFFF) {
600 proto_tree_add_ipv4_format_value(tree
, hf_radius_framed_ip_address
,
601 tvb
, 0, len
, ip
, "%s", str
);
602 } else if (ip_h
== 0xFFFFFFFE) {
604 proto_tree_add_ipv4_format_value(tree
, hf_radius_framed_ip_address
,
605 tvb
, 0, len
, ip
, "%s", str
);
607 str
= tvb_ip_to_str(pinfo
->pool
, tvb
, 0);
608 proto_tree_add_item(tree
, hf_radius_framed_ip_address
,
609 tvb
, 0, len
, ENC_BIG_ENDIAN
);
616 dissect_login_ip_host(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
)
623 len
= tvb_reported_length(tvb
);
625 return "[wrong length for IP address]";
627 ip
= tvb_get_ipv4(tvb
, 0);
630 if (ip_h
== 0xFFFFFFFF) {
631 str
= "User-selected";
632 proto_tree_add_ipv4_format_value(tree
, hf_radius_login_ip_host
,
633 tvb
, 0, len
, ip
, "%s", str
);
634 } else if (ip_h
== 0) {
635 str
= "NAS-selected";
636 proto_tree_add_ipv4_format_value(tree
, hf_radius_login_ip_host
,
637 tvb
, 0, len
, ip
, "%s", str
);
639 str
= tvb_ip_to_str(pinfo
->pool
, tvb
, 0);
640 proto_tree_add_item(tree
, hf_radius_login_ip_host
,
641 tvb
, 0, len
, ENC_BIG_ENDIAN
);
647 static const value_string ascenddf_filtertype
[] = { {0, "generic"}, {1, "ipv4"}, {3, "ipv6"}, {0, NULL
} };
648 static const value_string ascenddf_filteror
[] = { {0, "drop"}, {1, "forward"}, {0, NULL
} };
649 static const value_string ascenddf_inout
[] = { {0, "out"}, {1, "in"}, {0, NULL
} };
650 static const value_string ascenddf_proto
[] = { {1, "icmp"}, {6, "tcp"}, {17, "udp"}, {0, NULL
} };
651 static const value_string ascenddf_portq
[] = { {1, "lt"}, {2, "eq"}, {3, "gt"}, {4, "ne"}, {0, NULL
} };
654 dissect_ascend_data_filter(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
656 wmem_strbuf_t
*filterstr
;
658 proto_tree
*ascend_tree
;
660 uint8_t type
, proto
, srclen
, dstlen
;
661 address srcip
, dstip
;
662 uint16_t srcport
, dstport
;
663 uint8_t srcportq
, dstportq
;
666 len
=tvb_reported_length(tvb
);
668 if (len
!= 24 && len
!= 48) {
669 return wmem_strdup_printf(pinfo
->pool
, "Wrong attribute length %d", len
);
672 filterstr
= wmem_strbuf_new_sized(pinfo
->pool
, 128);
674 ti
= proto_tree_add_item(tree
, hf_radius_ascend_data_filter
, tvb
, 0, -1, ENC_NA
);
675 ascend_tree
= proto_item_add_subtree(ti
, ett_radius_ascend
);
677 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
678 type
= tvb_get_uint8(tvb
, 0);
680 if (type
== 3) { /* IPv6 */
684 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_filteror
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
686 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_inout
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
688 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_spare
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
691 if (type
== 3) { /* IPv6 */
692 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_src_ipv6
, tvb
, offset
, 16, ENC_NA
);
694 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_dst_ipv6
, tvb
, offset
, 16, ENC_NA
);
697 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_src_ipv4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
699 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_dst_ipv4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
702 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_src_ip_prefix
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
704 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_dst_ip_prefix
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
707 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_protocol
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
710 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_established
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
713 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_src_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
716 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_dst_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
719 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_src_port_qualifier
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
722 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_dst_port_qualifier
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
725 proto_tree_add_item(ascend_tree
, hf_radius_ascend_data_filter_reserved
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
727 wmem_strbuf_append_printf(filterstr
, "%s %s %s",
728 val_to_str(type
, ascenddf_filtertype
, "%u"),
729 val_to_str(tvb_get_uint8(tvb
, 2), ascenddf_inout
, "%u"),
730 val_to_str(tvb_get_uint8(tvb
, 1), ascenddf_filteror
, "%u"));
733 proto
= tvb_get_uint8(tvb
, 6+iplen
*2);
735 wmem_strbuf_append_printf(filterstr
, " %s",
736 val_to_str(proto
, ascenddf_proto
, "%u"));
739 if (type
== 3) { /* IPv6 */
740 set_address_tvb(&srcip
, AT_IPv6
, 16, tvb
, 4);
742 set_address_tvb(&srcip
, AT_IPv4
, 4, tvb
, 4);
744 srclen
= tvb_get_uint8(tvb
, 4+iplen
*2);
745 srcport
= tvb_get_ntohs(tvb
, 9+iplen
*2);
746 srcportq
= tvb_get_uint8(tvb
, 12+iplen
*2);
748 if (srclen
|| srcportq
) {
749 wmem_strbuf_append_printf(filterstr
, " srcip %s/%d", address_to_display(pinfo
->pool
, &srcip
), srclen
);
751 wmem_strbuf_append_printf(filterstr
, " srcport %s %d",
752 val_to_str(srcportq
, ascenddf_portq
, "%u"), srcport
);
755 if (type
== 3) { /* IPv6-*/
756 set_address_tvb(&dstip
, AT_IPv6
, 16, tvb
, 4+iplen
);
758 set_address_tvb(&dstip
, AT_IPv4
, 4, tvb
, 4+iplen
);
760 dstlen
= tvb_get_uint8(tvb
, 5+iplen
*2);
761 dstport
= tvb_get_ntohs(tvb
, 10+iplen
*2);
762 dstportq
= tvb_get_uint8(tvb
, 13+iplen
*2);
764 if (dstlen
|| dstportq
) {
765 wmem_strbuf_append_printf(filterstr
, " dstip %s/%d", address_to_display(pinfo
->pool
, &dstip
), dstlen
);
767 wmem_strbuf_append_printf(filterstr
, " dstport %s %d",
768 val_to_str(dstportq
, ascenddf_portq
, "%u"), dstport
);
771 return wmem_strbuf_get_str(filterstr
);
775 dissect_framed_ipx_network(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
781 len
= tvb_reported_length(tvb
);
783 return "[wrong length for IPX network]";
785 net
= tvb_get_ntohl(tvb
, 0);
787 if (net
== 0xFFFFFFFE)
788 str
= "NAS-selected";
790 str
= wmem_strdup_printf(pinfo
->pool
, "0x%08X", net
);
791 proto_tree_add_ipxnet_format_value(tree
, hf_radius_framed_ipx_network
, tvb
, 0,
792 len
, net
, "Framed-IPX-Network: %s", str
);
798 dissect_cosine_vpvc(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
802 if (tvb_reported_length(tvb
) != 4)
803 return "[Wrong Length for VP/VC AVP]";
805 vpi
= tvb_get_ntohs(tvb
, 0);
806 vci
= tvb_get_ntohs(tvb
, 2);
808 proto_tree_add_uint(tree
, hf_radius_cosine_vpi
, tvb
, 0, 2, vpi
);
809 proto_tree_add_uint(tree
, hf_radius_cosine_vci
, tvb
, 2, 2, vci
);
811 return wmem_strdup_printf(pinfo
->pool
, "%u/%u", vpi
, vci
);
814 static const value_string daylight_saving_time_vals
[] = {
815 {0, "No adjustment"},
816 {1, "+1 hour adjustment for Daylight Saving Time"},
817 {2, "+2 hours adjustment for Daylight Saving Time"},
823 dissect_radius_3gpp_imsi(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
825 return dissect_e212_utf8_imsi(tvb
, pinfo
, tree
, 0, tvb_reported_length(tvb
));
829 dissect_radius_3gpp_ms_tmime_zone(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
833 uint8_t oct
, daylight_saving_time
;
836 /* 3GPP TS 23.040 version 6.6.0 Release 6
837 * 9.2.3.11 TP-Service-Centre-Time-Stamp (TP-SCTS)
839 * The Time Zone indicates the difference, expressed in quarters of an hour,
840 * between the local time and GMT. In the first of the two semi-octets,
841 * the first bit (bit 3 of the seventh octet of the TP-Service-Centre-Time-Stamp field)
842 * represents the algebraic sign of this difference (0: positive, 1: negative).
845 oct
= tvb_get_uint8(tvb
, offset
);
846 sign
= (oct
& 0x08) ? '-' : '+';
847 oct
= (oct
>> 4) + (oct
& 0x07) * 10;
848 daylight_saving_time
= tvb_get_uint8(tvb
, offset
+1) & 0x3;
850 proto_tree_add_bytes_format_value(tree
, hf_radius_3gpp_ms_tmime_zone
, tvb
, offset
, 2, NULL
,
851 "GMT %c%d hours %d minutes %s", sign
, oct
/ 4, oct
% 4 * 15,
852 val_to_str_const(daylight_saving_time
, daylight_saving_time_vals
, "Unknown"));
854 return wmem_strdup_printf(pinfo
->pool
, "Timezone: GMT %c%d hours %d minutes %s ",
855 sign
, oct
/ 4, oct
% 4 * 15, val_to_str_const(daylight_saving_time
, daylight_saving_time_vals
, "Unknown"));
859 static const value_string egress_vlan_tag_vals
[] = {
865 dissect_rfc4675_egress_vlanid(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
870 len
= tvb_reported_length(tvb
);
872 return "[wrong length for Egress-VLANID ]";
874 proto_tree_add_item(tree
, hf_radius_egress_vlanid_tag
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
875 proto_tree_add_item(tree
, hf_radius_egress_vlanid_pad
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
876 proto_tree_add_item(tree
, hf_radius_egress_vlanid
, tvb
, 0, 4, ENC_BIG_ENDIAN
);
877 vlanid
= tvb_get_ntohl(tvb
, 0);
879 return wmem_strdup_printf(pinfo
->pool
, "%s, Vlan ID: %u",
880 val_to_str_const(((vlanid
&0xFF000000)>>24), egress_vlan_tag_vals
, "Unknown"), vlanid
&0xFFF);
884 dissect_rfc4675_egress_vlan_name(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
)
890 len
= tvb_reported_length(tvb
);
892 return "[wrong length for Egress-VLAN-Name ]";
894 proto_tree_add_item(tree
, hf_radius_egress_vlan_name_tag
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
895 tag
= tvb_get_uint8(tvb
, 0);
897 proto_tree_add_item_ret_string(tree
, hf_radius_egress_vlan_name
, tvb
, 1, len
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &name
);
899 return wmem_strdup_printf(pinfo
->pool
, "%s, Vlan Name: %s",
900 val_to_str_const(tag
, egress_vlan_tag_vals
, "Unknown"), name
);
904 radius_decrypt_avp(uint8_t *dest
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int length
, uint8_t *request_authenticator
, uint8_t *salt
, int salt_len
, int type
)
906 gcry_md_hd_t md5_handle
;
907 uint8_t digest
[HASH_MD5_LENGTH
];
912 if (gcry_md_open(&md5_handle
, GCRY_MD_MD5
, 0)) {
916 gcry_md_write(md5_handle
, request_authenticator
, AUTHENTICATOR_LENGTH
);
917 gcry_md_write(md5_handle
, (const uint8_t *)shared_secret
, (int)strlen(shared_secret
));
919 gcry_md_write(md5_handle
, (const uint8_t *)shared_secret
, (int)strlen(shared_secret
));
920 gcry_md_write(md5_handle
, request_authenticator
, AUTHENTICATOR_LENGTH
);
921 gcry_md_write(md5_handle
, salt
, salt_len
);
923 memcpy(digest
, gcry_md_read(md5_handle
, 0), HASH_MD5_LENGTH
);
925 padded_length
= length
+ ((length
% AUTHENTICATOR_LENGTH
) ?
926 (AUTHENTICATOR_LENGTH
- (length
% AUTHENTICATOR_LENGTH
)) : 0);
927 pd
= (uint8_t *)wmem_alloc0(pinfo
->pool
, padded_length
);
928 tvb_memcpy(tvb
, pd
, offset
, length
);
930 for (i
= 0; i
< padded_length
; i
+= AUTHENTICATOR_LENGTH
) {
931 for (j
= 0; j
< AUTHENTICATOR_LENGTH
&& i
+ j
< length
; j
++) {
932 dest
[i
+ j
] = pd
[i
+ j
] ^ digest
[j
];
934 gcry_md_reset(md5_handle
);
935 gcry_md_write(md5_handle
, (const uint8_t *)shared_secret
, (int)strlen(shared_secret
));
936 gcry_md_write(md5_handle
, &pd
[i
], AUTHENTICATOR_LENGTH
);
937 memcpy(digest
, gcry_md_read(md5_handle
, 0), HASH_MD5_LENGTH
);
939 gcry_md_close(md5_handle
);
943 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
, uint32_t avp_length
, uint32_t offset
);
947 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
)
953 uintv
= tvb_get_uint8(tvb
, offset
);
956 uintv
= tvb_get_ntohs(tvb
, offset
);
959 uintv
= tvb_get_ntoh24(tvb
, offset
);
962 uintv
= tvb_get_ntohl(tvb
, offset
);
965 uint64_t uintv64
= tvb_get_ntoh64(tvb
, offset
);
966 proto_tree_add_uint64(tree
, a
->hf_alt
, tvb
, offset
, len
, uintv64
);
967 proto_item_append_text(avp_item
, "%" PRIu64
, uintv64
);
971 proto_item_append_text(avp_item
, "[unhandled integer length(%u)]", len
);
974 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
977 proto_item_append_text(avp_item
, "%s(%u)", val_to_str_const(uintv
, a
->vs
, "Unknown"), uintv
);
979 proto_item_append_text(avp_item
, "%u", uintv
);
984 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
)
990 uintv
= tvb_get_uint8(tvb
, offset
);
993 uintv
= tvb_get_ntohs(tvb
, offset
);
996 uintv
= tvb_get_ntoh24(tvb
, offset
);
999 uintv
= tvb_get_ntohl(tvb
, offset
);
1002 uint64_t uintv64
= tvb_get_ntoh64(tvb
, offset
);
1003 proto_tree_add_int64(tree
, a
->hf_alt
, tvb
, offset
, len
, uintv64
);
1004 proto_item_append_text(avp_item
, "%" PRIu64
, uintv64
);
1008 proto_item_append_text(avp_item
, "[unhandled signed integer length(%u)]", len
);
1012 proto_tree_add_int(tree
, a
->hf
, tvb
, offset
, len
, uintv
);
1015 proto_item_append_text(avp_item
, "%s(%d)", val_to_str_const(uintv
, a
->vs
, "Unknown"), uintv
);
1017 proto_item_append_text(avp_item
, "%d", uintv
);
1022 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
)
1024 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_UTF_8
|ENC_NA
);
1025 proto_item_append_text(avp_item
, "%s", tvb_format_text(pinfo
->pool
, tvb
, offset
, len
));
1029 radius_octets(radius_attr_info_t
*a
, proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_item
*avp_item
)
1032 proto_item_append_text(avp_item
, "[wrong length]");
1036 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1037 proto_item_append_text(avp_item
, "%s", tvb_bytes_to_str(pinfo
->pool
, tvb
, offset
, len
));
1041 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
)
1045 proto_item_append_text(avp_item
, "[wrong length for IP address]");
1049 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
1051 proto_item_append_text(avp_item
, "%s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
1055 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
)
1059 proto_item_append_text(avp_item
, "[wrong length for IPv6 address]");
1063 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1065 proto_item_append_text(avp_item
, "%s", tvb_ip6_to_str(pinfo
->pool
, tvb
, offset
));
1069 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
)
1071 ws_in6_addr ipv6_buff
;
1075 if ((len
< 2) || (len
> 18)) {
1076 proto_item_append_text(avp_item
, "[wrong length for IPv6 prefix]");
1080 /* first byte is reserved == 0x00 */
1081 if (tvb_get_uint8(tvb
, offset
)) {
1082 proto_item_append_text(avp_item
, "[invalid reserved byte for IPv6 prefix]");
1086 /* this is the prefix length */
1087 n
= tvb_get_uint8(tvb
, offset
+ 1);
1089 proto_item_append_text(avp_item
, "[invalid IPv6 prefix length]");
1093 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1095 /* cannot use tvb_get_ipv6() here, since the prefix most likely is truncated */
1096 memset(&ipv6_buff
, 0, sizeof ipv6_buff
);
1097 tvb_memcpy(tvb
, &ipv6_buff
, offset
+ 2, len
- 2);
1098 ip6_to_str_buf(&ipv6_buff
, txtbuf
, sizeof(txtbuf
));
1099 proto_item_append_text(avp_item
, "%s/%u", txtbuf
, n
);
1104 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
)
1108 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
1109 proto_item_append_text(avp_item
, "%s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
1110 } else if (len
== 16) {
1111 proto_tree_add_item(tree
, a
->hf_alt
, tvb
, offset
, len
, ENC_NA
);
1112 proto_item_append_text(avp_item
, "%s", tvb_ip6_to_str(pinfo
->pool
, tvb
, offset
));
1114 proto_item_append_text(avp_item
, "[wrong length for both of IPv4 and IPv6 address]");
1120 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
)
1125 proto_item_append_text(avp_item
, "[wrong length for IPX network]");
1129 net
= tvb_get_ntohl(tvb
, offset
);
1131 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1133 proto_item_append_text(avp_item
, "0x%08X", net
);
1137 radius_date(radius_attr_info_t
*a
, proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_item
*avp_item
)
1142 proto_item_append_text(avp_item
, "[wrong length for timestamp]");
1146 time_ptr
.secs
= tvb_get_ntohl(tvb
, offset
);
1149 proto_tree_add_time(tree
, a
->hf
, tvb
, offset
, len
, &time_ptr
);
1150 proto_item_append_text(avp_item
, "%s", abs_time_to_str(pinfo
->pool
, &time_ptr
, ABSOLUTE_TIME_LOCAL
, true));
1154 * "abinary" is Ascend's binary format for filters. See dissect_ascend_data_filter().
1157 radius_abinary(radius_attr_info_t
*a
, proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_item
*avp_item
)
1159 if (a
->code
.u8_code
[0] == 242) {
1160 add_avp_to_tree_with_dissector(tree
, avp_item
, pinfo
, tvb
, dissect_ascend_data_filter
, len
, offset
);
1163 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1164 proto_item_append_text(avp_item
, "%s", tvb_bytes_to_str(pinfo
->pool
, tvb
, offset
, len
));
1168 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
)
1171 proto_item_append_text(avp_item
, "[wrong length for ethernet address]");
1175 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1176 proto_item_append_text(avp_item
, "%s", tvb_ether_to_str(pinfo
->pool
, tvb
, offset
));
1180 radius_ifid(radius_attr_info_t
*a
, proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_item
*avp_item
)
1182 proto_tree_add_item(tree
, a
->hf
, tvb
, offset
, len
, ENC_NA
);
1183 proto_item_append_text(avp_item
, "%s", tvb_bytes_to_str(pinfo
->pool
, tvb
, offset
, len
));
1187 add_tlv_to_tree(proto_tree
*tlv_tree
, proto_item
*tlv_item
, packet_info
*pinfo
, tvbuff_t
*tvb
, radius_attr_info_t
*dictionary_entry
, uint32_t tlv_length
, uint32_t offset
)
1189 proto_item_append_text(tlv_item
, ": ");
1190 dictionary_entry
->type(dictionary_entry
, tlv_tree
, pinfo
, tvb
, offset
, tlv_length
, tlv_item
);
1194 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
)
1199 radius_attr_info_t
*dictionary_entry
= NULL
;
1201 uint32_t tlv_length
;
1203 proto_item
*tlv_item
;
1204 proto_item
*tlv_len_item
;
1205 proto_tree
*tlv_tree
;
1208 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1209 "Not enough room in packet for TLV header");
1212 tlv_type
= tvb_get_uint8(tvb
, offset
);
1213 tlv_length
= tvb_get_uint8(tvb
, offset
+1);
1215 if (tlv_length
< 2) {
1216 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1217 "TLV too short: length %u < 2", tlv_length
);
1221 if (len
< (int)tlv_length
) {
1222 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1223 "Not enough room in packet for TLV");
1230 dictionary_entry
= (radius_attr_info_t
*)g_hash_table_lookup(a
->tlvs_by_id
, GUINT_TO_POINTER(tlv_type
));
1232 if (!dictionary_entry
) {
1233 dictionary_entry
= &no_dictionary_entry
;
1236 tlv_tree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, tlv_length
,
1237 dictionary_entry
->ett
, &tlv_item
, "TLV: t=%s(%u) l=%u ", dictionary_entry
->name
, tlv_type
,
1244 tlv_len_item
= proto_tree_add_uint(tlv_tree
,
1245 dictionary_entry
->hf_len
,
1246 tvb
, 0, 0, tlv_length
);
1247 proto_item_set_generated(tlv_len_item
);
1250 add_tlv_to_tree(tlv_tree
, tlv_item
, pinfo
, tvb
, dictionary_entry
,
1251 tlv_length
, offset
);
1252 offset
+= tlv_length
;
1256 proto_item_append_text(avp_item
, "%d TLV(s) inside", tlv_num
);
1260 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
, uint32_t avp_length
, uint32_t offset
)
1262 tvbuff_t
*tvb_value
;
1265 tvb_value
= tvb_new_subset_length(tvb
, offset
, avp_length
);
1266 str
= avp_dissector(avp_tree
, tvb_value
, pinfo
);
1267 proto_item_append_text(avp_item
, "%s", str
);
1271 add_avp_to_tree(proto_tree
*avp_tree
, proto_item
*avp_item
, packet_info
*pinfo
, tvbuff_t
*tvb
, radius_attr_info_t
*dictionary_entry
, uint32_t avp_length
, uint32_t offset
, radius_call_t
*radius_call
)
1274 if (dictionary_entry
->tagged
) {
1277 if (avp_length
== 0) {
1278 proto_tree_add_expert_format(avp_tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
,
1279 0, "AVP too short for tag");
1283 tag
= tvb_get_uint8(tvb
, offset
);
1286 proto_tree_add_uint(avp_tree
,
1287 dictionary_entry
->hf_tag
,
1288 tvb
, offset
, 1, tag
);
1290 proto_item_append_text(avp_item
,
1291 " Tag=0x%.2x", tag
);
1298 proto_item_append_text(avp_item
, " val=");
1300 if (dictionary_entry
->dissector
) {
1301 add_avp_to_tree_with_dissector(avp_tree
, avp_item
, pinfo
, tvb
, dictionary_entry
->dissector
, avp_length
, offset
);
1305 if (dictionary_entry
->encrypt
> 0) {
1306 if (*shared_secret
=='\0' || avp_length
== 0 || !radius_call
) {
1307 proto_item_append_text(avp_item
, "Encrypted");
1308 proto_tree_add_item(avp_tree
, dictionary_entry
->hf_enc
, tvb
, offset
, avp_length
, ENC_NA
);
1310 tvbuff_t
*tvb_decrypted
;
1313 switch (dictionary_entry
->encrypt
) {
1314 case 1: /* encrypted like User-Password as defined in RFC 2865 */
1315 /* decrypted data is same length as encrypted data */
1316 buffer
= (uint8_t *)wmem_alloc(pinfo
->pool
, avp_length
);
1318 radius_decrypt_avp(buffer
, pinfo
, tvb
, offset
, avp_length
, radius_call
->req_authenticator
, NULL
, 0, 1);
1319 tvb_decrypted
= tvb_new_child_real_data(tvb
, buffer
, avp_length
, avp_length
);
1320 proto_item_append_text(avp_item
, "Decrypted: ");
1321 add_new_data_source(pinfo
, tvb_decrypted
, "Decrypted Data");
1322 /* strip padding for string type */
1323 if (dictionary_entry
->type
== radius_string
) {
1324 for (uint8_t i
=0; i
< avp_length
; i
++){
1325 if (buffer
[i
] == '\0')
1329 dictionary_entry
->type(dictionary_entry
, avp_tree
, pinfo
, tvb_decrypted
, 0, avp_length
, avp_item
);
1332 case 2: /* encrypted like Tunnel-Password as defined in RFC 2868 */
1333 /* check if there is at least 1 byte of encrypted data after salt */
1334 if (avp_length
< 3) {
1335 proto_item_append_text(avp_item
, "Encrypted");
1336 proto_tree_add_item(avp_tree
, dictionary_entry
->hf_enc
, tvb
, offset
, avp_length
, ENC_NA
);
1339 /* decrypted data is same length as encrypted data */
1340 buffer
= (char *)wmem_alloc(pinfo
->pool
, avp_length
- 2);
1343 tvb_memcpy(tvb
, salt
, offset
, 2);
1345 radius_decrypt_avp(buffer
, pinfo
, tvb
, offset
+ 2, avp_length
, radius_call
->req_authenticator
, salt
, 2, 2);
1346 tvb_decrypted
= tvb_new_child_real_data(tvb
, buffer
, avp_length
, avp_length
);
1347 proto_item_append_text(avp_item
, "Decrypted: ");
1348 /* first byte contains length of decrypted data */
1349 avp_length
= (buffer
[0] < avp_length
) ? buffer
[0] : avp_length
-1;
1350 add_new_data_source(pinfo
, tvb_decrypted
, "Decrypted Data");
1351 dictionary_entry
->type(dictionary_entry
, avp_tree
, pinfo
, tvb_decrypted
, 1, avp_length
, avp_item
);
1354 case 3: /* encrypted like Ascend-Send-Secret as defined by Ascend^WLucent^WAlcatel-Lucent */
1355 /* maximum length is MD5 hash length */
1356 if (avp_length
> HASH_MD5_LENGTH
)
1357 avp_length
= HASH_MD5_LENGTH
;
1358 /* decrypted data is same length as encrypted data */
1359 buffer
= (uint8_t *)wmem_alloc(pinfo
->pool
, avp_length
);
1361 radius_decrypt_avp(buffer
, pinfo
, tvb
, offset
, avp_length
, radius_call
->req_authenticator
, NULL
, 0, 3);
1362 tvb_decrypted
= tvb_new_child_real_data(tvb
, buffer
, avp_length
, avp_length
);
1363 proto_item_append_text(avp_item
, "Decrypted: ");
1364 add_new_data_source(pinfo
, tvb_decrypted
, "Decrypted Data");
1365 dictionary_entry
->type(dictionary_entry
, avp_tree
, pinfo
, tvb_decrypted
, 0, avp_length
, avp_item
);
1370 dictionary_entry
->type(dictionary_entry
, avp_tree
, pinfo
, tvb
, offset
, avp_length
, avp_item
);
1375 vsa_buffer_destroy(void *k _U_
, void *v
, void *p _U_
)
1377 radius_vsa_buffer
*vsa_buffer
= (radius_vsa_buffer
*)v
;
1378 g_free((void *)vsa_buffer
->data
);
1384 eap_buffer_free_indirect(void *context
)
1386 uint8_t *eap_buffer
= *(uint8_t **)context
;
1391 vsa_buffer_table_destroy_indirect(void *context
)
1393 GHashTable
*vsa_buffer_table
= *(GHashTable
**)context
;
1394 if (vsa_buffer_table
) {
1395 g_hash_table_foreach_remove(vsa_buffer_table
, vsa_buffer_destroy
, NULL
);
1396 g_hash_table_destroy(vsa_buffer_table
);
1401 * returns true if the authenticator is valid
1402 * input: tvb of the radius packet, corresponding request authenticator (not used for request),
1403 * uses the shared secret to calculate the (message) authenticator
1404 * and checks with the current.
1405 * see RFC 2865, packet format page 16
1406 * see RFC 2866, Request Authenticator page 7
1407 * see RFC 2869, Message-Authenticator page 33
1410 valid_authenticator (packet_info
*pinfo
, tvbuff_t
*tvb
, uint8_t request_authenticator
[], bool rfc2869
, int offset
)
1412 gcry_md_hd_t md5_handle
;
1415 unsigned tvb_length
;
1418 uint8_t message_authenticator
[AUTHENTICATOR_LENGTH
];
1420 tvb_length
= tvb_captured_length(tvb
);
1422 if (tvb_length
!= tvb_reported_length(tvb
) || tvb_length
< (unsigned)(offset
+ AUTHENTICATOR_LENGTH
)) {
1426 /* copy packet into payload */
1427 payload
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, 0, tvb_length
);
1429 rh_code
= tvb_get_uint8(tvb
, 0);
1432 /* reset (message) authenticator field */
1433 memset(payload
+offset
, 0, AUTHENTICATOR_LENGTH
);
1434 if (rh_code
!= RADIUS_PKT_TYPE_ACCESS_REQUEST
) {
1435 /* replace authenticator in reply with the one in request */
1436 memcpy(payload
+4, request_authenticator
, AUTHENTICATOR_LENGTH
);
1438 /* copy authenticator data */
1439 tvb_memcpy(tvb
, message_authenticator
, offset
, AUTHENTICATOR_LENGTH
);
1440 /* calculate HMAC_MD5 hash (payload) */
1441 if (gcry_md_open(&md5_handle
, GCRY_MD_MD5
, GCRY_MD_FLAG_HMAC
)) {
1444 gcry_md_setkey(md5_handle
, shared_secret
, strlen(shared_secret
));
1445 gcry_md_write(md5_handle
, payload
, tvb_length
);
1446 digest
= gcry_md_read(md5_handle
, 0);
1448 result
= !memcmp(digest
, message_authenticator
, AUTHENTICATOR_LENGTH
);
1449 gcry_md_close(md5_handle
);
1451 if (rh_code
== RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
) {
1452 /* reset (message) authenticator field */
1453 memset(payload
+4, 0, AUTHENTICATOR_LENGTH
);
1455 /* replace authenticator in reply with the one in request */
1456 memcpy(payload
+4, request_authenticator
, AUTHENTICATOR_LENGTH
);
1458 /* calculate MD5 hash (payload+shared_secret) */
1459 if (gcry_md_open(&md5_handle
, GCRY_MD_MD5
, 0)) {
1462 gcry_md_write(md5_handle
, payload
, tvb_length
);
1463 gcry_md_write(md5_handle
, shared_secret
, strlen(shared_secret
));
1464 digest
= gcry_md_read(md5_handle
, 0);
1466 result
= !memcmp(digest
, authenticator
, AUTHENTICATOR_LENGTH
);
1467 gcry_md_close(md5_handle
);
1473 dissect_attribute_value_pairs(proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, unsigned length
, radius_call_t
*radius_call
)
1475 bool last_eap
= false;
1476 uint8_t *eap_buffer
= NULL
;
1477 unsigned eap_seg_num
= 0;
1478 unsigned eap_tot_len_captured
= 0;
1479 unsigned eap_tot_len
= 0;
1480 proto_tree
*eap_tree
= NULL
;
1481 tvbuff_t
*eap_tvb
= NULL
;
1483 GHashTable
*vsa_buffer_table
= NULL
;
1485 if (hf_radius_code
<= 0)
1486 proto_registrar_get_byname("radius.code");
1489 * In case we throw an exception, clean up whatever stuff we've
1490 * allocated (if any).
1492 CLEANUP_PUSH_PFX(la
, eap_buffer_free_indirect
, &eap_buffer
);
1493 CLEANUP_PUSH_PFX(lb
, vsa_buffer_table_destroy_indirect
, &vsa_buffer_table
);
1495 while (length
> 0) {
1496 radius_attr_info_t
*dictionary_entry
= NULL
;
1497 uint32_t avp_type0
= 0, avp_type1
= 0;
1498 radius_attr_type_t avp_type
;
1499 uint32_t avp_length
;
1501 bool avp_is_extended
= false;
1502 int avp_offset_start
= offset
;
1504 proto_item
*avp_item
;
1505 proto_item
*avp_len_item
;
1506 proto_tree
*avp_tree
;
1509 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1510 "Not enough room in packet for AVP header");
1511 break; /* exit outer loop, then cleanup & return */
1514 avp_type0
= tvb_get_uint8(tvb
, offset
);
1515 avp_length
= tvb_get_uint8(tvb
, offset
+1);
1516 avp_is_extended
= RADIUS_ATTR_TYPE_IS_EXTENDED(avp_type0
);
1517 if (avp_is_extended
) {
1518 avp_type1
= tvb_get_uint8(tvb
, offset
+2);
1520 memset(&avp_type
, 0, sizeof(avp_type
));
1521 avp_type
.u8_code
[0] = avp_type0
;
1522 avp_type
.u8_code
[1] = avp_type1
;
1524 if (disable_extended_attributes
) {
1525 avp_is_extended
= false;
1526 avp_type
.u8_code
[1] = 0;
1529 if (avp_length
< 2) {
1530 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1531 "AVP too short: length %u < 2", avp_length
);
1532 break; /* exit outer loop, then cleanup & return */
1535 if (avp_is_extended
&& avp_length
< 3) {
1536 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1537 "Extended AVP too short: length %u < 3", avp_length
);
1538 break; /* exit outer loop, then cleanup & return */
1541 if (length
< avp_length
) {
1542 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
, 0,
1543 "Not enough room in packet for AVP");
1544 break; /* exit outer loop, then cleanup & return */
1547 length
-= avp_length
;
1549 dictionary_entry
= (radius_attr_info_t
*)g_hash_table_lookup(dict
->attrs_by_id
, GUINT_TO_POINTER(avp_type
.value
));
1551 if (!dictionary_entry
) {
1552 dictionary_entry
= &no_dictionary_entry
;
1555 avp_item
= proto_tree_add_bytes_format_value(tree
, hf_radius_avp
, tvb
, offset
, avp_length
,
1556 NULL
, "t=%s", dictionary_entry
->name
);
1557 if (avp_is_extended
)
1558 proto_item_append_text(avp_item
, "(%u.%u)", avp_type0
, avp_type1
);
1560 proto_item_append_text(avp_item
, "(%u)", avp_type0
);
1562 proto_item_append_text(avp_item
, " l=%u", avp_length
);
1566 if (avp_is_extended
) {
1569 if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0
)) {
1575 if (avp_type0
== RADIUS_ATTR_TYPE_VENDOR_SPECIFIC
|| (avp_is_extended
&& avp_type1
== RADIUS_ATTR_TYPE_VENDOR_SPECIFIC
)) {
1576 radius_vendor_info_t
*vendor
;
1577 proto_tree
*vendor_tree
;
1578 int max_offset
= offset
+ avp_length
;
1579 const char *vendor_str
;
1582 /* XXX TODO: handle 2 byte codes for USR */
1584 if (avp_length
< 4) {
1585 expert_add_info_format(pinfo
, avp_item
, &ei_radius_invalid_length
, "AVP too short; no room for vendor ID");
1586 offset
+= avp_length
;
1587 continue; /* while (length > 0) */
1589 vendor_id
= tvb_get_ntohl(tvb
, offset
);
1594 vendor
= (radius_vendor_info_t
*)g_hash_table_lookup(dict
->vendors_by_id
, GUINT_TO_POINTER(vendor_id
));
1595 vendor_str
= enterprises_lookup(vendor_id
, "Unknown");
1597 vendor
= &no_vendor
;
1599 proto_item_append_text(avp_item
, " vnd=%s(%u)", vendor_str
,
1602 vendor_tree
= proto_item_add_subtree(avp_item
, vendor
->ett
);
1604 vendor_offset
= avp_offset_start
;
1605 proto_tree_add_item(vendor_tree
, hf_radius_avp_type
, tvb
, vendor_offset
, 1, ENC_BIG_ENDIAN
);
1606 proto_tree_add_item(vendor_tree
, hf_radius_avp_length
, tvb
, vendor_offset
+1, 1, ENC_BIG_ENDIAN
);
1608 if (avp_is_extended
) {
1609 proto_tree_add_item(vendor_tree
, hf_radius_avp_extended_type
, tvb
, vendor_offset
, 1, ENC_BIG_ENDIAN
);
1611 if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0
)) {
1612 proto_tree_add_item(vendor_tree
, hf_radius_avp_extended_more
, tvb
, vendor_offset
, 1, ENC_BIG_ENDIAN
);
1616 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
);
1619 while (offset
< max_offset
) {
1620 radius_attr_type_t vendor_type
;
1621 uint32_t avp_vsa_type
;
1622 uint32_t avp_vsa_len
;
1623 uint8_t avp_vsa_flags
= 0;
1624 uint32_t avp_vsa_header_len
;
1625 uint32_t vendor_attribute_len
;
1627 switch (vendor
->type_octets
) {
1629 avp_vsa_type
= tvb_get_uint8(tvb
, offset
++);
1632 avp_vsa_type
= tvb_get_ntohs(tvb
, offset
);
1636 avp_vsa_type
= tvb_get_ntohl(tvb
, offset
);
1640 /* vendor->type_octets = 1; */
1641 DISSECTOR_ASSERT_NOT_REACHED();
1645 if (!avp_is_extended
) {
1646 switch (vendor
->length_octets
) {
1648 avp_vsa_len
= tvb_get_uint8(tvb
, offset
++);
1651 avp_vsa_len
= avp_length
;
1654 avp_vsa_len
= tvb_get_ntohs(tvb
, offset
);
1658 /* vendor->length_octets = 1; */
1659 DISSECTOR_ASSERT_NOT_REACHED();
1662 avp_vsa_header_len
= vendor
->type_octets
+ vendor
->length_octets
+ (vendor
->has_flags
? 1 : 0);
1664 avp_vsa_len
= avp_length
;
1665 avp_vsa_header_len
= vendor
->type_octets
+ (vendor
->has_flags
? 1 : 0);
1668 if (vendor
->has_flags
) {
1669 avp_vsa_flags
= tvb_get_uint8(tvb
, offset
++);
1672 if (avp_vsa_len
< avp_vsa_header_len
) {
1673 proto_tree_add_expert_format(tree
, pinfo
, &ei_radius_invalid_length
, tvb
, offset
+1, 1,
1675 break; /* exit while (offset < max_offset) loop */
1678 avp_vsa_len
-= avp_vsa_header_len
;
1680 memset(&vendor_type
, 0, sizeof(vendor_type
));
1681 if (avp_is_extended
) {
1682 vendor_type
.u8_code
[0] = avp_type
.u8_code
[0];
1683 vendor_type
.u8_code
[1] = avp_vsa_type
;
1685 vendor_type
.u8_code
[0] = avp_vsa_type
;
1686 vendor_type
.u8_code
[1] = 0;
1688 if (vendor
->attrs_by_id
) {
1689 dictionary_entry
= (radius_attr_info_t
*)g_hash_table_lookup(vendor
->attrs_by_id
, GUINT_TO_POINTER(vendor_type
.value
));
1691 dictionary_entry
= NULL
;
1694 if (!dictionary_entry
) {
1695 dictionary_entry
= &no_dictionary_entry
;
1698 if (vendor
->has_flags
) {
1699 avp_tree
= proto_tree_add_subtree_format(vendor_tree
, tvb
, offset
-avp_vsa_header_len
, avp_vsa_len
+avp_vsa_header_len
,
1700 dictionary_entry
->ett
, &avp_item
, "VSA: t=%s(%u) l=%u C=0x%02x",
1701 dictionary_entry
->name
, avp_vsa_type
, avp_vsa_len
+avp_vsa_header_len
, avp_vsa_flags
);
1702 } else if (avp_is_extended
) {
1703 avp_tree
= proto_tree_add_subtree_format(vendor_tree
, tvb
, offset
-avp_vsa_header_len
, avp_vsa_len
+avp_vsa_header_len
,
1704 dictionary_entry
->ett
, &avp_item
, "EVS: t=%s(%u) l=%u",
1705 dictionary_entry
->name
, avp_vsa_type
, avp_vsa_len
+avp_vsa_header_len
);
1707 avp_tree
= proto_tree_add_subtree_format(vendor_tree
, tvb
, offset
-avp_vsa_header_len
, avp_vsa_len
+avp_vsa_header_len
,
1708 dictionary_entry
->ett
, &avp_item
, "VSA: t=%s(%u) l=%u",
1709 dictionary_entry
->name
, avp_vsa_type
, avp_vsa_len
+avp_vsa_header_len
);
1712 proto_tree_add_item(avp_tree
, hf_radius_avp_vendor_type
, tvb
, vendor_offset
, vendor
->type_octets
, ENC_BIG_ENDIAN
);
1713 vendor_offset
+= vendor
->type_octets
;
1714 if (!avp_is_extended
&& vendor
->length_octets
) {
1715 proto_tree_add_item_ret_uint(avp_tree
, hf_radius_avp_vendor_len
, tvb
, vendor_offset
, vendor
->length_octets
, ENC_BIG_ENDIAN
, &vendor_attribute_len
);
1716 vendor_offset
+= (vendor_attribute_len
- vendor
->type_octets
);
1720 avp_len_item
= proto_tree_add_uint(avp_tree
,
1721 dictionary_entry
->hf_len
,
1722 tvb
, 0, 0, avp_length
);
1723 proto_item_set_generated(avp_len_item
);
1726 if (vendor
->has_flags
) {
1728 * WiMAX VSA's have a non-standard format:
1732 * continuation 1 octet 0bcrrrrrrr
1735 * If the high bit of the "continuation" field is set, then
1736 * the next attribute of the same WiMAX type should have it's
1737 * value concatenated to this one.
1739 * See "dictionary.wimax" from FreeRADIUS for details and references.
1741 radius_vsa_buffer_key key
;
1742 radius_vsa_buffer
*vsa_buffer
= NULL
;
1743 key
.vendor_id
= vendor_id
;
1744 key
.vsa_type
= avp_vsa_type
;
1746 if (!vsa_buffer_table
) {
1747 vsa_buffer_table
= g_hash_table_new(radius_vsa_hash
, radius_vsa_equal
);
1750 vsa_buffer
= (radius_vsa_buffer
*)g_hash_table_lookup(vsa_buffer_table
, &key
);
1752 vsa_buffer
->data
= (uint8_t *)g_realloc(vsa_buffer
->data
, vsa_buffer
->len
+ avp_vsa_len
);
1753 tvb_memcpy(tvb
, vsa_buffer
->data
+ vsa_buffer
->len
, offset
, avp_vsa_len
);
1754 vsa_buffer
->len
+= avp_vsa_len
;
1755 vsa_buffer
->seg_num
++;
1758 if (avp_vsa_flags
& 0x80) {
1760 vsa_buffer
= g_new(radius_vsa_buffer
, 1);
1761 vsa_buffer
->key
.vendor_id
= vendor_id
;
1762 vsa_buffer
->key
.vsa_type
= avp_vsa_type
;
1763 vsa_buffer
->len
= avp_vsa_len
;
1764 vsa_buffer
->seg_num
= 1;
1765 vsa_buffer
->data
= (uint8_t *)g_malloc(avp_vsa_len
);
1766 tvb_memcpy(tvb
, vsa_buffer
->data
, offset
, avp_vsa_len
);
1767 g_hash_table_insert(vsa_buffer_table
, &(vsa_buffer
->key
), vsa_buffer
);
1769 proto_tree_add_item(avp_tree
, hf_radius_vsa_fragment
, tvb
, offset
, avp_vsa_len
, ENC_NA
);
1770 proto_item_append_text(avp_item
, ": VSA fragment[%u]", vsa_buffer
->seg_num
);
1773 tvbuff_t
*vsa_tvb
= NULL
;
1774 proto_tree_add_item(avp_tree
, hf_radius_vsa_fragment
, tvb
, offset
, avp_vsa_len
, ENC_NA
);
1775 proto_item_append_text(avp_item
, ": Last VSA fragment[%u]", vsa_buffer
->seg_num
);
1776 vsa_tvb
= tvb_new_child_real_data(tvb
, vsa_buffer
->data
, vsa_buffer
->len
, vsa_buffer
->len
);
1777 tvb_set_free_cb(vsa_tvb
, g_free
);
1778 add_new_data_source(pinfo
, vsa_tvb
, "Reassembled VSA");
1779 add_avp_to_tree(avp_tree
, avp_item
, pinfo
, vsa_tvb
, dictionary_entry
, vsa_buffer
->len
, 0, radius_call
);
1780 g_hash_table_remove(vsa_buffer_table
, &(vsa_buffer
->key
));
1784 add_avp_to_tree(avp_tree
, avp_item
, pinfo
, tvb
, dictionary_entry
, avp_vsa_len
, offset
, radius_call
);
1788 add_avp_to_tree(avp_tree
, avp_item
, pinfo
, tvb
, dictionary_entry
, avp_vsa_len
, offset
, radius_call
);
1791 offset
+= avp_vsa_len
;
1792 } /* while (offset < max_offset) */
1793 continue; /* while (length > 0) */
1796 avp_tree
= proto_item_add_subtree(avp_item
, dictionary_entry
->ett
);
1798 proto_tree_add_item(avp_tree
, hf_radius_avp_type
, tvb
, avp_offset_start
, 1, ENC_BIG_ENDIAN
);
1799 proto_tree_add_item(avp_tree
, hf_radius_avp_length
, tvb
, avp_offset_start
+1, 1, ENC_BIG_ENDIAN
);
1802 avp_len_item
= proto_tree_add_uint(avp_tree
,
1803 dictionary_entry
->hf_len
,
1804 tvb
, 0, 0, avp_length
);
1805 proto_item_set_generated(avp_len_item
);
1808 if (avp_is_extended
) {
1809 proto_tree_add_item(avp_tree
, hf_radius_avp_extended_type
, tvb
, avp_offset_start
+2, 1, ENC_BIG_ENDIAN
);
1810 if (RADIUS_ATTR_TYPE_IS_EXTENDED_LONG(avp_type0
)) {
1811 proto_tree_add_item(avp_tree
, hf_radius_avp_extended_more
, tvb
, avp_offset_start
+3, 1, ENC_BIG_ENDIAN
);
1815 /* XXX - Do similar concatenation if dictionary_entry->concat == true */
1816 if (avp_type0
== RADIUS_ATTR_TYPE_EAP_MESSAGE
) {
1821 tvb_len
= tvb_captured_length_remaining(tvb
, offset
);
1823 if ((int)avp_length
< tvb_len
)
1824 tvb_len
= avp_length
;
1826 /* Show this as an EAP fragment. */
1827 proto_tree_add_item(avp_tree
, hf_radius_eap_fragment
, tvb
, offset
, tvb_len
, ENC_NA
);
1829 if (eap_tvb
!= NULL
) {
1831 * Oops, a non-consecutive EAP-Message
1834 proto_item_append_text(avp_item
, " (non-consecutive)");
1837 * RFC 2869 says, in section 5.13, describing
1838 * the EAP-Message attribute:
1840 * The NAS places EAP messages received
1841 * from the authenticating peer into one
1842 * or more EAP-Message attributes and
1843 * forwards them to the RADIUS Server
1844 * within an Access-Request message.
1845 * If multiple EAP-Messages are
1846 * contained within an Access-Request or
1847 * Access-Challenge packet, they MUST be
1848 * in order and they MUST be consecutive
1849 * attributes in the Access-Request or
1850 * Access-Challenge packet.
1854 * The String field contains EAP packets,
1855 * as defined in [3]. If multiple
1856 * EAP-Message attributes are present
1857 * in a packet their values should be
1858 * concatenated; this allows EAP packets
1859 * longer than 253 octets to be passed
1862 * Do reassembly of EAP-Message attributes.
1863 * We just concatenate all the attributes,
1864 * and when we see either the end of the
1865 * attribute list or a non-EAP-Message
1866 * attribute, we know we're done.
1869 if (eap_buffer
== NULL
)
1870 eap_buffer
= (uint8_t *)g_malloc(eap_tot_len_captured
+ tvb_len
);
1872 eap_buffer
= (uint8_t *)g_realloc(eap_buffer
,
1873 eap_tot_len_captured
+ tvb_len
);
1874 tvb_memcpy(tvb
, eap_buffer
+ eap_tot_len_captured
, offset
,
1876 eap_tot_len_captured
+= tvb_len
;
1877 eap_tot_len
+= avp_length
;
1879 if (tvb_bytes_exist(tvb
, offset
+ avp_length
+ 1, 1)) {
1880 uint8_t next_type
= tvb_get_uint8(tvb
, offset
+ avp_length
);
1882 if (next_type
!= RADIUS_ATTR_TYPE_EAP_MESSAGE
) {
1883 /* Non-EAP-Message attribute */
1888 * No more attributes, either because
1889 * we're at the end of the packet or
1890 * because we're at the end of the
1891 * captured packet data.
1896 if (last_eap
&& eap_buffer
) {
1899 proto_item_append_text(avp_item
, " Last Segment[%u]",
1902 eap_tree
= proto_item_add_subtree(avp_item
, ett_eap
);
1904 eap_tvb
= tvb_new_child_real_data(tvb
, eap_buffer
,
1905 eap_tot_len_captured
,
1907 tvb_set_free_cb(eap_tvb
, g_free
);
1908 add_new_data_source(pinfo
, eap_tvb
, "Reassembled EAP");
1911 * Don't free this when we're done -
1912 * it's associated with a tvbuff.
1917 * Set the columns non-writable,
1918 * so that the packet list shows
1919 * this as an RADIUS packet, not
1922 save_writable
= col_get_writable(pinfo
->cinfo
, -1);
1923 col_set_writable(pinfo
->cinfo
, -1, false);
1925 call_dissector(eap_handle
, eap_tvb
, pinfo
, eap_tree
);
1927 col_set_writable(pinfo
->cinfo
, -1, save_writable
);
1929 proto_item_append_text(avp_item
, " Segment[%u]",
1934 offset
+= avp_length
;
1938 if (avp_type0
== RADIUS_ATTR_TYPE_MESSAGE_AUTHENTICATOR
&& validate_authenticator
&& *shared_secret
!= '\0' && radius_call
) {
1939 proto_item
*authenticator_tree
, *item
;
1942 valid
= valid_authenticator(pinfo
, tvb
, radius_call
->req_authenticator
, true, offset
);
1944 proto_item_append_text(avp_item
, " [%s]", valid
? "correct" : "incorrect");
1946 authenticator_tree
= proto_item_add_subtree(avp_item
, ett_radius_authenticator
);
1947 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_message_authenticator_valid
, tvb
, offset
, AUTHENTICATOR_LENGTH
, valid
== 1 ? true : false);
1948 proto_item_set_generated(item
);
1949 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_message_authenticator_invalid
, tvb
, offset
, AUTHENTICATOR_LENGTH
, valid
== 0 ? true : false);
1950 proto_item_set_generated(item
);
1953 col_append_str(pinfo
->cinfo
, COL_INFO
, " [incorrect message authenticator]");
1957 add_avp_to_tree(avp_tree
, avp_item
, pinfo
, tvb
, dictionary_entry
,
1958 avp_length
, offset
, radius_call
);
1959 offset
+= avp_length
;
1961 } /* while (length > 0) */
1963 CLEANUP_CALL_AND_POP_PFX(lb
); /* vsa_buffer_table_destroy_indirect(&vsa_buffer_table) */
1966 * Call the cleanup handler to free any reassembled data we haven't
1967 * attached to a tvbuff, and pop the handler.
1969 CLEANUP_CALL_AND_POP_PFX(la
); /* eap_buffer_free_indirect(&eap_buffer); */
1972 /* This function tries to determine whether a packet is radius or not */
1974 is_radius(tvbuff_t
*tvb
)
1979 code
= tvb_get_uint8(tvb
, 0);
1980 if (try_val_to_str_ext(code
, &radius_pkt_type_codes_ext
) == NULL
) {
1984 /* Check for valid length value:
1987 * The Length field is two octets. It indicates the length of the
1988 * packet including the Code, Identifier, Length, Authenticator and
1989 * Attribute fields. Octets outside the range of the Length field
1990 * MUST be treated as padding and ignored on reception. If the
1991 * packet is shorter than the Length field indicates, it MUST be
1992 * silently discarded. The minimum length is 20 and maximum length
1995 length
= tvb_get_ntohs(tvb
, 2);
1996 if ((length
< 20) || (length
> 4096)) {
2004 dissect_radius(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2006 proto_tree
*radius_tree
= NULL
;
2007 proto_tree
*avptree
= NULL
;
2008 proto_item
*ti
, *hidden_item
, *authenticator_item
= NULL
;
2011 radius_info_t
*rad_info
;
2013 conversation_t
*conversation
;
2014 radius_call_info_key radius_call_key
;
2015 radius_call_info_key
*new_radius_call_key
;
2016 wmem_tree_t
*radius_call_tree
;
2017 radius_call_t
*radius_call
= NULL
;
2018 static address null_address
= ADDRESS_INIT_NONE
;
2020 /* does this look like radius ? */
2021 if (!is_radius(tvb
)) {
2025 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RADIUS");
2026 col_clear(pinfo
->cinfo
, COL_INFO
);
2028 rh
.rh_code
= tvb_get_uint8(tvb
, 0);
2029 rh
.rh_ident
= tvb_get_uint8(tvb
, 1);
2030 rh
.rh_pktlength
= tvb_get_ntohs(tvb
, 2);
2033 /* Initialise stat info for passing to tap */
2034 rad_info
= wmem_new(wmem_packet_scope(), radius_info_t
);
2035 rad_info
->req_time
.secs
= 0;
2036 rad_info
->req_time
.nsecs
= 0;
2037 rad_info
->is_duplicate
= false;
2038 rad_info
->request_available
= false;
2039 rad_info
->req_num
= 0; /* frame number request seen */
2040 rad_info
->rspcode
= 0;
2042 rad_info
->code
= rh
.rh_code
;
2043 rad_info
->ident
= rh
.rh_ident
;
2044 tap_queue_packet(radius_tap
, pinfo
, rad_info
);
2046 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s id=%d",
2047 val_to_str_ext_const(rh
.rh_code
, &radius_pkt_type_codes_ext
, "Unknown Packet"),
2050 /* Load header fields if not already done */
2051 if (hf_radius_code
<= 0)
2052 proto_registrar_get_byname("radius.code");
2054 ti
= proto_tree_add_item(tree
, proto_radius
, tvb
, 0, rh
.rh_pktlength
, ENC_NA
);
2055 radius_tree
= proto_item_add_subtree(ti
, ett_radius
);
2056 proto_tree_add_uint(radius_tree
, hf_radius_code
, tvb
, 0, 1, rh
.rh_code
);
2057 proto_tree_add_uint_format(radius_tree
, hf_radius_id
, tvb
, 1, 1, rh
.rh_ident
,
2058 "Packet identifier: 0x%01x (%d)", rh
.rh_ident
, rh
.rh_ident
);
2061 * Make sure the length is sane.
2063 if (rh
.rh_pktlength
< HDR_LENGTH
) {
2064 proto_tree_add_uint_format_value(radius_tree
, hf_radius_length
,
2065 tvb
, 2, 2, rh
.rh_pktlength
, "%u (bogus, < %u)",
2066 rh
.rh_pktlength
, HDR_LENGTH
);
2067 return tvb_captured_length(tvb
);
2070 avplength
= rh
.rh_pktlength
- HDR_LENGTH
;
2071 proto_tree_add_uint(radius_tree
, hf_radius_length
, tvb
, 2, 2, rh
.rh_pktlength
);
2072 authenticator_item
= proto_tree_add_item(radius_tree
, hf_radius_authenticator
, tvb
, 4, AUTHENTICATOR_LENGTH
, ENC_NA
);
2073 tvb_memcpy(tvb
, authenticator
, 4, AUTHENTICATOR_LENGTH
);
2075 /* Conversation support REQUEST/RESPONSES */
2078 case RADIUS_PKT_TYPE_ACCESS_REQUEST
:
2079 case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
:
2080 case RADIUS_PKT_TYPE_PASSWORD_REQUEST
:
2081 case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST
:
2082 case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST
:
2083 case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST
:
2084 case RADIUS_PKT_TYPE_EVENT_REQUEST
:
2085 case RADIUS_PKT_TYPE_DISCONNECT_REQUEST
:
2086 case RADIUS_PKT_TYPE_COA_REQUEST
:
2087 case RADIUS_PKT_TYPE_ALU_STATE_REQUEST
:
2088 /* Don't bother creating conversations if we're encapsulated within
2089 * an error packet, such as an ICMP destination unreachable */
2090 if (pinfo
->flags
.in_error_pkt
)
2093 hidden_item
= proto_tree_add_boolean(radius_tree
, hf_radius_req
, tvb
, 0, 0, true);
2094 proto_item_set_hidden(hidden_item
);
2096 /* Keep track of the address and port whence the call came
2097 * so that we can match up requests with replies.
2099 * Because it is UDP and the reply can come from any IP
2100 * and port (not necessarily the request dest), we only
2101 * track the source IP and port of the request to match
2106 * XXX - can we just use NO_ADDR_B? Unfortunately,
2107 * you currently still have to pass a non-null
2108 * pointer for the second address argument even
2111 conversation
= find_conversation(pinfo
->num
, &pinfo
->src
,
2112 &null_address
, conversation_pt_to_conversation_type(pinfo
->ptype
), pinfo
->srcport
,
2113 pinfo
->destport
, 0);
2114 if (conversation
== NULL
)
2116 /* It's not part of any conversation - create a new one. */
2117 conversation
= conversation_new(pinfo
->num
, &pinfo
->src
,
2118 &null_address
, conversation_pt_to_conversation_type(pinfo
->ptype
), pinfo
->srcport
,
2119 pinfo
->destport
, 0);
2122 /* Prepare the key data */
2123 radius_call_key
.code
= rh
.rh_code
;
2124 radius_call_key
.ident
= rh
.rh_ident
;
2125 radius_call_key
.conversation
= conversation
;
2126 radius_call_key
.req_time
= pinfo
->abs_ts
;
2128 /* Look up the tree of calls with this ident */
2129 radius_call_tree
= (wmem_tree_t
*)wmem_map_lookup(radius_calls
, &radius_call_key
);
2131 if (!radius_call_tree
) {
2132 radius_call_tree
= wmem_tree_new(wmem_file_scope());
2133 new_radius_call_key
= wmem_new(wmem_file_scope(), radius_call_info_key
);
2134 *new_radius_call_key
= radius_call_key
;
2135 wmem_map_insert(radius_calls
, new_radius_call_key
, radius_call_tree
);
2138 /* Find the last call we've seen (for this ident in this conversation) */
2139 radius_call
= (radius_call_t
*)wmem_tree_lookup32_le(radius_call_tree
, pinfo
->num
);
2140 if (radius_call
!= NULL
) {
2141 /* We found a request with the same ident (in this conversation).
2142 * Is it really a duplicate?
2144 if (pinfo
->num
!= radius_call
->req_num
&&
2145 !memcmp(radius_call
->req_authenticator
, authenticator
, AUTHENTICATOR_LENGTH
)) {
2146 /* Yes, mark it as such */
2147 rad_info
->is_duplicate
= true;
2148 rad_info
->req_num
= radius_call
->req_num
;
2149 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Duplicate Request");
2153 hidden_item
= proto_tree_add_uint(radius_tree
, hf_radius_dup
, tvb
, 0, 0, rh
.rh_ident
);
2154 proto_item_set_hidden(hidden_item
);
2155 item
= proto_tree_add_uint(radius_tree
, hf_radius_req_dup
, tvb
, 0, 0, radius_call
->req_num
);
2156 proto_item_set_generated(item
);
2160 /* Accounting Request Authenticator Validation */
2161 if (rh
.rh_code
== RADIUS_PKT_TYPE_ACCOUNTING_REQUEST
&& validate_authenticator
&& *shared_secret
!= '\0') {
2162 proto_item
*authenticator_tree
, *item
;
2164 valid
= valid_authenticator(pinfo
, tvb
, radius_call
->req_authenticator
, false, 4);
2166 proto_item_append_text(authenticator_item
, " [%s]", valid
? "correct" : "incorrect");
2168 authenticator_tree
= proto_item_add_subtree(authenticator_item
, ett_radius_authenticator
);
2169 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_authenticator_valid
, tvb
, 4, AUTHENTICATOR_LENGTH
, valid
== 1 ? true : false);
2170 proto_item_set_generated(item
);
2171 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_authenticator_invalid
, tvb
, 4, AUTHENTICATOR_LENGTH
, valid
== 0 ? true : false);
2172 proto_item_set_generated(item
);
2175 col_append_str(pinfo
->cinfo
, COL_INFO
, " [incorrect authenticator]");
2180 if (!PINFO_FD_VISITED(pinfo
) && (radius_call
== NULL
|| !rad_info
->is_duplicate
)) {
2181 /* Prepare the value data.
2182 * "req_num" and "rsp_num" are frame numbers;
2183 * frame numbers are 1-origin, so we use 0
2184 * to mean "we don't yet know in which frame
2185 * the reply for this call appears".
2187 radius_call
= wmem_new(wmem_file_scope(), radius_call_t
);
2188 radius_call
->req_num
= pinfo
->num
;
2189 radius_call
->rsp_num
= 0;
2190 radius_call
->ident
= rh
.rh_ident
;
2191 radius_call
->code
= rh
.rh_code
;
2192 memcpy(radius_call
->req_authenticator
, authenticator
, AUTHENTICATOR_LENGTH
);
2193 radius_call
->responded
= false;
2194 radius_call
->req_time
= pinfo
->abs_ts
;
2195 radius_call
->rspcode
= 0;
2198 wmem_tree_insert32(radius_call_tree
, pinfo
->num
, radius_call
);
2201 if (radius_call
&& radius_call
->rsp_num
) {
2203 item
= proto_tree_add_uint_format(radius_tree
,
2204 hf_radius_rsp_frame
, tvb
, 0, 0, radius_call
->rsp_num
,
2205 "The response to this request is in frame %u",
2206 radius_call
->rsp_num
);
2207 proto_item_set_generated(item
);
2210 case RADIUS_PKT_TYPE_ACCESS_ACCEPT
:
2211 case RADIUS_PKT_TYPE_ACCESS_REJECT
:
2212 case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE
:
2213 case RADIUS_PKT_TYPE_PASSWORD_ACK
:
2214 case RADIUS_PKT_TYPE_PASSWORD_REJECT
:
2215 case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE
:
2216 case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE
:
2217 case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE
:
2218 case RADIUS_PKT_TYPE_EVENT_RESPONSE
:
2219 case RADIUS_PKT_TYPE_DISCONNECT_ACK
:
2220 case RADIUS_PKT_TYPE_DISCONNECT_NAK
:
2221 case RADIUS_PKT_TYPE_COA_ACK
:
2222 case RADIUS_PKT_TYPE_COA_NAK
:
2223 case RADIUS_PKT_TYPE_ACCESS_CHALLENGE
:
2224 case RADIUS_PKT_TYPE_ALU_STATE_ACCEPT
:
2225 case RADIUS_PKT_TYPE_ALU_STATE_REJECT
:
2226 case RADIUS_PKT_TYPE_ALU_STATE_ERROR
:
2227 /* Don't bother finding conversations if we're encapsulated within
2228 * an error packet, such as an ICMP destination unreachable */
2229 if (pinfo
->flags
.in_error_pkt
)
2232 hidden_item
= proto_tree_add_boolean(radius_tree
, hf_radius_rsp
, tvb
, 0, 0, true);
2233 proto_item_set_hidden(hidden_item
);
2235 /* Check for RADIUS response. A response must match a call that
2236 * we've seen, and the response must be sent to the same
2237 * port and address that the call came from.
2239 * Because it is UDP and the reply can come from any IP
2240 * and port (not necessarily the request dest), we only
2241 * track the source IP and port of the request to match
2245 /* XXX - can we just use NO_ADDR_B? Unfortunately,
2246 * you currently still have to pass a non-null
2247 * pointer for the second address argument even
2250 conversation
= find_conversation(pinfo
->num
, &null_address
,
2251 &pinfo
->dst
, conversation_pt_to_conversation_type(pinfo
->ptype
), pinfo
->srcport
, pinfo
->destport
, 0);
2252 if (conversation
== NULL
) {
2253 /* Nothing more to do here */
2257 /* Prepare the key data */
2258 radius_call_key
.code
= rh
.rh_code
;
2259 radius_call_key
.ident
= rh
.rh_ident
;
2260 radius_call_key
.conversation
= conversation
;
2261 radius_call_key
.req_time
= pinfo
->abs_ts
;
2263 /* Look up the tree of calls with this ident */
2264 radius_call_tree
= (wmem_tree_t
*)wmem_map_lookup(radius_calls
, &radius_call_key
);
2265 if (radius_call_tree
== NULL
) {
2266 /* Nothing more to do here */
2270 /* Find the last call we've seen (for this ident in this conversation) */
2271 radius_call
= (radius_call_t
*)wmem_tree_lookup32_le(radius_call_tree
, pinfo
->num
);
2272 if (radius_call
== NULL
) {
2273 /* Nothing more to do here */
2277 /* Indicate the frame to which this is a reply. */
2278 if (radius_call
->req_num
) {
2282 rad_info
->request_available
= true;
2283 rad_info
->req_num
= radius_call
->req_num
;
2284 radius_call
->responded
= true;
2286 item
= proto_tree_add_uint_format(radius_tree
,
2287 hf_radius_req_frame
, tvb
, 0, 0,
2288 radius_call
->req_num
,
2289 "This is a response to a request in frame %u",
2290 radius_call
->req_num
);
2291 proto_item_set_generated(item
);
2292 nstime_delta(&delta
, &pinfo
->abs_ts
, &radius_call
->req_time
);
2293 item
= proto_tree_add_time(radius_tree
, hf_radius_time
, tvb
, 0, 0, &delta
);
2294 proto_item_set_generated(item
);
2295 /* Response Authenticator Validation */
2296 if (validate_authenticator
&& *shared_secret
!= '\0') {
2297 proto_item
*authenticator_tree
;
2299 valid
= valid_authenticator(pinfo
, tvb
, radius_call
->req_authenticator
, false, 4);
2301 proto_item_append_text(authenticator_item
, " [%s]", valid
? "correct" : "incorrect");
2303 authenticator_tree
= proto_item_add_subtree(authenticator_item
, ett_radius_authenticator
);
2304 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_authenticator_valid
, tvb
, 4, AUTHENTICATOR_LENGTH
, valid
== 1 ? true : false);
2305 proto_item_set_generated(item
);
2306 item
= proto_tree_add_boolean(authenticator_tree
, hf_radius_authenticator_invalid
, tvb
, 4, AUTHENTICATOR_LENGTH
, valid
== 0 ? true : false);
2307 proto_item_set_generated(item
);
2310 col_append_str(pinfo
->cinfo
, COL_INFO
, " [incorrect authenticator]");
2315 if (radius_call
->rsp_num
== 0) {
2316 /* We have not yet seen a response to that call, so
2317 this must be the first response; remember its
2319 radius_call
->rsp_num
= pinfo
->num
;
2321 /* We have seen a response to this call - but was it
2322 *this* response? (disregard provisional responses) */
2323 if ((radius_call
->rsp_num
!= pinfo
->num
) && (radius_call
->rspcode
== rh
.rh_code
)) {
2324 /* No, so it's a duplicate response. Mark it as such. */
2325 rad_info
->is_duplicate
= true;
2326 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Duplicate Response");
2330 hidden_item
= proto_tree_add_uint(radius_tree
,
2331 hf_radius_dup
, tvb
, 0, 0, rh
.rh_ident
);
2332 proto_item_set_hidden(hidden_item
);
2333 item
= proto_tree_add_uint(radius_tree
,
2334 hf_radius_rsp_dup
, tvb
, 0, 0, radius_call
->rsp_num
);
2335 proto_item_set_generated(item
);
2339 /* Now store the response code (after comparison above) */
2340 radius_call
->rspcode
= rh
.rh_code
;
2341 rad_info
->rspcode
= rh
.rh_code
;
2348 rad_info
->req_time
= radius_call
->req_time
;
2351 if (avplength
> 0) {
2352 /* list the attribute value pairs */
2353 avptree
= proto_tree_add_subtree(radius_tree
, tvb
, HDR_LENGTH
,
2354 avplength
, ett_radius_avp
, NULL
, "Attribute Value Pairs");
2355 dissect_attribute_value_pairs(avptree
, pinfo
, tvb
, HDR_LENGTH
,
2356 avplength
, radius_call
);
2359 return tvb_captured_length(tvb
);
2363 free_radius_attr_info(void *data
)
2365 radius_attr_info_t
* attr
= (radius_attr_info_t
*)data
;
2366 value_string
*vs
= (value_string
*)attr
->vs
;
2369 if (attr
->tlvs_by_id
) {
2370 g_hash_table_destroy(attr
->tlvs_by_id
);
2373 for (; vs
->strptr
; vs
++) {
2374 g_free((void *)vs
->strptr
);
2376 g_free((void *)attr
->vs
);
2383 free_radius_vendor_info(void *data
)
2385 radius_vendor_info_t
* vendor
= (radius_vendor_info_t
*)data
;
2387 g_free(vendor
->name
);
2388 if (vendor
->attrs_by_id
)
2389 g_hash_table_destroy(vendor
->attrs_by_id
);
2395 register_attrs(void *k _U_
, void *v
, void *p
)
2397 radius_attr_info_t
*a
= (radius_attr_info_t
*)v
;
2399 int *ett
= &(a
->ett
);
2400 char *abbrev
= wmem_strdup_printf(wmem_epan_scope(), "radius.%s", a
->name
);
2401 hf_register_info hfri
[] = {
2402 { NULL
, { NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2403 { NULL
, { NULL
, NULL
, FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
2404 { NULL
, { NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2405 { NULL
, { NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
2406 { NULL
, { NULL
, NULL
, FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}}
2408 unsigned len_hf
= 2;
2409 hfett_t
*ri
= (hfett_t
*)p
;
2411 for(i
=0; abbrev
[i
]; i
++) {
2412 if (abbrev
[i
] == '-') abbrev
[i
] = '_';
2413 if (abbrev
[i
] == '/') abbrev
[i
] = '_';
2416 hfri
[0].p_id
= &(a
->hf
);
2417 hfri
[1].p_id
= &(a
->hf_len
);
2419 hfri
[0].hfinfo
.name
= a
->name
;
2420 hfri
[0].hfinfo
.abbrev
= abbrev
;
2422 hfri
[1].hfinfo
.name
= "Length";
2423 hfri
[1].hfinfo
.abbrev
= wmem_strdup_printf(wmem_epan_scope(), "%s.len", abbrev
);
2424 hfri
[1].hfinfo
.blurb
= wmem_strdup_printf(wmem_epan_scope(), "%s Length", a
->name
);
2426 if (a
->type
== radius_integer
) {
2427 hfri
[0].hfinfo
.type
= FT_UINT32
;
2428 hfri
[0].hfinfo
.display
= BASE_DEC
;
2430 hfri
[2].p_id
= &(a
->hf_alt
);
2431 hfri
[2].hfinfo
.name
= wmem_strdup(wmem_epan_scope(), a
->name
);
2432 hfri
[2].hfinfo
.abbrev
= abbrev
;
2433 hfri
[2].hfinfo
.type
= FT_UINT64
;
2434 hfri
[2].hfinfo
.display
= BASE_DEC
;
2437 hfri
[0].hfinfo
.strings
= VALS(a
->vs
);
2441 } else if (a
->type
== radius_signed
) {
2442 hfri
[0].hfinfo
.type
= FT_INT32
;
2443 hfri
[0].hfinfo
.display
= BASE_DEC
;
2445 hfri
[2].p_id
= &(a
->hf_alt
);
2446 hfri
[2].hfinfo
.name
= wmem_strdup(wmem_epan_scope(), a
->name
);
2447 hfri
[2].hfinfo
.abbrev
= abbrev
;
2448 hfri
[2].hfinfo
.type
= FT_INT64
;
2449 hfri
[2].hfinfo
.display
= BASE_DEC
;
2452 hfri
[0].hfinfo
.strings
= VALS(a
->vs
);
2456 } else if (a
->type
== radius_string
) {
2457 hfri
[0].hfinfo
.type
= FT_STRING
;
2458 hfri
[0].hfinfo
.display
= BASE_NONE
;
2459 } else if (a
->type
== radius_octets
) {
2460 hfri
[0].hfinfo
.type
= FT_BYTES
;
2461 hfri
[0].hfinfo
.display
= BASE_NONE
;
2462 } else if (a
->type
== radius_ipaddr
) {
2463 hfri
[0].hfinfo
.type
= FT_IPv4
;
2464 hfri
[0].hfinfo
.display
= BASE_NONE
;
2465 } else if (a
->type
== radius_ipv6addr
) {
2466 hfri
[0].hfinfo
.type
= FT_IPv6
;
2467 hfri
[0].hfinfo
.display
= BASE_NONE
;
2468 } else if (a
->type
== radius_ipv6prefix
) {
2469 hfri
[0].hfinfo
.type
= FT_BYTES
;
2470 hfri
[0].hfinfo
.display
= BASE_NONE
;
2471 } else if (a
->type
== radius_ipxnet
) {
2472 hfri
[0].hfinfo
.type
= FT_IPXNET
;
2473 hfri
[0].hfinfo
.display
= BASE_NONE
;
2474 } else if (a
->type
== radius_date
) {
2475 hfri
[0].hfinfo
.type
= FT_ABSOLUTE_TIME
;
2476 hfri
[0].hfinfo
.display
= ABSOLUTE_TIME_LOCAL
;
2477 } else if (a
->type
== radius_abinary
) {
2478 hfri
[0].hfinfo
.type
= FT_BYTES
;
2479 hfri
[0].hfinfo
.display
= BASE_NONE
;
2480 } else if (a
->type
== radius_ifid
) {
2481 hfri
[0].hfinfo
.type
= FT_BYTES
;
2482 hfri
[0].hfinfo
.display
= BASE_NONE
;
2483 } else if (a
->type
== radius_combo_ip
) {
2484 hfri
[0].hfinfo
.type
= FT_IPv4
;
2485 hfri
[0].hfinfo
.display
= BASE_NONE
;
2487 hfri
[2].p_id
= &(a
->hf_alt
);
2488 hfri
[2].hfinfo
.name
= wmem_strdup(wmem_epan_scope(), a
->name
);
2489 hfri
[2].hfinfo
.abbrev
= wmem_strdup(wmem_epan_scope(), abbrev
);
2490 hfri
[2].hfinfo
.type
= FT_IPv6
;
2491 hfri
[2].hfinfo
.display
= BASE_NONE
;
2494 #if 0 /* Fix -Wduplicated-branches */
2495 } else if (a
->type
== radius_tlv
) {
2496 hfri
[0].hfinfo
.type
= FT_BYTES
;
2497 hfri
[0].hfinfo
.display
= BASE_NONE
;
2500 hfri
[0].hfinfo
.type
= FT_BYTES
;
2501 hfri
[0].hfinfo
.display
= BASE_NONE
;
2505 hfri
[len_hf
].p_id
= &(a
->hf_tag
);
2506 hfri
[len_hf
].hfinfo
.name
= "Tag";
2507 hfri
[len_hf
].hfinfo
.abbrev
= wmem_strdup_printf(wmem_epan_scope(), "%s.tag", abbrev
);
2508 hfri
[len_hf
].hfinfo
.blurb
= wmem_strdup_printf(wmem_epan_scope(), "%s Tag", a
->name
);
2509 hfri
[len_hf
].hfinfo
.type
= FT_UINT8
;
2510 hfri
[len_hf
].hfinfo
.display
= BASE_HEX
;
2514 if (a
->encrypt
!= 0) {
2516 * This attribute is encrypted, so create an
2517 * alternative field for the encrypted value.
2519 hfri
[len_hf
].p_id
= &(a
->hf_enc
);
2520 hfri
[len_hf
].hfinfo
.name
= wmem_strdup_printf(wmem_epan_scope(), "%s (encrypted)", a
->name
);
2521 hfri
[len_hf
].hfinfo
.abbrev
= wmem_strdup_printf(wmem_epan_scope(), "%s_encrypted", abbrev
);
2522 hfri
[len_hf
].hfinfo
.type
= FT_BYTES
;
2523 hfri
[len_hf
].hfinfo
.display
= BASE_NONE
;
2527 wmem_array_append(ri
->hf
, hfri
, len_hf
);
2528 wmem_array_append_one(ri
->ett
, ett
);
2530 if (a
->tlvs_by_id
) {
2531 g_hash_table_foreach(a
->tlvs_by_id
, register_attrs
, ri
);
2536 register_vendors(void *k _U_
, void *v
, void *p
)
2538 radius_vendor_info_t
*vnd
= (radius_vendor_info_t
*)v
;
2539 hfett_t
*ri
= (hfett_t
*)p
;
2540 value_string vnd_vs
;
2541 int *ett_p
= &(vnd
->ett
);
2543 vnd_vs
.value
= vnd
->code
;
2544 vnd_vs
.strptr
= vnd
->name
;
2546 wmem_array_append_one(ri
->vend_vs
, vnd_vs
);
2547 wmem_array_append_one(ri
->ett
, ett_p
);
2549 g_hash_table_foreach(vnd
->attrs_by_id
, register_attrs
, ri
);
2553 radius_register_avp_dissector(uint32_t vendor_id
, uint32_t _attribute_id
, radius_avp_dissector_t radius_avp_dissector
)
2555 radius_vendor_info_t
*vendor
;
2556 radius_attr_info_t
*dictionary_entry
;
2558 radius_attr_type_t attribute_id
;
2560 DISSECTOR_ASSERT(radius_avp_dissector
!= NULL
);
2561 memset(&attribute_id
, 0, sizeof(attribute_id
));
2562 attribute_id
.u8_code
[0] = _attribute_id
;
2565 vendor
= (radius_vendor_info_t
*)g_hash_table_lookup(dict
->vendors_by_id
, GUINT_TO_POINTER(vendor_id
));
2568 vendor
= g_new(radius_vendor_info_t
, 1);
2570 vendor
->name
= ws_strdup_printf("%s-%u",
2571 enterprises_lookup(vendor_id
, "Unknown"),
2573 vendor
->code
= vendor_id
;
2574 vendor
->attrs_by_id
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_radius_attr_info
);
2575 vendor
->ett
= no_vendor
.ett
;
2577 /* XXX: Default "standard" values: Should be parameters ? */
2578 vendor
->type_octets
= 1;
2579 vendor
->length_octets
= 1;
2580 vendor
->has_flags
= false;
2582 g_hash_table_insert(dict
->vendors_by_id
, GUINT_TO_POINTER(vendor
->code
), vendor
);
2583 g_hash_table_insert(dict
->vendors_by_name
, (void *)(vendor
->name
), vendor
);
2586 dictionary_entry
= (radius_attr_info_t
*)g_hash_table_lookup(vendor
->attrs_by_id
, GUINT_TO_POINTER(attribute_id
.value
));
2587 by_id
= vendor
->attrs_by_id
;
2589 dictionary_entry
= (radius_attr_info_t
*)g_hash_table_lookup(dict
->attrs_by_id
, GUINT_TO_POINTER(attribute_id
.value
));
2590 by_id
= dict
->attrs_by_id
;
2593 if (!dictionary_entry
) {
2594 dictionary_entry
= g_new(radius_attr_info_t
, 1);
2596 dictionary_entry
->name
= ws_strdup_printf("Unknown-Attribute-%u", attribute_id
.value
);
2597 dictionary_entry
->code
= attribute_id
;
2598 dictionary_entry
->encrypt
= 0;
2599 dictionary_entry
->type
= NULL
;
2600 dictionary_entry
->vs
= NULL
;
2601 dictionary_entry
->hf
= no_dictionary_entry
.hf
;
2602 dictionary_entry
->tagged
= false;
2603 dictionary_entry
->concat
= false;
2604 dictionary_entry
->hf_tag
= -1;
2605 dictionary_entry
->hf_len
= no_dictionary_entry
.hf_len
;
2606 dictionary_entry
->ett
= no_dictionary_entry
.ett
;
2607 dictionary_entry
->tlvs_by_id
= NULL
;
2609 g_hash_table_insert(by_id
, GUINT_TO_POINTER(dictionary_entry
->code
.value
), dictionary_entry
);
2612 dictionary_entry
->dissector
= radius_avp_dissector
;
2616 /* Discard and init any state we've saved */
2618 radius_init_protocol(void)
2620 module_t
*radius_module
= prefs_find_module("radius");
2621 pref_t
*alternate_port
;
2623 if (radius_module
) {
2624 /* Find alternate_port preference and mark it obsolete (thus hiding it from a user) */
2625 alternate_port
= prefs_find_preference(radius_module
, "alternate_port");
2626 if (! prefs_get_preference_obsolete(alternate_port
))
2627 prefs_set_preference_obsolete(alternate_port
);
2632 radius_shutdown(void)
2635 g_hash_table_destroy(dict
->attrs_by_id
);
2636 g_hash_table_destroy(dict
->attrs_by_name
);
2637 g_hash_table_destroy(dict
->vendors_by_id
);
2638 g_hash_table_destroy(dict
->vendors_by_name
);
2639 g_hash_table_destroy(dict
->tlvs_by_name
);
2645 _radius_load_dictionary(char* dir
)
2647 char *dict_err_str
= NULL
;
2649 if (!dir
|| test_for_directory(dir
) != EISDIR
) {
2653 radius_load_dictionary(dict
, dir
, "dictionary", &dict_err_str
);
2656 report_failure("radius: %s", dict_err_str
);
2657 g_free(dict_err_str
);
2662 register_radius_fields(const char *unused _U_
)
2664 hf_register_info base_hf
[] = {
2666 { "Request", "radius.req", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2667 "true if RADIUS request", HFILL
}},
2669 { "Response", "radius.rsp", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2670 "true if RADIUS response", HFILL
}},
2671 { &hf_radius_req_frame
,
2672 { "Request Frame", "radius.reqframe", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0,
2674 { &hf_radius_rsp_frame
,
2675 { "Response Frame", "radius.rspframe", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0,
2678 { "Time from request", "radius.time", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0,
2679 "Timedelta between Request and Response", HFILL
}},
2681 { "Code", "radius.code", FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &radius_pkt_type_codes_ext
, 0x0,
2684 { "Identifier", "radius.id", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2686 { &hf_radius_authenticator
,
2687 { "Authenticator", "radius.authenticator", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2689 { &hf_radius_authenticator_valid
,
2690 { "Valid Authenticator", "radius.authenticator.valid", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2691 "true if Authenticator is valid", HFILL
}},
2692 { &hf_radius_authenticator_invalid
,
2693 { "Invalid Authenticator", "radius.authenticator.invalid", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2694 "true if Authenticator is invalid", HFILL
}},
2695 { &hf_radius_message_authenticator_valid
,
2696 { "Valid Message-Authenticator", "radius.Message_Authenticator.valid", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2697 "true if Message-Authenticator is valid", HFILL
}},
2698 { &hf_radius_message_authenticator_invalid
,
2699 { "Invalid Message-Authenticator", "radius.Message_Authenticator.invalid", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
2700 "true if Message-Authenticator is invalid", HFILL
}},
2701 { &hf_radius_length
,
2702 { "Length", "radius.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2704 { &(no_dictionary_entry
.hf
),
2705 { "Unknown-Attribute", "radius.Unknown_Attribute", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2707 { &(no_dictionary_entry
.hf_len
),
2708 { "Unknown-Attribute Length", "radius.Unknown_Attribute.length", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2710 { &hf_radius_chap_password
,
2711 { "CHAP-Password", "radius.CHAP_Password", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2713 { &hf_radius_chap_ident
,
2714 { "CHAP Ident", "radius.CHAP_Ident", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2716 { &hf_radius_chap_string
,
2717 { "CHAP String", "radius.CHAP_String", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2719 { &hf_radius_framed_ip_address
,
2720 { "Framed-IP-Address", "radius.Framed-IP-Address", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
2722 { &hf_radius_login_ip_host
,
2723 { "Login-IP-Host", "radius.Login-IP-Host", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
2725 { &hf_radius_framed_ipx_network
,
2726 { "Framed-IPX-Network", "radius.Framed-IPX-Network", FT_IPXNET
, BASE_NONE
, NULL
, 0x0,
2728 { &hf_radius_cosine_vpi
,
2729 { "Cosine-VPI", "radius.Cosine-Vpi", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2731 { &hf_radius_cosine_vci
,
2732 { "Cosine-VCI", "radius.Cosine-Vci", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2735 { "Duplicate Message ID", "radius.dup", FT_UINT32
, BASE_DEC
, NULL
, 0x0,
2737 { &hf_radius_req_dup
,
2738 { "Duplicate Request Frame Number", "radius.req.dup", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
2740 { &hf_radius_rsp_dup
,
2741 { "Duplicate Response Frame Number", "radius.rsp.dup", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
2743 { &hf_radius_ascend_data_filter
,
2744 { "Ascend Data Filter", "radius.ascenddatafilter", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2746 { &hf_radius_ascend_data_filter_type
,
2747 { "Type", "radius.ascenddatafilter.type", FT_UINT8
, BASE_DEC
, VALS(ascenddf_filtertype
), 0x0,
2749 { &hf_radius_ascend_data_filter_filteror
,
2750 { "Filter or forward", "radius.ascenddatafilter.filteror", FT_UINT8
, BASE_DEC
, VALS(ascenddf_filteror
), 0x0,
2752 { &hf_radius_ascend_data_filter_inout
,
2753 { "Indirection", "radius.ascenddatafilter.inout", FT_UINT8
, BASE_DEC
, VALS(ascenddf_inout
), 0x0,
2755 { &hf_radius_ascend_data_filter_spare
,
2756 { "Spare", "radius.ascenddatafilter.spare", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2758 { &hf_radius_ascend_data_filter_src_ipv4
,
2759 { "Source IPv4 address", "radius.ascenddatafilter.src_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
2761 { &hf_radius_ascend_data_filter_dst_ipv4
,
2762 { "Destination IPv4 address", "radius.ascenddatafilter.dst_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
2764 { &hf_radius_ascend_data_filter_src_ipv6
,
2765 { "Source IPv6 address", "radius.ascenddatafilter.src_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
2767 { &hf_radius_ascend_data_filter_dst_ipv6
,
2768 { "Destination IPv6 address", "radius.ascenddatafilter.dst_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
2770 { &hf_radius_ascend_data_filter_src_ip_prefix
,
2771 { "Source IP prefix", "radius.ascenddatafilter.src_prefix_ip", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2773 { &hf_radius_ascend_data_filter_dst_ip_prefix
,
2774 { "Destination IP prefix", "radius.ascenddatafilter.dst_prefix_ip", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2776 { &hf_radius_ascend_data_filter_protocol
,
2777 { "Protocol", "radius.ascenddatafilter.protocol", FT_UINT8
, BASE_DEC
, VALS(ascenddf_proto
), 0x0,
2779 { &hf_radius_ascend_data_filter_established
,
2780 { "Established", "radius.ascenddatafilter.established", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2782 { &hf_radius_ascend_data_filter_src_port
,
2783 { "Source Port", "radius.ascenddatafilter.src_port", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2785 { &hf_radius_ascend_data_filter_dst_port
,
2786 { "Destination Port", "radius.ascenddatafilter.dst_port", FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2788 { &hf_radius_ascend_data_filter_src_port_qualifier
,
2789 { "Source Port Qualifier", "radius.ascenddatafilter.src_port_qualifier", FT_UINT8
, BASE_DEC
, VALS(ascenddf_portq
), 0x0,
2791 { &hf_radius_ascend_data_filter_dst_port_qualifier
,
2792 { "Destination Port Qualifier", "radius.ascenddatafilter.dst_port_qualifier", FT_UINT8
, BASE_DEC
, VALS(ascenddf_portq
), 0x0,
2794 { &hf_radius_ascend_data_filter_reserved
,
2795 { "Reserved", "radius.ascenddatafilter.reserved", FT_UINT16
, BASE_HEX
, NULL
, 0x0,
2797 { &hf_radius_vsa_fragment
,
2798 { "VSA fragment", "radius.vsa_fragment", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2800 { &hf_radius_eap_fragment
,
2801 { "EAP fragment", "radius.eap_fragment", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2804 { "AVP", "radius.avp", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2806 { &hf_radius_avp_length
,
2807 { "Length", "radius.avp.length", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2809 { &hf_radius_avp_type
,
2810 { "Type", "radius.avp.type", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2812 { &hf_radius_avp_vendor_id
,
2813 { "Vendor ID", "radius.avp.vendor_id", FT_UINT32
, BASE_ENTERPRISES
, STRINGS_ENTERPRISES
, 0x0,
2815 { &hf_radius_avp_vendor_type
,
2816 { "Type", "radius.avp.vendor_type", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2818 { &hf_radius_avp_vendor_len
,
2819 { "Length", "radius.avp.vendor_len", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2821 { &hf_radius_avp_extended_type
,
2822 { "Extended Type", "radius.avp.extended_type", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
2824 { &hf_radius_avp_extended_more
,
2825 { "Extended More", "radius.avp.extended_more", FT_BOOLEAN
, 8, NULL
, 0x80,
2827 { &hf_radius_egress_vlanid_tag
,
2828 { "Tag", "radius.egress_vlanid_tag", FT_UINT32
, BASE_HEX
, VALS(egress_vlan_tag_vals
), 0xFF000000,
2830 { &hf_radius_egress_vlanid_pad
,
2831 { "Pad", "radius.egress_vlanid_pad", FT_UINT32
, BASE_HEX
, NULL
, 0x00FFF000,
2833 { &hf_radius_egress_vlanid
,
2834 { "Vlan ID", "radius.egress_vlanid", FT_UINT32
, BASE_DEC
, NULL
, 0x00000FFF,
2836 { &hf_radius_egress_vlan_name_tag
,
2837 { "Tag", "radius.egress_vlan_name_tag", FT_UINT8
, BASE_HEX
, VALS(egress_vlan_tag_vals
), 0x0,
2839 { &hf_radius_egress_vlan_name
,
2840 { "Vlan Name", "radius.egress_vlan_name", FT_STRING
, BASE_NONE
, NULL
, 0x0,
2842 { &hf_radius_3gpp_ms_tmime_zone
,
2843 { "Timezone", "radius.3gpp_ms_tmime_zone", FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2850 &ett_radius_authenticator
,
2854 &(no_dictionary_entry
.ett
),
2858 static ei_register_info ei
[] = {
2860 &ei_radius_invalid_length
, { "radius.invalid_length", PI_MALFORMED
, PI_ERROR
, "Invalid length", EXPFILL
}},
2863 expert_module_t
*expert_radius
;
2867 ri
.hf
= wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info
));
2868 ri
.ett
= wmem_array_new(wmem_epan_scope(), sizeof(int *));
2869 ri
.vend_vs
= wmem_array_new(wmem_epan_scope(), sizeof(value_string
));
2871 wmem_array_append(ri
.hf
, base_hf
, array_length(base_hf
));
2872 wmem_array_append(ri
.ett
, base_ett
, array_length(base_ett
));
2875 dir
= get_datafile_path("radius");
2876 _radius_load_dictionary(dir
);
2878 dir
= get_persconffile_path("radius", false);
2879 _radius_load_dictionary(dir
);
2882 g_hash_table_foreach(dict
->attrs_by_id
, register_attrs
, &ri
);
2883 g_hash_table_foreach(dict
->vendors_by_id
, register_vendors
, &ri
);
2885 proto_register_field_array(proto_radius
, (hf_register_info
*)wmem_array_get_raw(ri
.hf
), wmem_array_get_count(ri
.hf
));
2886 proto_register_subtree_array((int **)wmem_array_get_raw(ri
.ett
), wmem_array_get_count(ri
.ett
));
2887 expert_radius
= expert_register_protocol(proto_radius
);
2888 expert_register_field_array(expert_radius
, ei
, array_length(ei
));
2891 * Handle attributes that have a special format.
2893 radius_register_avp_dissector(0, 3, dissect_chap_password
);
2894 radius_register_avp_dissector(0, 8, dissect_framed_ip_address
);
2895 radius_register_avp_dissector(0, 14, dissect_login_ip_host
);
2896 radius_register_avp_dissector(0, 23, dissect_framed_ipx_network
);
2897 radius_register_avp_dissector(0, 56, dissect_rfc4675_egress_vlanid
);
2898 radius_register_avp_dissector(0, 58, dissect_rfc4675_egress_vlan_name
);
2900 radius_register_avp_dissector(VENDOR_COSINE
, 5, dissect_cosine_vpvc
);
2903 * XXX - we should special-case Cisco attribute 252; see the comment in
2906 radius_register_avp_dissector(VENDOR_THE3GPP
, 1, dissect_radius_3gpp_imsi
);
2907 radius_register_avp_dissector(VENDOR_THE3GPP
, 23, dissect_radius_3gpp_ms_tmime_zone
);
2912 proto_register_radius(void)
2914 module_t
*radius_module
;
2916 proto_radius
= proto_register_protocol("RADIUS Protocol", "RADIUS", "radius");
2917 radius_handle
= register_dissector("radius", dissect_radius
, proto_radius
);
2918 register_init_routine(&radius_init_protocol
);
2919 register_shutdown_routine(radius_shutdown
);
2920 radius_module
= prefs_register_protocol(proto_radius
, NULL
);
2921 prefs_register_string_preference(radius_module
, "shared_secret", "Shared Secret",
2922 "Shared secret used to decode User Passwords and validate Accounting Request and Response Authenticators",
2924 prefs_register_bool_preference(radius_module
, "validate_authenticator", "Validate Authenticator and Message-Authenticator",
2925 "Whether to check or not if Authenticator and Message-Authenticator are correct. You need to define shared secret for this to work.",
2926 &validate_authenticator
);
2927 prefs_register_bool_preference(radius_module
, "show_length", "Show AVP Lengths",
2928 "Whether to add or not to the tree the AVP's payload length",
2931 * For now this preference allows supporting legacy Ascend AVPs and others
2932 * who might use these attribute types (not complying with IANA allocation).
2934 prefs_register_bool_preference(radius_module
, "disable_extended_attributes", "Disable extended attribute space (RFC 6929)",
2935 "Whether to interpret 241-246 as extended attributes according to RFC 6929",
2936 &disable_extended_attributes
);
2937 prefs_register_obsolete_preference(radius_module
, "request_ttl");
2939 radius_tap
= register_tap("radius");
2940 proto_register_prefix("radius", register_radius_fields
);
2942 dict
= g_new(radius_dictionary_t
, 1);
2944 * IDs map to names and vice versa. The attribute and vendor is stored
2945 * only once, but referenced by both name and ID mappings.
2946 * See also radius_dictionary_t in packet-radius.h
2948 dict
->attrs_by_id
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_radius_attr_info
);
2949 dict
->attrs_by_name
= g_hash_table_new(g_str_hash
, g_str_equal
);
2950 dict
->vendors_by_id
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_radius_vendor_info
);
2951 dict
->vendors_by_name
= g_hash_table_new(g_str_hash
, g_str_equal
);
2952 dict
->tlvs_by_name
= g_hash_table_new(g_str_hash
, g_str_equal
);
2954 radius_calls
= wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), radius_call_hash
, radius_call_equal
);
2956 register_rtd_table(proto_radius
, NULL
, RADIUS_CAT_NUM_TIMESTATS
, 1, radius_message_code
, radiusstat_packet
, NULL
);
2960 proto_reg_handoff_radius(void)
2962 eap_handle
= find_dissector_add_dependency("eap", proto_radius
);
2963 dissector_add_uint_range_with_preference("udp.port", DEFAULT_RADIUS_PORT_RANGE
, radius_handle
);
2967 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2972 * indent-tabs-mode: t
2975 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2976 * :indentSize=8:tabSize=8:noTabs=false: