ln.radius/RadiusMessage.cs

122 lines
3.7 KiB
C#

// /**
// * File: RadiusMessage.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Net;
using System.Collections.Generic;
using System.IO;
using ln.types;
using System.Security.Cryptography;
namespace ln.radius
{
public enum RadiusCode : byte {
AccessRequest = 1,
AccessAccept = 2,
AccessReject = 3,
AccountingRequest = 4,
AccountingResponse = 5,
AccessChallenge = 11,
StatusServer = 12,
StatusClient = 13,
Reserved = 255
}
public class RadiusMessage
{
public IPEndPoint EndPoint { get; set; }
public RadiusCode Code { get; set; }
byte identifier;
public byte Identifier
{
get => identifier;
set
{
identifier = value;
Authenticator = Guid.NewGuid().ToByteArray();
}
}
public byte[] Authenticator { get; set; }
List<RadiusAttribute> radiusAttributes = new List<RadiusAttribute>();
public RadiusMessage(IPEndPoint endPoint,RadiusCode radiusCode)
{
EndPoint = endPoint;
Code = radiusCode;
}
public byte[] Authenticate(byte[] secret)
{
byte[] packet = ToBytes();
MD5 md5 = MD5.Create();
md5.TransformBlock(packet, 0, packet.Length, null, 0);
md5.TransformFinalBlock(secret, 0, secret.Length);
Array.Copy(md5.Hash, 0, packet, 4, 16);
return packet;
}
public byte[] ToBytes()
{
using (MemoryStream memoryStream = new MemoryStream())
{
memoryStream.WriteByte((byte)Code);
memoryStream.WriteByte((byte)Identifier);
memoryStream.WriteShort((short)0);
memoryStream.WriteBytes(Authenticator);
foreach (RadiusAttribute radiusAttribute in radiusAttributes)
memoryStream.WriteBytes(radiusAttribute.ToBytes());
byte[] bytes = memoryStream.ToArray();
Array.Copy(
BitConverter.GetBytes((short)bytes.Length), 0,
bytes, 2,
2
);
return bytes;
}
}
public override string ToString()
{
return String.Format("[RadiusMessage Code={0} Identifier={1} Attributes: {2}]",Code,Identifier,String.Join(", ",radiusAttributes));
}
public static RadiusMessage FromBytes(byte[] bytes,IPEndPoint remoteEndpoint)
{
if ((bytes.Length < 20) || (bytes.Length > 4096))
throw new ArgumentOutOfRangeException(nameof(bytes),"Radius packet needs to be sized between 20 and 4095 bytes");
RadiusMessage radiusMessage = new RadiusMessage(remoteEndpoint, (RadiusCode)bytes[0]);
using (Stream stream = new MemoryStream(bytes))
{
stream.ReadByte();
radiusMessage.Identifier = (byte)stream.ReadByte();
short plength = stream.ReadShort(true);
if (plength != bytes.Length)
throw new ArgumentException("packet: length != bytes.length");
radiusMessage.Authenticator = stream.ReadBytes(16);
while (stream.Position < stream.Length)
radiusMessage.radiusAttributes.Add(RadiusAttribute.Read(stream));
}
return radiusMessage;
}
}
}