Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unknown attributes breaking packet init #107

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions pyrad/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ def _PktEncodeTlv(self, tlv_key, tlv_value):
def _PktEncodeAttributes(self):
result = six.b('')
for (code, datalst) in self.items():
if self.dict.attributes[self._DecodeKey(code)].type == 'tlv':
if self._PktIsTlvAttribute(code):
result += self._PktEncodeTlv(code, datalst)
else:
for data in datalst:
Expand All @@ -472,7 +472,7 @@ def _PktDecodeVendorAttribute(self, data):
(vendor, type, length) = struct.unpack('!LBB', data[:6])[0:3]

try:
if self.dict.attributes[self._DecodeKey((vendor, type))].type == 'tlv':
if self._PktIsTlvAttribute((vendor, type)):
self._PktDecodeTlvAttribute((vendor, type), data[6:length + 4])
tlvs = [] # tlv is added to the packet inside _PktDecodeTlvAttribute
else:
Expand All @@ -499,6 +499,10 @@ def _PktDecodeTlvAttribute(self, code, data):
sub_attributes.setdefault(type, []).append(data[loc+2:loc+length])
loc += length

def _PktIsTlvAttribute(self, code):
attr = self.dict.attributes.get(self._DecodeKey(code))
return (attr is not None and attr.type == 'tlv')

def DecodePacket(self, packet):
"""Initialize the object from raw packet data. Decode a packet as
received from the network and decode it.
Expand Down Expand Up @@ -538,7 +542,6 @@ def DecodePacket(self, packet):
# POST: Message Authenticator AVP is present.
self.message_authenticator = True
self.setdefault(key, []).append(value)

elif self.dict.attributes[self._DecodeKey(key)].type == 'tlv':
self._PktDecodeTlvAttribute(key,value)
else:
Expand Down
146 changes: 146 additions & 0 deletions pyrad/tests/data/realistic
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# A realistic dictfile based on actual RADIUS accounting fields
ATTRIBUTE User-Name 1 string
ATTRIBUTE User-Password 2 string
ATTRIBUTE CHAP-Password 3 string
ATTRIBUTE NAS-IP-Address 4 ipaddr
ATTRIBUTE NAS-Port 5 integer
ATTRIBUTE Service-Type 6 integer
VALUE Service-Type Login-User 1
VALUE Service-Type Framed-User 2
VALUE Service-Type Callback-Login-User 3
VALUE Service-Type Callback-Framed-User 4
VALUE Service-Type Outbound-User 5
VALUE Service-Type Administrative-User 6
VALUE Service-Type NAS-Prompt-User 7
VALUE Service-Type Authenticate-Only 8
VALUE Service-Type Callback-NAS-Prompt 9
VALUE Service-Type Call-Check 10
VALUE Service-Type Callback-Administrative 11
ATTRIBUTE Framed-Protocol 7 integer
VALUE Framed-Protocol Login-User 1
VALUE Framed-Protocol Framed-User 2
VALUE Framed-Protocol Callback-Login-User 3
VALUE Framed-Protocol Callback-Framed-User 4
VALUE Framed-Protocol Outbound-User 5
VALUE Framed-Protocol Administrative-User 6
VALUE Framed-Protocol NAS-Prompt-User 7
VALUE Framed-Protocol Authenticate-Only 8
VALUE Framed-Protocol Callback-NAS-Prompt 9
VALUE Framed-Protocol Call-Check 10
VALUE Framed-Protocol Callback-Administrative 11
ATTRIBUTE Framed-IP-Address 8 ipaddr
ATTRIBUTE Framed-IP-Netmask 9 ipaddr
ATTRIBUTE Framed-Routing 10 integer
ATTRIBUTE Filter-ID 11 string
ATTRIBUTE Framed-MTU 12 integer
ATTRIBUTE Framed-Compression 13 integer
ATTRIBUTE Login-IP-Host 14 ipaddr
ATTRIBUTE Login-Service 15 integer
ATTRIBUTE Login-TCP-Port 16 integer
ATTRIBUTE Reply-Message 18 string
ATTRIBUTE Callback-Number 19 string
ATTRIBUTE Callback-Id 20 string
ATTRIBUTE Framed-Route 22 string
ATTRIBUTE Framed-IPX-Network 23 integer
ATTRIBUTE State 24 string
ATTRIBUTE Class 25 string
ATTRIBUTE Vendor-Specific 26 string
ATTRIBUTE Session-Timeout 27 integer
ATTRIBUTE Idle-Timeout 28 integer
ATTRIBUTE Termination-Action 29 integer
ATTRIBUTE Called-Station-Id 30 string
ATTRIBUTE Calling-Station-Id 31 string
ATTRIBUTE NAS-Identifier 32 string
ATTRIBUTE Proxy-State 33 string
ATTRIBUTE Login-LAT-Service 34 string
ATTRIBUTE Login-LAT-Node 35 string
ATTRIBUTE Login-LAT-Group 36 string
ATTRIBUTE Framed-AppleTalk-Link 37 integer
ATTRIBUTE Framed-AppleTalk-Network 38 integer
ATTRIBUTE Framed-AppleTalk-Zone 39 string
ATTRIBUTE Acct-Status-Type 40 integer
VALUE Acct-Status-Type Start 1
VALUE Acct-Status-Type Stop 2
VALUE Acct-Status-Type Interim-Update 3
VALUE Acct-Status-Type Accounting-On 7
VALUE Acct-Status-Type Accounting-Off 8
VALUE Acct-Status-Type Failed 15
ATTRIBUTE Acct-Delay-Time 41 integer
ATTRIBUTE Acct-Input-Octets 42 integer
ATTRIBUTE Acct-Output-Octets 43 integer
ATTRIBUTE Acct-Session-Id 44 string
ATTRIBUTE Acct-Authentic 45 integer
VALUE Acct-Authentic RADIUS 1
VALUE Acct-Authentic Local 2
VALUE Acct-Authentic Remote 3
VALUE Acct-Authentic Diameter 4
ATTRIBUTE Acct-Session-Time 46 integer
ATTRIBUTE Acct-Input-Packets 47 integer
ATTRIBUTE Acct-Output-Packets 48 integer
ATTRIBUTE Acct-Terminate-Cause 49 integer
VALUE Acct-Terminate-Cause User-Request 1
VALUE Acct-Terminate-Cause Lost-Carrier 2
VALUE Acct-Terminate-Cause Lost-Service 3
VALUE Acct-Terminate-Cause Idle-Timeout 4
VALUE Acct-Terminate-Cause Session-Timeout 5
VALUE Acct-Terminate-Cause Admin-Reset 6
VALUE Acct-Terminate-Cause Admin-Reboot 7
VALUE Acct-Terminate-Cause Port-Error 8
VALUE Acct-Terminate-Cause NAS-Error 9
VALUE Acct-Terminate-Cause NAS-Request 10
VALUE Acct-Terminate-Cause NAS-Reboot 11
VALUE Acct-Terminate-Cause Port-Unneeded 12
VALUE Acct-Terminate-Cause Port-Preempted 13
VALUE Acct-Terminate-Cause Port-Suspended 14
VALUE Acct-Terminate-Cause Service-Unavailable 15
VALUE Acct-Terminate-Cause Callback 16
VALUE Acct-Terminate-Cause User-Error 17
VALUE Acct-Terminate-Cause Host-Request 18
ATTRIBUTE Acct-Multi-Session-Id 50 string
ATTRIBUTE Acct-Link-Count 51 integer
ATTRIBUTE Acct-Input-Gigawords 52 integer
ATTRIBUTE Acct-Output-Gigawords 53 integer
ATTRIBUTE Event-Timestamp 55 date
ATTRIBUTE NAS-Port-Type 61 integer
VALUE NAS-Port-Type Async 0
VALUE NAS-Port-Type Sync 1
VALUE NAS-Port-Type ISDN 2
VALUE NAS-Port-Type ISDN-V120 3
VALUE NAS-Port-Type ISDN-V110 4
VALUE NAS-Port-Type Virtual 5
VALUE NAS-Port-Type PIAFS 6
VALUE NAS-Port-Type HDLC-Clear-Channel 7
VALUE NAS-Port-Type X.25 8
VALUE NAS-Port-Type X.75 9
VALUE NAS-Port-Type G.3-Fax 10
VALUE NAS-Port-Type SDSL 11
VALUE NAS-Port-Type ADSL-CAP 12
VALUE NAS-Port-Type ADSL-DMT 13
VALUE NAS-Port-Type IDSL 14
VALUE NAS-Port-Type Ethernet 15
VALUE NAS-Port-Type xDSL 16
VALUE NAS-Port-Type Cable 17
VALUE NAS-Port-Type Wireless-Other 18
VALUE NAS-Port-Type Wireless-802.11 19
ATTRIBUTE Port-Limit 62 integer
ATTRIBUTE Login-LAT-Port 63 string
ATTRIBUTE Tunnel-Type 64 integer
ATTRIBUTE Tunnel-Medium-Type 65 integer
ATTRIBUTE Tunnel-Client-Endpoint 66 string
ATTRIBUTE Tunnel-Server-Endpoint 67 string
ATTRIBUTE Acct-Tunnel-Connection 68 string
ATTRIBUTE Connect-Info 77 string
ATTRIBUTE Tunnel-Private-Group-ID 81 string
ATTRIBUTE Tunnel-Assignment-ID 82 string
ATTRIBUTE Tunnel-Preference 83 integer
ATTRIBUTE NAS-Port-Id 87 string
ATTRIBUTE Tunnel-Client-Auth-ID 90 string
ATTRIBUTE Tunnel-Server-Auth-ID 91 string
ATTRIBUTE NAS-Filter-Rule 92 string
ATTRIBUTE NAS-IPv6-Address 95 ipv6addr
ATTRIBUTE Framed-Interface-Id 96 ifid
ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix
ATTRIBUTE Framed-IPv6-Route 99 string
ATTRIBUTE Framed-IPv6-Pool 100 string
ATTRIBUTE Delegated-IPv6-Prefix 123 ipv6prefix
ATTRIBUTE Framed-IPv6-Address 168 ipv6addr
52 changes: 52 additions & 0 deletions pyrad/tests/testPacket.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,21 @@ def testDecodePacketWithAttribute(self):
six.b('\x01\x02\x00\x1b1234567890123456\x01\x07value'))
self.assertEqual(self.packet[1], [six.b('value')])

def testDecodePacketWithUnknownAttribute(self):
self.packet.DecodePacket(
six.b('\x01\x02\x00\x1b1234567890123456\x09\x07value'))
self.assertEqual(self.packet[9], [six.b('value')])

def testDecodePacketWithTlvAttribute(self):
self.packet.DecodePacket(
six.b('\x01\x02\x00\x1d1234567890123456\x04\x09\x01\x07value'))
self.assertEqual(self.packet[4], {1:[six.b('value')]})

def testDecodePacketIsTlvAttribute(self):
self.packet.DecodePacket(
six.b('\x01\x02\x00\x1d1234567890123456\x04\x09\x01\x07value'))
self.assertTrue(self.packet._PktIsTlvAttribute(4))

def testDecodePacketWithVendorTlvAttribute(self):
self.packet.DecodePacket(
six.b('\x01\x02\x00\x231234567890123456\x1a\x0f\x00\x00\x00\x10\x03\x09\x01\x07value'))
Expand Down Expand Up @@ -528,3 +538,45 @@ def testRequestPacketSetsId(self):
self.packet.id = None
self.packet.RequestPacket()
self.assertTrue(self.packet.id is not None)

def testRealisticUnknownAttributes(self):
""" Test a realistic Accounting Packet from raw
User-Name: [u'[email protected]']
NAS-IP-Address: ['1.2.3.4']
Service-Type: ['Framed-User']
Framed-Protocol: ['NAS-Prompt-User']
Framed-IP-Address: ['1.2.3.4']
Acct-Status-Type: ['Interim-Update']
Acct-Delay-Time: [0]
Acct-Input-Octets: [1290826858]
Acct-Output-Octets: [3551101035]
Acct-Session-Id: [u'90dbd65a18b0a6c']
Acct-Authentic: ['RADIUS']
Acct-Session-Time: [769500]
Acct-Input-Packets: [7403861]
Acct-Output-Packets: [10928170]
Acct-Link-Count: [1]
Acct-Input-Gigawords: [0]
Acct-Output-Gigawords: [2]
Event-Timestamp: [1554155989]
# vendor specific
NAS-Port-Type: ['Virtual']
(26, 594, 1): [u'UNKNOWN_PRODUCT']
# implementation specific fields
224: ['24P\x10\x00\x22\x96\xc9']
228: ['\xfe\x99\xd0P']
"""
path = os.path.join(home, 'tests', 'data')
dictObj = Dictionary(os.path.join(path, 'realistic'))
raw = six.b('\x04\x8e\x00\xc4\xb2\xf8z\xdb\xac\xfd9l\x9dI?E\x8c%\xe9'\
'\xf5\x01\[email protected]\x04\x06\x01\x02\x03\x04\x06\x06'\
'\x00\x00\x00\x02\x07\x06\x00\x00\x00\x07\x08\x06\x01\x02\x03'\
'\x04(\x06\x00\x00\x00\x03)\x06\x00\x00\x00\x00*\x06L\xf0tj+'\
'\x06\xd3\xa9\x80k,\x1190dbd65a18b0a6c-\x06\x00\x00\x00\x01.'\
'\x06\x00\x0b\xbd\xdc/\x06\x00p\xf9U0\x06\x00\xa6\xc0*3\x06'\
'\x00\x00\x00\x014\x06\x00\x00\x00\x005\x06\x00\x00\x00\x027'\
'\x06\\\xa2\x89\xd5=\x06\x00\x00\x00\x05\x1a\x17\x00\x00\x02R'\
'\x01\x11UNKNOWN_PRODUCT\xe0\n24P\x10\x00\x22\x96\xc9\xe4\x06'\
'\xfe\x99\xd0P')
pkt = packet.AcctPacket(dict=dictObj, packet=raw)
self.assertEqual(pkt.raw_packet, raw)