/// <summary> /// Parses the content and returns an object of proper type /// </summary> /// <param name="contentBytes"></param> /// <param name="type"></param> /// <param name="code"></param> /// <param name="authenticator"></param> /// <param name="sharedSecret"></param> /// <returns></returns> private Object ParseContentBytes(Byte[] contentBytes, String type, UInt32 code, Byte[] authenticator, Byte[] sharedSecret) { switch (type) { case DictionaryAttribute.TYPE_STRING: case DictionaryAttribute.TYPE_TAGGED_STRING: //couse some NAS (like NPS) send binary within string attributes, check content before unpack to prevent data loss if (contentBytes.All(b => b >= 32 && b <= 127)) //only if ascii { return(Encoding.UTF8.GetString(contentBytes)); } return(contentBytes); case DictionaryAttribute.TYPE_OCTET: // If this is a password attribute it must be decrypted if (code == 2) { return(RadiusPassword.Decrypt(sharedSecret, authenticator, contentBytes)); } return(contentBytes); case DictionaryAttribute.TYPE_INTEGER: case DictionaryAttribute.TYPE_TAGGED_INTEGER: return(BitConverter.ToUInt32(contentBytes.Reverse().ToArray(), 0)); case DictionaryAttribute.TYPE_IPADDR: return(new IPAddress(contentBytes)); default: return(null); } }
/// <summary> /// Get the raw packet bytes /// </summary> /// <returns></returns> public Byte[] GetBytes(IRadiusPacket packet) { var packetBytes = new List <Byte> { (Byte)packet.Code, packet.Identifier }; packetBytes.AddRange(new Byte[18]); // Placeholder for length and authenticator var messageAuthenticatorPosition = 0; foreach (var attribute in packet.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]; var attributeType = _radiusDictionary.GetAttribute(attribute.Key); 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(packet.SharedSecret, packet.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 (packet.Code == PacketCode.AccountingRequest || packet.Code == PacketCode.DisconnectRequest || packet.Code == PacketCode.CoaRequest) { if (messageAuthenticatorPosition != 0) { var temp = new Byte[16]; Buffer.BlockCopy(temp, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16); var messageAuthenticatorBytes = CalculateMessageAuthenticator(packetBytesArray, packet.SharedSecret, null); Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16); } var authenticator = CalculateRequestAuthenticator(packet.SharedSecret, packetBytesArray); Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16); } else if (packet.Code == PacketCode.StatusServer) { var authenticator = packet.RequestAuthenticator != null?CalculateResponseAuthenticator(packet.SharedSecret, packet.RequestAuthenticator, packetBytesArray) : packet.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, packet.SharedSecret, packet.RequestAuthenticator); Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16); } } else { if (packet.RequestAuthenticator == null) { Buffer.BlockCopy(packet.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, packet.SharedSecret, packet.RequestAuthenticator); Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16); } if (packet.RequestAuthenticator != null) { var authenticator = CalculateResponseAuthenticator(packet.SharedSecret, packet.RequestAuthenticator, packetBytesArray); Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16); } } return(packetBytesArray); }