Example #1
0
        /// <summary>
        /// Get the raw packet bytes
        /// </summary>
        /// <returns></returns>
        public Byte[] GetBytes(RadiusDictionary dictionary)
        {
            var packetBytes = new List <Byte>
            {
                (Byte)Code,
                Identifier
            };

            packetBytes.AddRange(new Byte[18]); // Placeholder for length and authenticator

            var messageAuthenticatorPosition = 0;

            foreach (var attribute in Attributes)
            {
                // todo add logic to check attribute object type matches type in dictionary?
                foreach (var value in attribute.Value)
                {
                    var contentBytes = GetAttributeValueBytes(value);
                    var headerBytes  = new Byte[2];

                    dictionary.AttributeNames.TryGetValue(attribute.Key, out var attributeType);
                    switch (attributeType)
                    {
                    case DictionaryVendorAttribute _attributeType:
                        headerBytes    = new Byte[8];
                        headerBytes[0] = 26;     // VSA type

                        var vendorId = BitConverter.GetBytes(_attributeType.VendorId);
                        Array.Reverse(vendorId);
                        Buffer.BlockCopy(vendorId, 0, headerBytes, 2, 4);
                        headerBytes[6] = (Byte)_attributeType.VendorCode;
                        headerBytes[7] = (Byte)(2 + contentBytes.Length);      // length of the vsa part
                        break;

                    case DictionaryAttribute _attributeType:
                        headerBytes[0] = attributeType.Code;

                        // Encrypt password if this is a User-Password attribute
                        if (_attributeType.Code == 2)
                        {
                            contentBytes = RadiusPassword.Encrypt(SharedSecret, Authenticator, contentBytes);
                        }
                        else if (_attributeType.Code == 80)        // Remember the position of the message authenticator, because it has to be added after everything else
                        {
                            messageAuthenticatorPosition = packetBytes.Count;
                        }
                        break;

                    default:
                        throw new InvalidOperationException($"Unknown attribute {attribute.Key}, check spelling or dictionary");
                    }

                    headerBytes[1] = (Byte)(headerBytes.Length + contentBytes.Length);
                    packetBytes.AddRange(headerBytes);
                    packetBytes.AddRange(contentBytes);
                }
            }

            // Note the order of the bytes...
            var packetLengthBytes = BitConverter.GetBytes(packetBytes.Count);

            packetBytes[2] = packetLengthBytes[1];
            packetBytes[3] = packetLengthBytes[0];

            var packetBytesArray = packetBytes.ToArray();

            if (Code == PacketCode.AccountingRequest || Code == PacketCode.DisconnectRequest)
            {
                var authenticator = CalculateRequestAuthenticator(SharedSecret, packetBytesArray);
                Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16);
            }
            else
            {
                var authenticator = _requestAuthenticator != null?CalculateResponseAuthenticator(SharedSecret, _requestAuthenticator, packetBytesArray) : Authenticator;

                Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16);
            }

            if (messageAuthenticatorPosition != 0)
            {
                var temp = new Byte[16];
                Buffer.BlockCopy(temp, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                var messageAuthenticatorBytes = CalculateMessageAuthenticator(packetBytesArray, SharedSecret);
                Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
            }


            return(packetBytesArray);
        }
Example #2
0
        /// <summary>
        /// Parses packet bytes and returns an IRadiusPacket
        /// </summary>
        /// <param name="packetBytes"></param>
        /// <param name="dictionary"></param>
        /// <param name="sharedSecret"></param>
        public static IRadiusPacket Parse(Byte[] packetBytes, RadiusDictionary dictionary, Byte[] sharedSecret)
        {
            var packetLength = BitConverter.ToUInt16(packetBytes.Skip(2).Take(2).Reverse().ToArray(), 0);

            if (packetBytes.Length != packetLength)
            {
                throw new InvalidOperationException($"Packet length does not match, expected: {packetLength}, actual: {packetBytes.Length}");
            }

            var packet = new RadiusPacket
            {
                SharedSecret = sharedSecret,
                Identifier   = packetBytes[1],
                Code         = (PacketCode)packetBytes[0],
            };

            Buffer.BlockCopy(packetBytes, 4, packet.Authenticator, 0, 16);

            if (packet.Code == PacketCode.AccountingRequest || packet.Code == PacketCode.DisconnectRequest)
            {
                if (!packet.Authenticator.SequenceEqual(CalculateRequestAuthenticator(packet.SharedSecret, packetBytes)))
                {
                    throw new InvalidOperationException($"Invalid request authenticator in packet {packet.Identifier}, check secret?");
                }
            }

            // The rest are attribute value pairs
            var position = 20;
            var messageAuthenticatorPosition = 0;

            while (position < packetBytes.Length)
            {
                var typecode = packetBytes[position];
                var length   = packetBytes[position + 1];

                if (position + length > packetLength)
                {
                    throw new ArgumentOutOfRangeException("Go home roamserver, youre drunk");
                }
                var contentBytes = new Byte[length - 2];
                Buffer.BlockCopy(packetBytes, position + 2, contentBytes, 0, length - 2);

                try
                {
                    if (typecode == 26) // VSA
                    {
                        var vsa = new VendorSpecificAttribute(contentBytes);
                        var vendorAttributeDefinition = dictionary.VendorSpecificAttributes.FirstOrDefault(o => o.VendorId == vsa.VendorId && o.VendorCode == vsa.VendorCode);
                        if (vendorAttributeDefinition == null)
                        {
                            _log.Info($"Unknown vsa: {vsa.VendorId}:{vsa.VendorCode}");
                        }
                        else
                        {
                            try
                            {
                                var content = ParseContentBytes(vsa.Value, vendorAttributeDefinition.Type, typecode, packet.Authenticator, packet.SharedSecret);
                                packet.AddAttributeObject(vendorAttributeDefinition.Name, content);
                            }
                            catch (Exception ex)
                            {
                                _log.Error($"Something went wrong with vsa {vendorAttributeDefinition.Name}", ex);
                            }
                        }
                    }
                    else
                    {
                        var attributeDefinition = dictionary.Attributes[typecode];
                        if (attributeDefinition.Code == 80)
                        {
                            messageAuthenticatorPosition = position;
                        }
                        try
                        {
                            var content = ParseContentBytes(contentBytes, attributeDefinition.Type, typecode, packet.Authenticator, packet.SharedSecret);
                            packet.AddAttributeObject(attributeDefinition.Name, content);
                        }
                        catch (Exception ex)
                        {
                            _log.Error($"Something went wrong with {attributeDefinition.Name}", ex);
                            _log.Debug($"Attribute bytes: {contentBytes.ToHexString()}");
                        }
                    }
                }
                catch (KeyNotFoundException)
                {
                    _log.Warn($"Attribute {typecode} not found in dictionary");
                }
                catch (Exception ex)
                {
                    _log.Error($"Something went wrong parsing attribute {typecode}", ex);
                }

                position += length;
            }

            if (messageAuthenticatorPosition != 0)
            {
                var messageAuthenticator = packet.GetAttribute <Byte[]>("Message-Authenticator");
                var temp = new Byte[16];
                Buffer.BlockCopy(temp, 0, packetBytes, messageAuthenticatorPosition + 2, 16);
                var calculatedMessageAuthenticator = CalculateMessageAuthenticator(packetBytes, sharedSecret);
                if (!calculatedMessageAuthenticator.SequenceEqual(messageAuthenticator))
                {
                    throw new InvalidOperationException($"Invalid Message-Authenticator in packet {packet.Identifier}");
                }
            }

            return(packet);
        }
Example #3
0
        /// <summary>
        /// Tries to get a packet from the stream. Returns true if successful
        /// Returns false if no packet could be parsed or stream is empty ie closing
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="packet"></param>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static Boolean TryParsePacketFromStream(Stream stream, out IRadiusPacket packet, RadiusDictionary dictionary, Byte[] sharedSecret)
        {
            var packetHeaderBytes = new Byte[4];
            var i = stream.Read(packetHeaderBytes, 0, 4);

            if (i != 0)
            {
                try
                {
                    var packetLength       = BitConverter.ToUInt16(packetHeaderBytes.Reverse().ToArray(), 0);
                    var packetContentBytes = new Byte[packetLength - 4];
                    stream.Read(packetContentBytes, 0, packetContentBytes.Length);

                    packet = Parse(packetHeaderBytes.Concat(packetContentBytes).ToArray(), dictionary, sharedSecret);
                    return(true);
                }
                catch (Exception ex)
                {
                    _log.Warn("Unable to parse packet from stream", ex);
                }
            }

            packet = null;
            return(false);
        }