| ## 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) |