blob: be7b549678ba81b147ad2124b4d0c5226533847a [file] [log] [blame]
## This file is part of Scapy
## See http://www.secdev.org/projects/scapy for more informations
## Copyright (C) Philippe Biondi <phil@secdev.org>
## Vincent Mauge <vmauge.nospam@nospam.gmail.com>
## This program is published under a GPLv2 license
"""
RADIUS (Remote Authentication Dial In User Service)
"""
import struct
import logging
import hashlib
import hmac
from scapy.compat import *
from scapy.packet import Packet, bind_layers
from scapy.fields import ByteField, ByteEnumField, IntField, StrLenField,\
XStrLenField, XStrFixedLenField, FieldLenField, PacketField,\
PacketListField, IPField, MultiEnumField
from scapy.layers.inet import UDP
from scapy.layers.eap import EAP
from scapy.config import conf
from scapy.error import Scapy_Exception
# https://www.iana.org/assignments/radius-types/radius-types.xhtml
_radius_attribute_types = {
1: "User-Name",
2: "User-Password",
3: "CHAP-Password",
4: "NAS-IP-Address",
5: "NAS-Port",
6: "Service-Type",
7: "Framed-Protocol",
8: "Framed-IP-Address",
9: "Framed-IP-Netmask",
10: "Framed-Routing",
11: "Filter-Id",
12: "Framed-MTU",
13: "Framed-Compression",
14: "Login-IP-Host",
15: "Login-Service",
16: "Login-TCP-Port",
17: "Unassigned",
18: "Reply-Message",
19: "Callback-Number",
20: "Callback-Id",
21: "Unassigned",
22: "Framed-Route",
23: "Framed-IPX-Network",
24: "State",
25: "Class",
26: "Vendor-Specific",
27: "Session-Timeout",
28: "Idle-Timeout",
29: "Termination-Action",
30: "Called-Station-Id",
31: "Calling-Station-Id",
32: "NAS-Identifier",
33: "Proxy-State",
34: "Login-LAT-Service",
35: "Login-LAT-Node",
36: "Login-LAT-Group",
37: "Framed-AppleTalk-Link",
38: "Framed-AppleTalk-Network",
39: "Framed-AppleTalk-Zone",
40: "Acct-Status-Type",
41: "Acct-Delay-Time",
42: "Acct-Input-Octets",
43: "Acct-Output-Octets",
44: "Acct-Session-Id",
45: "Acct-Authentic",
46: "Acct-Session-Time",
47: "Acct-Input-Packets",
48: "Acct-Output-Packets",
49: "Acct-Terminate-Cause",
50: "Acct-Multi-Session-Id",
51: "Acct-Link-Count",
52: "Acct-Input-Gigawords",
53: "Acct-Output-Gigawords",
54: "Unassigned",
55: "Event-Timestamp",
56: "Egress-VLANID",
57: "Ingress-Filters",
58: "Egress-VLAN-Name",
59: "User-Priority-Table",
60: "CHAP-Challenge",
61: "NAS-Port-Type",
62: "Port-Limit",
63: "Login-LAT-Port",
64: "Tunnel-Type",
65: "Tunnel-Medium-Type",
66: "Tunnel-Client-Endpoint",
67: "Tunnel-Server-Endpoint",
68: "Acct-Tunnel-Connection",
69: "Tunnel-Password",
70: "ARAP-Password",
71: "ARAP-Features",
72: "ARAP-Zone-Access",
73: "ARAP-Security",
74: "ARAP-Security-Data",
75: "Password-Retry",
76: "Prompt",
77: "Connect-Info",
78: "Configuration-Token",
79: "EAP-Message",
80: "Message-Authenticator",
81: "Tunnel-Private-Group-ID",
82: "Tunnel-Assignment-ID",
83: "Tunnel-Preference",
84: "ARAP-Challenge-Response",
85: "Acct-Interim-Interval",
86: "Acct-Tunnel-Packets-Lost",
87: "NAS-Port-Id",
88: "Framed-Pool",
89: "CUI",
90: "Tunnel-Client-Auth-ID",
91: "Tunnel-Server-Auth-ID",
92: "NAS-Filter-Rule",
93: "Unassigned",
94: "Originating-Line-Info",
95: "NAS-IPv6-Address",
96: "Framed-Interface-Id",
97: "Framed-IPv6-Prefix",
98: "Login-IPv6-Host",
99: "Framed-IPv6-Route",
100: "Framed-IPv6-Pool",
101: "Error-Cause",
102: "EAP-Key-Name",
103: "Digest-Response",
104: "Digest-Realm",
105: "Digest-Nonce",
106: "Digest-Response-Auth",
107: "Digest-Nextnonce",
108: "Digest-Method",
109: "Digest-URI",
110: "Digest-Qop",
111: "Digest-Algorithm",
112: "Digest-Entity-Body-Hash",
113: "Digest-CNonce",
114: "Digest-Nonce-Count",
115: "Digest-Username",
116: "Digest-Opaque",
117: "Digest-Auth-Param",
118: "Digest-AKA-Auts",
119: "Digest-Domain",
120: "Digest-Stale",
121: "Digest-HA1",
122: "SIP-AOR",
123: "Delegated-IPv6-Prefix",
124: "MIP6-Feature-Vector",
125: "MIP6-Home-Link-Prefix",
126: "Operator-Name",
127: "Location-Information",
128: "Location-Data",
129: "Basic-Location-Policy-Rules",
130: "Extended-Location-Policy-Rules",
131: "Location-Capable",
132: "Requested-Location-Info",
133: "Framed-Management-Protocol",
134: "Management-Transport-Protection",
135: "Management-Policy-Id",
136: "Management-Privilege-Level",
137: "PKM-SS-Cert",
138: "PKM-CA-Cert",
139: "PKM-Config-Settings",
140: "PKM-Cryptosuite-List",
141: "PKM-SAID",
142: "PKM-SA-Descriptor",
143: "PKM-Auth-Key",
144: "DS-Lite-Tunnel-Name",
145: "Mobile-Node-Identifier",
146: "Service-Selection",
147: "PMIP6-Home-LMA-IPv6-Address",
148: "PMIP6-Visited-LMA-IPv6-Address",
149: "PMIP6-Home-LMA-IPv4-Address",
150: "PMIP6-Visited-LMA-IPv4-Address",
151: "PMIP6-Home-HN-Prefix",
152: "PMIP6-Visited-HN-Prefix",
153: "PMIP6-Home-Interface-ID",
154: "PMIP6-Visited-Interface-ID",
155: "PMIP6-Home-IPv4-HoA",
156: "PMIP6-Visited-IPv4-HoA",
157: "PMIP6-Home-DHCP4-Server-Address",
158: "PMIP6-Visited-DHCP4-Server-Address",
159: "PMIP6-Home-DHCP6-Server-Address",
160: "PMIP6-Visited-DHCP6-Server-Address",
161: "PMIP6-Home-IPv4-Gateway",
162: "PMIP6-Visited-IPv4-Gateway",
163: "EAP-Lower-Layer",
164: "GSS-Acceptor-Service-Name",
165: "GSS-Acceptor-Host-Name",
166: "GSS-Acceptor-Service-Specifics",
167: "GSS-Acceptor-Realm-Name",
168: "Framed-IPv6-Address",
169: "DNS-Server-IPv6-Address",
170: "Route-IPv6-Information",
171: "Delegated-IPv6-Prefix-Pool",
172: "Stateful-IPv6-Address-Pool",
173: "IPv6-6rd-Configuration",
174: "Allowed-Called-Station-Id",
175: "EAP-Peer-Id",
176: "EAP-Server-Id",
177: "Mobility-Domain-Id",
178: "Preauth-Timeout",
179: "Network-Id-Name",
180: "EAPoL-Announcement",
181: "WLAN-HESSID",
182: "WLAN-Venue-Info",
183: "WLAN-Venue-Language",
184: "WLAN-Venue-Name",
185: "WLAN-Reason-Code",
186: "WLAN-Pairwise-Cipher",
187: "WLAN-Group-Cipher",
188: "WLAN-AKM-Suite",
189: "WLAN-Group-Mgmt-Cipher",
190: "WLAN-RF-Band",
191: "Unassigned",
}
class RadiusAttribute(Packet):
"""
Implements a RADIUS attribute (RFC 2865). Every specific RADIUS attribute
class should inherit from this one.
"""
name = "Radius Attribute"
fields_desc = [
ByteEnumField("type", 1, _radius_attribute_types),
FieldLenField("len", None, "value", "B",
adjust=lambda pkt, x: len(pkt.value) + 2),
StrLenField("value", "", length_from=lambda pkt: pkt.len - 2)
]
registered_attributes = {}
@classmethod
def register_variant(cls):
"""
Registers the RADIUS attributes defined in this module.
"""
if hasattr(cls, "val"):
cls.registered_attributes[cls.val] = cls
else:
cls.registered_attributes[cls.type.default] = cls
@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
"""
Returns the right RadiusAttribute class for the given data.
"""
if _pkt:
attr_type = orb(_pkt[0])
return cls.registered_attributes.get(attr_type, cls)
return cls
def haslayer(self, cls):
if cls == "RadiusAttribute":
if isinstance(self, RadiusAttribute):
return True
elif issubclass(cls, RadiusAttribute):
if isinstance(self, cls):
return True
return super(RadiusAttribute, self).haslayer(cls)
def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt):
return super(RadiusAttribute, self).getlayer(cls, nb=nb, _track=_track,
_subclass=True, **flt)
def post_build(self, p, pay):
length = self.len
if length is None:
length = len(p)
p = p[:1] + struct.pack("!B", length) + p[2:]
return p
class _SpecificRadiusAttr(RadiusAttribute):
"""
Class from which every "specific" RADIUS attribute defined in this module
inherits.
"""
__slots__ = ["val"]
def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields):
super(_SpecificRadiusAttr, self).__init__(
_pkt,
post_transform,
_internal,
_underlayer
)
self.fields["type"] = self.val
name_parts = self.__class__.__name__.split('RadiusAttr_')
if len(name_parts) < 2:
raise Scapy_Exception(
"Invalid class name: {}".format(self.__class__.__name__)
)
self.name = name_parts[1].replace('_', '-')
#
# RADIUS attributes which values are 4 bytes integers
#
class _RadiusAttrIntValue(_SpecificRadiusAttr):
"""
Implements a RADIUS attribute which value field is 4 bytes long integer.
"""
fields_desc = [
ByteEnumField("type", 5, _radius_attribute_types),
ByteField("len", 6),
IntField("value", 0)
]
class RadiusAttr_NAS_Port(_RadiusAttrIntValue):
"""RFC 2865"""
val = 5
class RadiusAttr_Framed_MTU(_RadiusAttrIntValue):
"""RFC 2865"""
val = 12
class RadiusAttr_Login_TCP_Port(_RadiusAttrIntValue):
"""RFC 2865"""
val = 16
class RadiusAttr_Session_Timeout(_RadiusAttrIntValue):
"""RFC 2865"""
val = 27
class RadiusAttr_Idle_Timeout(_RadiusAttrIntValue):
"""RFC 2865"""
val = 28
class RadiusAttr_Framed_AppleTalk_Link(_RadiusAttrIntValue):
"""RFC 2865"""
val = 37
class RadiusAttr_Framed_AppleTalk_Network(_RadiusAttrIntValue):
"""RFC 2865"""
val = 38
class RadiusAttr_Acct_Delay_Time(_RadiusAttrIntValue):
"""RFC 2866"""
val = 41
class RadiusAttr_Acct_Input_Octets(_RadiusAttrIntValue):
"""RFC 2866"""
val = 42
class RadiusAttr_Acct_Output_Octets(_RadiusAttrIntValue):
"""RFC 2866"""
val = 43
class RadiusAttr_Acct_Session_Time(_RadiusAttrIntValue):
"""RFC 2866"""
val = 46
class RadiusAttr_Acct_Input_Packets(_RadiusAttrIntValue):
"""RFC 2866"""
val = 47
class RadiusAttr_Acct_Output_Packets(_RadiusAttrIntValue):
"""RFC 2866"""
val = 48
class RadiusAttr_Acct_Link_Count(_RadiusAttrIntValue):
"""RFC 2866"""
val = 51
class RadiusAttr_Acct_Input_Gigawords(_RadiusAttrIntValue):
"""RFC 2869"""
val = 52
class RadiusAttr_Acct_Output_Gigawords(_RadiusAttrIntValue):
"""RFC 2869"""
val = 53
class RadiusAttr_Egress_VLANID(_RadiusAttrIntValue):
"""RFC 4675"""
val = 56
class RadiusAttr_Port_Limit(_RadiusAttrIntValue):
"""RFC 2865"""
val = 62
class RadiusAttr_ARAP_Security(_RadiusAttrIntValue):
"""RFC 2869"""
val = 73
class RadiusAttr_Password_Retry(_RadiusAttrIntValue):
"""RFC 2869"""
val = 75
class RadiusAttr_Tunnel_Preference(_RadiusAttrIntValue):
"""RFC 2868"""
val = 83
class RadiusAttr_Acct_Interim_Interval(_RadiusAttrIntValue):
"""RFC 2869"""
val = 85
class RadiusAttr_Acct_Tunnel_Packets_Lost(_RadiusAttrIntValue):
"""RFC 2867"""
val = 86
class RadiusAttr_Management_Privilege_Level(_RadiusAttrIntValue):
"""RFC 5607"""
val = 136
class RadiusAttr_Mobility_Domain_Id(_RadiusAttrIntValue):
"""RFC 7268"""
val = 177
class RadiusAttr_Preauth_Timeout(_RadiusAttrIntValue):
"""RFC 7268"""
val = 178
class RadiusAttr_WLAN_Venue_Info(_RadiusAttrIntValue):
"""RFC 7268"""
val = 182
class RadiusAttr_WLAN_Reason_Code(_RadiusAttrIntValue):
"""RFC 7268"""
val = 185
class RadiusAttr_WLAN_Pairwise_Cipher(_RadiusAttrIntValue):
"""RFC 7268"""
val = 186
class RadiusAttr_WLAN_Group_Cipher(_RadiusAttrIntValue):
"""RFC 7268"""
val = 187
class RadiusAttr_WLAN_AKM_Suite(_RadiusAttrIntValue):
"""RFC 7268"""
val = 188
class RadiusAttr_WLAN_Group_Mgmt_Cipher(_RadiusAttrIntValue):
"""RFC 7268"""
val = 189
class RadiusAttr_WLAN_RF_Band(_RadiusAttrIntValue):
"""RFC 7268"""
val = 190
#
# RADIUS attributes which values are string (displayed as hex)
#
class _RadiusAttrHexStringVal(_SpecificRadiusAttr):
"""
Implements a RADIUS attribute which value field is a string that will be
as a hex string.
"""
__slots__ = ["val"]
def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields):
super(_RadiusAttrHexStringVal, self).__init__(
_pkt,
post_transform,
_internal,
_underlayer
)
self.fields["type"] = self.val
name_parts = self.__class__.__name__.split('RadiusAttr_')
if len(name_parts) < 2:
raise Scapy_Exception(
"Invalid class name: {}".format(self.__class__.__name__)
)
self.name = name_parts[1].replace('_', '-')
fields_desc = [
ByteEnumField("type", 24, _radius_attribute_types),
FieldLenField(
"len",
None,
"value",
"B",
adjust=lambda p, x: len(p.value) + 2
),
XStrLenField("value", "", length_from=lambda p: p.len - 2 if p.len else 0)
]
class RadiusAttr_State(_RadiusAttrHexStringVal):
"""RFC 2865"""
val = 24
def prepare_packed_data(radius_packet, packed_req_authenticator):
"""
Pack RADIUS data prior computing the authentication MAC
"""
packed_hdr = struct.pack("!B", radius_packet.code)
packed_hdr += struct.pack("!B", radius_packet.id)
packed_hdr += struct.pack("!H", radius_packet.len)
packed_attrs = b''
for attr in radius_packet.attributes:
packed_attrs += raw(attr)
return packed_hdr + packed_req_authenticator + packed_attrs
class RadiusAttr_Message_Authenticator(_RadiusAttrHexStringVal):
"""RFC 2869"""
val = 80
fields_desc = [
ByteEnumField("type", 24, _radius_attribute_types),
FieldLenField(
"len",
18,
"value",
"B",
),
XStrFixedLenField("value", "\x00" * 16, length=16)
]
@staticmethod
def compute_message_authenticator(radius_packet, packed_req_authenticator,
shared_secret):
"""
Computes the "Message-Authenticator" of a given RADIUS packet.
"""
data = prepare_packed_data(radius_packet, packed_req_authenticator)
radius_hmac = hmac.new(shared_secret, data, hashlib.md5)
return radius_hmac.digest()
#
# RADIUS attributes which values are IPv4 prefixes
#
class _RadiusAttrIPv4AddrVal(RadiusAttribute):
"""
Implements a RADIUS attribute which value field is an IPv4 address.
"""
__slots__ = ["val"]
fields_desc = [
ByteEnumField("type", 4, _radius_attribute_types),
ByteField("len", 6),
IPField("value", "0.0.0.0")
]
class RadiusAttr_NAS_IP_Address(_RadiusAttrIPv4AddrVal):
"""RFC 2865"""
val = 4
class RadiusAttr_Framed_IP_Address(_RadiusAttrIPv4AddrVal):
"""RFC 2865"""
val = 8
class RadiusAttr_Framed_IP_Netmask(_RadiusAttrIPv4AddrVal):
"""RFC 2865"""
val = 9
class RadiusAttr_Login_IP_Host(_RadiusAttrIPv4AddrVal):
"""RFC 2865"""
val = 14
class RadiusAttr_Framed_IPX_Network(_RadiusAttrIPv4AddrVal):
"""RFC 2865"""
val = 23
class RadiusAttr_PMIP6_Home_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 149
class RadiusAttr_PMIP6_Visited_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 150
class RadiusAttr_PMIP6_Home_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 157
class RadiusAttr_PMIP6_Visited_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 158
class RadiusAttr_PMIP6_Home_IPv4_Gateway(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 161
class RadiusAttr_PMIP6_Visited_IPv4_Gateway(_RadiusAttrIPv4AddrVal):
"""RFC 6572"""
val = 162
# See IANA registry "RADIUS Types"
_radius_attrs_values = {
# Service-Type
6:
{
1: "Login",
2: "Framed",
3: "Callback Login",
4: "Callback Framed",
5: "Outbound",
6: "Administrative",
7: "NAS Prompt",
8: "Authenticate Only",
9: "Callback NAS Prompt",
10: "Call Check",
11: "Callback Administrative",
12: "Voice",
13: "Fax",
14: "Modem Relay",
15: "IAPP-Register",
16: "IAPP-AP-Check",
17: "Authorize Only",
18: "Framed-Management",
19: "Additional-Authorization"
},
# Framed-Protocol
7:
{
1: "PPP",
2: "SLIP",
3: "AppleTalk Remote Access Protocol (ARAP)",
4: "Gandalf proprietary SingleLink/MultiLink protocol",
5: "Xylogics proprietary IPX/SLIP",
6: "X.75 Synchronous",
7: "GPRS PDP Context"
},
# Framed-Routing
10:
{
0: "None",
1: "Send routing packets",
2: "Listen for routing packets",
3: "Send and Listen"
},
# Framed-Compression
13:
{
0: "None",
1: "VJ TCP/IP header compression",
2: "IPX header compression",
3: "Stac-LZS compression"
},
# Login-Service
15:
{
0: "Telnet",
1: "Rlogin",
2: "TCP Clear",
3: "PortMaster (proprietary)",
4: "LAT",
5: "X25-PAD",
6: "X25-T3POS",
7: "Unassigned",
8: "TCP Clear Quiet (suppresses any NAS-generated connect string)"
},
# Termination-Action
29:
{
0: "Default",
1: "RADIUS-Request"
},
# Acct-Status-Type
40:
{
1: "Start",
2: "Stop",
3: "Interim-Update",
4: "Unassigned",
5: "Unassigned",
6: "Unassigned",
7: "Accounting-On",
8: "Accounting-Off",
9: "Tunnel-Start",
10: "Tunnel-Stop",
11: "Tunnel-Reject",
12: "Tunnel-Link-Start",
13: "Tunnel-Link-Stop",
14: "Tunnel-Link-Reject",
15: "Failed"
},
# Acct-Authentic
45:
{
1: "RADIUS",
2: "Local",
3: "Remote",
4: "Diameter"
},
# Acct-Terminate-Cause
49:
{
1: "User Request",
2: "Lost Carrier",
3: "Lost Service",
4: "Idle Timeout",
5: "Session Timeout",
6: "Admin Reset",
7: "Admin Reboot",
8: "Port Error",
9: "NAS Error",
10: "NAS Request",
11: "NAS Reboot",
12: "Port Unneeded",
13: "Port Preempted",
14: "Port Suspended",
15: "Service Unavailable",
16: "Callback",
17: "User Error",
18: "Host Request",
19: "Supplicant Restart",
20: "Reauthentication Failure",
21: "Port Reinitialized",
22: "Port Administratively Disabled",
23: "Lost Power",
},
# NAS-Port-Type
61:
{
0: "Async",
1: "Sync",
2: "ISDN Sync",
3: "ISDN Async V.120",
4: "ISDN Async V.110",
5: "Virtual",
6: "PIAFS",
7: "HDLC Clear Channel",
8: "X.25",
9: "X.75",
10: "G.3 Fax",
11: "SDSL - Symmetric DSL",
12: "ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation",
13: "ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone",
14: "IDSL - ISDN Digital Subscriber Line",
15: "Ethernet",
16: "xDSL - Digital Subscriber Line of unknown type",
17: "Cable",
18: "Wireles - Other",
19: "Wireless - IEEE 802.11",
20: "Token-Ring",
21: "FDDI",
22: "Wireless - CDMA2000",
23: "Wireless - UMTS",
24: "Wireless - 1X-EV",
25: "IAPP",
26: "FTTP - Fiber to the Premises",
27: "Wireless - IEEE 802.16",
28: "Wireless - IEEE 802.20",
29: "Wireless - IEEE 802.22",
30: "PPPoA - PPP over ATM",
31: "PPPoEoA - PPP over Ethernet over ATM",
32: "PPPoEoE - PPP over Ethernet over Ethernet",
33: "PPPoEoVLAN - PPP over Ethernet over VLAN",
34: "PPPoEoQinQ - PPP over Ethernet over IEEE 802.1QinQ",
35: "xPON - Passive Optical Network",
36: "Wireless - XGP",
37: "WiMAX Pre-Release 8 IWK Function",
38: "WIMAX-WIFI-IWK: WiMAX WIFI Interworking",
39: "WIMAX-SFF: Signaling Forwarding Function for LTE/3GPP2",
40: "WIMAX-HA-LMA: WiMAX HA and or LMA function",
41: "WIMAX-DHCP: WIMAX DCHP service",
42: "WIMAX-LBS: WiMAX location based service",
43: "WIMAX-WVS: WiMAX voice service"
},
# Tunnel-Type
64:
{
1: "Point-to-Point Tunneling Protocol (PPTP)",
2: "Layer Two Forwarding (L2F)",
3: "Layer Two Tunneling Protocol (L2TP)",
4: "Ascend Tunnel Management Protocol (ATMP)",
5: "Virtual Tunneling Protocol (VTP)",
6: "IP Authentication Header in the Tunnel-mode (AH)",
7: "IP-in-IP Encapsulation (IP-IP)",
8: "Minimal IP-in-IP Encapsulation (MIN-IP-IP)",
9: "IP Encapsulating Security Payload in the Tunnel-mode (ESP)",
10: "Generic Route Encapsulation (GRE)",
11: "Bay Dial Virtual Services (DVS)",
12: "IP-in-IP Tunneling",
13: "Virtual LANs (VLAN)"
},
# Tunnel-Medium-Type
65:
{
1: "IPv4 (IP version 4)",
2: "IPv6 (IP version 6)",
3: "NSAP",
4: "HDLC (8-bit multidrop)",
5: "BBN 1822",
6: "802",
7: "E.163 (POTS)",
8: "E.164 (SMDS, Frame Relay, ATM)",
9: "F.69 (Telex)",
10: "X.121 (X.25, Frame Relay)",
11: "IPX",
12: "Appletalk",
13: "Decnet IV",
14: "Banyan Vine",
15: "E.164 with NSAP format subaddress"
},
# ARAP-Zone-Access
72:
{
1: "Only allow access to default zone",
2: "Use zone filter inclusively",
3: "Not used",
4: "Use zone filter exclusively"
},
# Prompt
76:
{
0: "No Echo",
1: "Echo"
},
# Error-Cause Attribute
101:
{
201: "Residual Session Context Removed",
202: "Invalid EAP Packet (Ignored)",
401: "Unsupported Attribute",
402: "Missing Attribute",
403: "NAS Identification Mismatch",
404: "Invalid Request",
405: "Unsupported Service",
406: "Unsupported Extension",
407: "Invalid Attribute Value",
501: "Administratively Prohibited",
502: "Request Not Routable (Proxy)",
503: "Session Context Not Found",
504: "Session Context Not Removable",
505: "Other Proxy Processing Error",
506: "Resources Unavailable",
507: "Request Initiated",
508: "Multiple Session Selection Unsupported",
509: "Location-Info-Required",
601: "Response Too Big"
},
# Operator Namespace Identifier - Attribute 126
126:
{
0x30: "TADIG",
0x31: "REALM",
0x32: "E212",
0x33: "ICC",
0xFF: "Reserved"
},
# Basic-Location-Policy-Rules
129:
{
0: "Retransmission allowed",
},
# Location-Capable
131:
{
1: "CIVIC_LOCATION",
2: "GEO_LOCATION",
4: "USERS_LOCATION",
8: "NAS_LOCATION"
},
# Framed-Management-Protocol
133:
{
1: "SNMP",
2: "Web-based",
3: "NETCONF",
4: "FTP",
5: "TFTP",
6: "SFTP",
7: "RCP",
8: "SCP"
},
# Management-Transport-Protection
134:
{
1: "No-Protection",
2: "Integrity-Protection",
3: "Integrity-Confidentiality-Protection",
},
}
class _RadiusAttrIntEnumVal(_SpecificRadiusAttr):
"""
Implements a RADIUS attribute which value field is 4 bytes long integer.
"""
__slots__ = ["val"]
fields_desc = [
ByteEnumField("type", 6, _radius_attribute_types),
ByteField("len", 6),
MultiEnumField(
"value",
0,
_radius_attrs_values,
depends_on=lambda p: p.type,
fmt="I"
)
]
class RadiusAttr_Service_Type(_RadiusAttrIntEnumVal):
"""RFC 2865"""
val = 6
class RadiusAttr_Framed_Protocol(_RadiusAttrIntEnumVal):
"""RFC 2865"""
val = 7
class RadiusAttr_NAS_Port_Type(_RadiusAttrIntEnumVal):
"""RFC 2865"""
val = 61
class _EAPPacketField(PacketField):
"""
Handles EAP-Message attribute value (the actual EAP packet).
"""
def m2i(self, pkt, m):
ret = None
eap_packet_len = struct.unpack("!H", m[2:4])[0]
if eap_packet_len < 254:
# If the EAP packet has not been fragmented, build a Scapy EAP
# packet from the data.
ret = EAP(m)
else:
ret = conf.raw_layer(m)
return ret
class RadiusAttr_EAP_Message(RadiusAttribute):
"""
Implements the "EAP-Message" attribute (RFC 3579).
"""
name = "EAP-Message"
fields_desc = [
ByteEnumField("type", 79, _radius_attribute_types),
FieldLenField(
"len",
None,
"value",
"B",
adjust=lambda pkt, x: len(pkt.value) + 2
),
_EAPPacketField("value", "", EAP)
]
class RadiusAttr_Vendor_Specific(RadiusAttribute):
"""
Implements the "Vendor-Specific" attribute, as described in RFC 2865.
"""
name = "Vendor-Specific"
fields_desc = [
ByteEnumField("type", 26, _radius_attribute_types),
FieldLenField(
"len",
None,
"value",
"B",
adjust=lambda pkt, x: len(pkt.value) + 8
),
IntField("vendor_id", 0),
ByteField("vendor_type", 0),
FieldLenField(
"vendor_len",
None,
"value",
"B",
adjust=lambda p, x: len(p.value) + 2
),
StrLenField("value", "", length_from=lambda p: p.vendor_len - 2)
]
class _RADIUSAttrPacketListField(PacketListField):
"""
PacketListField handling a list of RADIUS attributes.
"""
def getfield(self, pkt, s):
lst = []
length = None
ret = ""
if self.length_from is not None:
length = self.length_from(pkt)
if length is not None:
remain, ret = s[:length], s[length:]
while remain:
attr_len = orb(remain[1])
current = remain[:attr_len]
remain = remain[attr_len:]
packet = self.m2i(pkt, current)
lst.append(packet)
return remain + ret, lst
# See IANA RADIUS Packet Type Codes registry
_packet_codes = {
1: "Access-Request",
2: "Access-Accept",
3: "Access-Reject",
4: "Accounting-Request",
5: "Accounting-Response",
6: "Accounting-Status (now Interim Accounting)",
7: "Password-Request",
8: "Password-Ack",
9: "Password-Reject",
10: "Accounting-Message",
11: "Access-Challenge",
12: "Status-Server (experimental)",
13: "Status-Client (experimental)",
21: "Resource-Free-Request",
22: "Resource-Free-Response",
23: "Resource-Query-Request",
24: "Resource-Query-Response",
25: "Alternate-Resource-Reclaim-Request",
26: "NAS-Reboot-Request",
27: "NAS-Reboot-Response",
28: "Reserved",
29: "Next-Passcode",
30: "New-Pin",
31: "Terminate-Session",
32: "Password-Expired",
33: "Event-Request",
34: "Event-Response",
40: "Disconnect-Request",
41: "Disconnect-ACK",
42: "Disconnect-NAK",
43: "CoA-Request",
44: "CoA-ACK",
45: "CoA-NAK",
50: "IP-Address-Allocate",
51: "IP-Address-Release",
52: "Protocol-Error",
250: "Experimental Use",
251: "Experimental Use",
252: "Experimental Use",
253: "Experimental Use",
254: "Reserved",
255: "Reserved"
}
class Radius(Packet):
"""
Implements a RADIUS packet (RFC 2865).
"""
name = "RADIUS"
fields_desc = [
ByteEnumField("code", 1, _packet_codes),
ByteField("id", 0),
FieldLenField(
"len",
None,
"attributes",
"H",
adjust=lambda pkt, x: len(pkt.attributes) + 20
),
XStrFixedLenField("authenticator", "", 16),
_RADIUSAttrPacketListField(
"attributes",
[],
RadiusAttribute,
length_from=lambda pkt: pkt.len - 20
)
]
def compute_authenticator(self, packed_request_auth, shared_secret):
"""
Computes the authenticator field (RFC 2865 - Section 3)
"""
data = prepare_packed_data(self, packed_request_auth)
radius_mac = hashlib.md5(data + shared_secret)
return radius_mac.digest()
def post_build(self, p, pay):
p += pay
length = self.len
if length is None:
length = len(p)
p = p[:2] + struct.pack("!H", length) + p[4:]
return p
bind_layers(UDP, Radius, sport=1812)
bind_layers(UDP, Radius, dport=1812)
bind_layers(UDP, Radius, sport=1813)
bind_layers(UDP, Radius, dport=1813)