// Copyright 2020 The GoPacket Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found // in the LICENSE file in the root of the source tree. package layers import ( "encoding/binary" "fmt" "github.com/google/gopacket" ) const ( // RFC 2865 3. Packet Format // `The minimum length is 20 and maximum length is 4096.` radiusMinimumRecordSizeInBytes int = 20 radiusMaximumRecordSizeInBytes int = 4096 // RFC 2865 5. Attributes // `The Length field is one octet, and indicates the length of this Attribute including the Type, Length and Value fields.` // `The Value field is zero or more octets and contains information specific to the Attribute.` radiusAttributesMinimumRecordSizeInBytes int = 2 ) // RADIUS represents a Remote Authentication Dial In User Service layer. type RADIUS struct { BaseLayer Code RADIUSCode Identifier RADIUSIdentifier Length RADIUSLength Authenticator RADIUSAuthenticator Attributes []RADIUSAttribute } // RADIUSCode represents packet type. type RADIUSCode uint8 // constants that define RADIUSCode. const ( RADIUSCodeAccessRequest RADIUSCode = 1 // RFC2865 3. Packet Format RADIUSCodeAccessAccept RADIUSCode = 2 // RFC2865 3. Packet Format RADIUSCodeAccessReject RADIUSCode = 3 // RFC2865 3. Packet Format RADIUSCodeAccountingRequest RADIUSCode = 4 // RFC2865 3. Packet Format RADIUSCodeAccountingResponse RADIUSCode = 5 // RFC2865 3. Packet Format RADIUSCodeAccessChallenge RADIUSCode = 11 // RFC2865 3. Packet Format RADIUSCodeStatusServer RADIUSCode = 12 // RFC2865 3. Packet Format (experimental) RADIUSCodeStatusClient RADIUSCode = 13 // RFC2865 3. Packet Format (experimental) RADIUSCodeReserved RADIUSCode = 255 // RFC2865 3. Packet Format ) // String returns a string version of a RADIUSCode. func (t RADIUSCode) String() (s string) { switch t { case RADIUSCodeAccessRequest: s = "Access-Request" case RADIUSCodeAccessAccept: s = "Access-Accept" case RADIUSCodeAccessReject: s = "Access-Reject" case RADIUSCodeAccountingRequest: s = "Accounting-Request" case RADIUSCodeAccountingResponse: s = "Accounting-Response" case RADIUSCodeAccessChallenge: s = "Access-Challenge" case RADIUSCodeStatusServer: s = "Status-Server" case RADIUSCodeStatusClient: s = "Status-Client" case RADIUSCodeReserved: s = "Reserved" default: s = fmt.Sprintf("Unknown(%d)", t) } return } // RADIUSIdentifier represents packet identifier. type RADIUSIdentifier uint8 // RADIUSLength represents packet length. type RADIUSLength uint16 // RADIUSAuthenticator represents authenticator. type RADIUSAuthenticator [16]byte // RADIUSAttribute represents attributes. type RADIUSAttribute struct { Type RADIUSAttributeType Length RADIUSAttributeLength Value RADIUSAttributeValue } // RADIUSAttributeType represents attribute type. type RADIUSAttributeType uint8 // constants that define RADIUSAttributeType. const ( RADIUSAttributeTypeUserName RADIUSAttributeType = 1 // RFC2865 5.1. User-Name RADIUSAttributeTypeUserPassword RADIUSAttributeType = 2 // RFC2865 5.2. User-Password RADIUSAttributeTypeCHAPPassword RADIUSAttributeType = 3 // RFC2865 5.3. CHAP-Password RADIUSAttributeTypeNASIPAddress RADIUSAttributeType = 4 // RFC2865 5.4. NAS-IP-Address RADIUSAttributeTypeNASPort RADIUSAttributeType = 5 // RFC2865 5.5. NAS-Port RADIUSAttributeTypeServiceType RADIUSAttributeType = 6 // RFC2865 5.6. Service-Type RADIUSAttributeTypeFramedProtocol RADIUSAttributeType = 7 // RFC2865 5.7. Framed-Protocol RADIUSAttributeTypeFramedIPAddress RADIUSAttributeType = 8 // RFC2865 5.8. Framed-IP-Address RADIUSAttributeTypeFramedIPNetmask RADIUSAttributeType = 9 // RFC2865 5.9. Framed-IP-Netmask RADIUSAttributeTypeFramedRouting RADIUSAttributeType = 10 // RFC2865 5.10. Framed-Routing RADIUSAttributeTypeFilterId RADIUSAttributeType = 11 // RFC2865 5.11. Filter-Id RADIUSAttributeTypeFramedMTU RADIUSAttributeType = 12 // RFC2865 5.12. Framed-MTU RADIUSAttributeTypeFramedCompression RADIUSAttributeType = 13 // RFC2865 5.13. Framed-Compression RADIUSAttributeTypeLoginIPHost RADIUSAttributeType = 14 // RFC2865 5.14. Login-IP-Host RADIUSAttributeTypeLoginService RADIUSAttributeType = 15 // RFC2865 5.15. Login-Service RADIUSAttributeTypeLoginTCPPort RADIUSAttributeType = 16 // RFC2865 5.16. Login-TCP-Port RADIUSAttributeTypeReplyMessage RADIUSAttributeType = 18 // RFC2865 5.18. Reply-Message RADIUSAttributeTypeCallbackNumber RADIUSAttributeType = 19 // RFC2865 5.19. Callback-Number RADIUSAttributeTypeCallbackId RADIUSAttributeType = 20 // RFC2865 5.20. Callback-Id RADIUSAttributeTypeFramedRoute RADIUSAttributeType = 22 // RFC2865 5.22. Framed-Route RADIUSAttributeTypeFramedIPXNetwork RADIUSAttributeType = 23 // RFC2865 5.23. Framed-IPX-Network RADIUSAttributeTypeState RADIUSAttributeType = 24 // RFC2865 5.24. State RADIUSAttributeTypeClass RADIUSAttributeType = 25 // RFC2865 5.25. Class RADIUSAttributeTypeVendorSpecific RADIUSAttributeType = 26 // RFC2865 5.26. Vendor-Specific RADIUSAttributeTypeSessionTimeout RADIUSAttributeType = 27 // RFC2865 5.27. Session-Timeout RADIUSAttributeTypeIdleTimeout RADIUSAttributeType = 28 // RFC2865 5.28. Idle-Timeout RADIUSAttributeTypeTerminationAction RADIUSAttributeType = 29 // RFC2865 5.29. Termination-Action RADIUSAttributeTypeCalledStationId RADIUSAttributeType = 30 // RFC2865 5.30. Called-Station-Id RADIUSAttributeTypeCallingStationId RADIUSAttributeType = 31 // RFC2865 5.31. Calling-Station-Id RADIUSAttributeTypeNASIdentifier RADIUSAttributeType = 32 // RFC2865 5.32. NAS-Identifier RADIUSAttributeTypeProxyState RADIUSAttributeType = 33 // RFC2865 5.33. Proxy-State RADIUSAttributeTypeLoginLATService RADIUSAttributeType = 34 // RFC2865 5.34. Login-LAT-Service RADIUSAttributeTypeLoginLATNode RADIUSAttributeType = 35 // RFC2865 5.35. Login-LAT-Node RADIUSAttributeTypeLoginLATGroup RADIUSAttributeType = 36 // RFC2865 5.36. Login-LAT-Group RADIUSAttributeTypeFramedAppleTalkLink RADIUSAttributeType = 37 // RFC2865 5.37. Framed-AppleTalk-Link RADIUSAttributeTypeFramedAppleTalkNetwork RADIUSAttributeType = 38 // RFC2865 5.38. Framed-AppleTalk-Network RADIUSAttributeTypeFramedAppleTalkZone RADIUSAttributeType = 39 // RFC2865 5.39. Framed-AppleTalk-Zone RADIUSAttributeTypeAcctStatusType RADIUSAttributeType = 40 // RFC2866 5.1. Acct-Status-Type RADIUSAttributeTypeAcctDelayTime RADIUSAttributeType = 41 // RFC2866 5.2. Acct-Delay-Time RADIUSAttributeTypeAcctInputOctets RADIUSAttributeType = 42 // RFC2866 5.3. Acct-Input-Octets RADIUSAttributeTypeAcctOutputOctets RADIUSAttributeType = 43 // RFC2866 5.4. Acct-Output-Octets RADIUSAttributeTypeAcctSessionId RADIUSAttributeType = 44 // RFC2866 5.5. Acct-Session-Id RADIUSAttributeTypeAcctAuthentic RADIUSAttributeType = 45 // RFC2866 5.6. Acct-Authentic RADIUSAttributeTypeAcctSessionTime RADIUSAttributeType = 46 // RFC2866 5.7. Acct-Session-Time RADIUSAttributeTypeAcctInputPackets RADIUSAttributeType = 47 // RFC2866 5.8. Acct-Input-Packets RADIUSAttributeTypeAcctOutputPackets RADIUSAttributeType = 48 // RFC2866 5.9. Acct-Output-Packets RADIUSAttributeTypeAcctTerminateCause RADIUSAttributeType = 49 // RFC2866 5.10. Acct-Terminate-Cause RADIUSAttributeTypeAcctMultiSessionId RADIUSAttributeType = 50 // RFC2866 5.11. Acct-Multi-Session-Id RADIUSAttributeTypeAcctLinkCount RADIUSAttributeType = 51 // RFC2866 5.12. Acct-Link-Count RADIUSAttributeTypeAcctInputGigawords RADIUSAttributeType = 52 // RFC2869 5.1. Acct-Input-Gigawords RADIUSAttributeTypeAcctOutputGigawords RADIUSAttributeType = 53 // RFC2869 5.2. Acct-Output-Gigawords RADIUSAttributeTypeEventTimestamp RADIUSAttributeType = 55 // RFC2869 5.3. Event-Timestamp RADIUSAttributeTypeCHAPChallenge RADIUSAttributeType = 60 // RFC2865 5.40. CHAP-Challenge RADIUSAttributeTypeNASPortType RADIUSAttributeType = 61 // RFC2865 5.41. NAS-Port-Type RADIUSAttributeTypePortLimit RADIUSAttributeType = 62 // RFC2865 5.42. Port-Limit RADIUSAttributeTypeLoginLATPort RADIUSAttributeType = 63 // RFC2865 5.43. Login-LAT-Port RADIUSAttributeTypeTunnelType RADIUSAttributeType = 64 // RFC2868 3.1. Tunnel-Type RADIUSAttributeTypeTunnelMediumType RADIUSAttributeType = 65 // RFC2868 3.2. Tunnel-Medium-Type RADIUSAttributeTypeTunnelClientEndpoint RADIUSAttributeType = 66 // RFC2868 3.3. Tunnel-Client-Endpoint RADIUSAttributeTypeTunnelServerEndpoint RADIUSAttributeType = 67 // RFC2868 3.4. Tunnel-Server-Endpoint RADIUSAttributeTypeAcctTunnelConnection RADIUSAttributeType = 68 // RFC2867 4.1. Acct-Tunnel-Connection RADIUSAttributeTypeTunnelPassword RADIUSAttributeType = 69 // RFC2868 3.5. Tunnel-Password RADIUSAttributeTypeARAPPassword RADIUSAttributeType = 70 // RFC2869 5.4. ARAP-Password RADIUSAttributeTypeARAPFeatures RADIUSAttributeType = 71 // RFC2869 5.5. ARAP-Features RADIUSAttributeTypeARAPZoneAccess RADIUSAttributeType = 72 // RFC2869 5.6. ARAP-Zone-Access RADIUSAttributeTypeARAPSecurity RADIUSAttributeType = 73 // RFC2869 5.7. ARAP-Security RADIUSAttributeTypeARAPSecurityData RADIUSAttributeType = 74 // RFC2869 5.8. ARAP-Security-Data RADIUSAttributeTypePasswordRetry RADIUSAttributeType = 75 // RFC2869 5.9. Password-Retry RADIUSAttributeTypePrompt RADIUSAttributeType = 76 // RFC2869 5.10. Prompt RADIUSAttributeTypeConnectInfo RADIUSAttributeType = 77 // RFC2869 5.11. Connect-Info RADIUSAttributeTypeConfigurationToken RADIUSAttributeType = 78 // RFC2869 5.12. Configuration-Token RADIUSAttributeTypeEAPMessage RADIUSAttributeType = 79 // RFC2869 5.13. EAP-Message RADIUSAttributeTypeMessageAuthenticator RADIUSAttributeType = 80 // RFC2869 5.14. Message-Authenticator RADIUSAttributeTypeTunnelPrivateGroupID RADIUSAttributeType = 81 // RFC2868 3.6. Tunnel-Private-Group-ID RADIUSAttributeTypeTunnelAssignmentID RADIUSAttributeType = 82 // RFC2868 3.7. Tunnel-Assignment-ID RADIUSAttributeTypeTunnelPreference RADIUSAttributeType = 83 // RFC2868 3.8. Tunnel-Preference RADIUSAttributeTypeARAPChallengeResponse RADIUSAttributeType = 84 // RFC2869 5.15. ARAP-Challenge-Response RADIUSAttributeTypeAcctInterimInterval RADIUSAttributeType = 85 // RFC2869 5.16. Acct-Interim-Interval RADIUSAttributeTypeAcctTunnelPacketsLost RADIUSAttributeType = 86 // RFC2867 4.2. Acct-Tunnel-Packets-Lost RADIUSAttributeTypeNASPortId RADIUSAttributeType = 87 // RFC2869 5.17. NAS-Port-Id RADIUSAttributeTypeFramedPool RADIUSAttributeType = 88 // RFC2869 5.18. Framed-Pool RADIUSAttributeTypeTunnelClientAuthID RADIUSAttributeType = 90 // RFC2868 3.9. Tunnel-Client-Auth-ID RADIUSAttributeTypeTunnelServerAuthID RADIUSAttributeType = 91 // RFC2868 3.10. Tunnel-Server-Auth-ID ) // RADIUSAttributeType represents attribute length. type RADIUSAttributeLength uint8 // RADIUSAttributeType represents attribute value. type RADIUSAttributeValue []byte // String returns a string version of a RADIUSAttributeType. func (t RADIUSAttributeType) String() (s string) { switch t { case RADIUSAttributeTypeUserName: s = "User-Name" case RADIUSAttributeTypeUserPassword: s = "User-Password" case RADIUSAttributeTypeCHAPPassword: s = "CHAP-Password" case RADIUSAttributeTypeNASIPAddress: s = "NAS-IP-Address" case RADIUSAttributeTypeNASPort: s = "NAS-Port" case RADIUSAttributeTypeServiceType: s = "Service-Type" case RADIUSAttributeTypeFramedProtocol: s = "Framed-Protocol" case RADIUSAttributeTypeFramedIPAddress: s = "Framed-IP-Address" case RADIUSAttributeTypeFramedIPNetmask: s = "Framed-IP-Netmask" case RADIUSAttributeTypeFramedRouting: s = "Framed-Routing" case RADIUSAttributeTypeFilterId: s = "Filter-Id" case RADIUSAttributeTypeFramedMTU: s = "Framed-MTU" case RADIUSAttributeTypeFramedCompression: s = "Framed-Compression" case RADIUSAttributeTypeLoginIPHost: s = "Login-IP-Host" case RADIUSAttributeTypeLoginService: s = "Login-Service" case RADIUSAttributeTypeLoginTCPPort: s = "Login-TCP-Port" case RADIUSAttributeTypeReplyMessage: s = "Reply-Message" case RADIUSAttributeTypeCallbackNumber: s = "Callback-Number" case RADIUSAttributeTypeCallbackId: s = "Callback-Id" case RADIUSAttributeTypeFramedRoute: s = "Framed-Route" case RADIUSAttributeTypeFramedIPXNetwork: s = "Framed-IPX-Network" case RADIUSAttributeTypeState: s = "State" case RADIUSAttributeTypeClass: s = "Class" case RADIUSAttributeTypeVendorSpecific: s = "Vendor-Specific" case RADIUSAttributeTypeSessionTimeout: s = "Session-Timeout" case RADIUSAttributeTypeIdleTimeout: s = "Idle-Timeout" case RADIUSAttributeTypeTerminationAction: s = "Termination-Action" case RADIUSAttributeTypeCalledStationId: s = "Called-Station-Id" case RADIUSAttributeTypeCallingStationId: s = "Calling-Station-Id" case RADIUSAttributeTypeNASIdentifier: s = "NAS-Identifier" case RADIUSAttributeTypeProxyState: s = "Proxy-State" case RADIUSAttributeTypeLoginLATService: s = "Login-LAT-Service" case RADIUSAttributeTypeLoginLATNode: s = "Login-LAT-Node" case RADIUSAttributeTypeLoginLATGroup: s = "Login-LAT-Group" case RADIUSAttributeTypeFramedAppleTalkLink: s = "Framed-AppleTalk-Link" case RADIUSAttributeTypeFramedAppleTalkNetwork: s = "Framed-AppleTalk-Network" case RADIUSAttributeTypeFramedAppleTalkZone: s = "Framed-AppleTalk-Zone" case RADIUSAttributeTypeAcctStatusType: s = "Acct-Status-Type" case RADIUSAttributeTypeAcctDelayTime: s = "Acct-Delay-Time" case RADIUSAttributeTypeAcctInputOctets: s = "Acct-Input-Octets" case RADIUSAttributeTypeAcctOutputOctets: s = "Acct-Output-Octets" case RADIUSAttributeTypeAcctSessionId: s = "Acct-Session-Id" case RADIUSAttributeTypeAcctAuthentic: s = "Acct-Authentic" case RADIUSAttributeTypeAcctSessionTime: s = "Acct-Session-Time" case RADIUSAttributeTypeAcctInputPackets: s = "Acct-Input-Packets" case RADIUSAttributeTypeAcctOutputPackets: s = "Acct-Output-Packets" case RADIUSAttributeTypeAcctTerminateCause: s = "Acct-Terminate-Cause" case RADIUSAttributeTypeAcctMultiSessionId: s = "Acct-Multi-Session-Id" case RADIUSAttributeTypeAcctLinkCount: s = "Acct-Link-Count" case RADIUSAttributeTypeAcctInputGigawords: s = "Acct-Input-Gigawords" case RADIUSAttributeTypeAcctOutputGigawords: s = "Acct-Output-Gigawords" case RADIUSAttributeTypeEventTimestamp: s = "Event-Timestamp" case RADIUSAttributeTypeCHAPChallenge: s = "CHAP-Challenge" case RADIUSAttributeTypeNASPortType: s = "NAS-Port-Type" case RADIUSAttributeTypePortLimit: s = "Port-Limit" case RADIUSAttributeTypeLoginLATPort: s = "Login-LAT-Port" case RADIUSAttributeTypeTunnelType: s = "Tunnel-Type" case RADIUSAttributeTypeTunnelMediumType: s = "Tunnel-Medium-Type" case RADIUSAttributeTypeTunnelClientEndpoint: s = "Tunnel-Client-Endpoint" case RADIUSAttributeTypeTunnelServerEndpoint: s = "Tunnel-Server-Endpoint" case RADIUSAttributeTypeAcctTunnelConnection: s = "Acct-Tunnel-Connection" case RADIUSAttributeTypeTunnelPassword: s = "Tunnel-Password" case RADIUSAttributeTypeARAPPassword: s = "ARAP-Password" case RADIUSAttributeTypeARAPFeatures: s = "ARAP-Features" case RADIUSAttributeTypeARAPZoneAccess: s = "ARAP-Zone-Access" case RADIUSAttributeTypeARAPSecurity: s = "ARAP-Security" case RADIUSAttributeTypeARAPSecurityData: s = "ARAP-Security-Data" case RADIUSAttributeTypePasswordRetry: s = "Password-Retry" case RADIUSAttributeTypePrompt: s = "Prompt" case RADIUSAttributeTypeConnectInfo: s = "Connect-Info" case RADIUSAttributeTypeConfigurationToken: s = "Configuration-Token" case RADIUSAttributeTypeEAPMessage: s = "EAP-Message" case RADIUSAttributeTypeMessageAuthenticator: s = "Message-Authenticator" case RADIUSAttributeTypeTunnelPrivateGroupID: s = "Tunnel-Private-Group-ID" case RADIUSAttributeTypeTunnelAssignmentID: s = "Tunnel-Assignment-ID" case RADIUSAttributeTypeTunnelPreference: s = "Tunnel-Preference" case RADIUSAttributeTypeARAPChallengeResponse: s = "ARAP-Challenge-Response" case RADIUSAttributeTypeAcctInterimInterval: s = "Acct-Interim-Interval" case RADIUSAttributeTypeAcctTunnelPacketsLost: s = "Acct-Tunnel-Packets-Lost" case RADIUSAttributeTypeNASPortId: s = "NAS-Port-Id" case RADIUSAttributeTypeFramedPool: s = "Framed-Pool" case RADIUSAttributeTypeTunnelClientAuthID: s = "Tunnel-Client-Auth-ID" case RADIUSAttributeTypeTunnelServerAuthID: s = "Tunnel-Server-Auth-ID" default: s = fmt.Sprintf("Unknown(%d)", t) } return } // Len returns the length of a RADIUS packet. func (radius *RADIUS) Len() (int, error) { n := radiusMinimumRecordSizeInBytes for _, v := range radius.Attributes { alen, err := attributeValueLength(v.Value) if err != nil { return 0, err } n += int(alen) + 2 // Added Type and Length } return n, nil } // LayerType returns LayerTypeRADIUS. func (radius *RADIUS) LayerType() gopacket.LayerType { return LayerTypeRADIUS } // DecodeFromBytes decodes the given bytes into this layer. func (radius *RADIUS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) > radiusMaximumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS length %d too big", len(data)) } if len(data) < radiusMinimumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS length %d too short", len(data)) } radius.BaseLayer = BaseLayer{Contents: data} radius.Code = RADIUSCode(data[0]) radius.Identifier = RADIUSIdentifier(data[1]) radius.Length = RADIUSLength(binary.BigEndian.Uint16(data[2:4])) if int(radius.Length) > radiusMaximumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS length %d too big", radius.Length) } if int(radius.Length) < radiusMinimumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS length %d too short", radius.Length) } // RFC 2865 3. Packet Format // `If the packet is shorter than the Length field indicates, it MUST be silently discarded.` if int(radius.Length) > len(data) { df.SetTruncated() return fmt.Errorf("RADIUS length %d too big", radius.Length) } // RFC 2865 3. Packet Format // `Octets outside the range of the Length field MUST be treated as padding and ignored on reception.` if int(radius.Length) < len(data) { df.SetTruncated() data = data[:radius.Length] } copy(radius.Authenticator[:], data[4:20]) if len(data) == radiusMinimumRecordSizeInBytes { return nil } pos := radiusMinimumRecordSizeInBytes for { if len(data) == pos { break } if len(data[pos:]) < radiusAttributesMinimumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS attributes length %d too short", len(data[pos:])) } attr := RADIUSAttribute{} attr.Type = RADIUSAttributeType(data[pos]) attr.Length = RADIUSAttributeLength(data[pos+1]) if int(attr.Length) > len(data[pos:]) { df.SetTruncated() return fmt.Errorf("RADIUS attributes length %d too big", attr.Length) } if int(attr.Length) < radiusAttributesMinimumRecordSizeInBytes { df.SetTruncated() return fmt.Errorf("RADIUS attributes length %d too short", attr.Length) } if int(attr.Length) > radiusAttributesMinimumRecordSizeInBytes { attr.Value = make([]byte, attr.Length-2) copy(attr.Value[:], data[pos+2:pos+int(attr.Length)]) radius.Attributes = append(radius.Attributes, attr) } pos += int(attr.Length) } for _, v := range radius.Attributes { if v.Type == RADIUSAttributeTypeEAPMessage { radius.BaseLayer.Payload = append(radius.BaseLayer.Payload, v.Value...) } } return nil } // SerializeTo writes the serialized form of this layer into the // SerializationBuffer, implementing gopacket.SerializableLayer. // See the docs for gopacket.SerializableLayer for more info. func (radius *RADIUS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { plen, err := radius.Len() if err != nil { return err } if opts.FixLengths { radius.Length = RADIUSLength(plen) } data, err := b.PrependBytes(plen) if err != nil { return err } data[0] = byte(radius.Code) data[1] = byte(radius.Identifier) binary.BigEndian.PutUint16(data[2:], uint16(radius.Length)) copy(data[4:20], radius.Authenticator[:]) pos := radiusMinimumRecordSizeInBytes for _, v := range radius.Attributes { if opts.FixLengths { v.Length, err = attributeValueLength(v.Value) if err != nil { return err } } data[pos] = byte(v.Type) data[pos+1] = byte(v.Length) copy(data[pos+2:], v.Value[:]) pos += len(v.Value) + 2 // Added Type and Length } return nil } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (radius *RADIUS) CanDecode() gopacket.LayerClass { return LayerTypeRADIUS } // NextLayerType returns the layer type contained by this DecodingLayer. func (radius *RADIUS) NextLayerType() gopacket.LayerType { if len(radius.BaseLayer.Payload) > 0 { return LayerTypeEAP } else { return gopacket.LayerTypeZero } } // Payload returns the EAP Type-Data for EAP-Message attributes. func (radius *RADIUS) Payload() []byte { return radius.BaseLayer.Payload } func decodeRADIUS(data []byte, p gopacket.PacketBuilder) error { radius := &RADIUS{} err := radius.DecodeFromBytes(data, p) if err != nil { return err } p.AddLayer(radius) p.SetApplicationLayer(radius) next := radius.NextLayerType() if next == gopacket.LayerTypeZero { return nil } return p.NextDecoder(next) } func attributeValueLength(v []byte) (RADIUSAttributeLength, error) { n := len(v) if n > 255 { return 0, fmt.Errorf("RADIUS attribute value length %d too long", n) } else { return RADIUSAttributeLength(n), nil } }