Subdivide ResourceRecord types

This commit is contained in:
femsci 2023-09-30 08:49:12 +02:00
parent efdf871b4e
commit 359c370b49
Signed by: femsci
GPG key ID: 08F7911F0E650C67
5 changed files with 91 additions and 18 deletions

View file

@ -22,7 +22,7 @@ public struct DnsMessage : IBinarySerializable<DnsMessage>
public DnsMessageType MessageType { get; set; }
public DnsMessageOpcode Opcode { get; set; }
public DnsResponseCode ResponseCode { get; set; }
public ICollection<ResourceRecord> Questions { get; set; }
public ICollection<QueryResourceRecord> Questions { get; set; }
public static DnsMessage Deserialize(ReadOnlyMemory<byte> data)
{

View file

@ -51,17 +51,44 @@ public enum ResourceRecordClass : short
HS = 4,
}
public struct ResourceRecord : IBinarySerializable<ResourceRecord>
public record QueryResourceRecord : IBinarySerializable<QueryResourceRecord>
{
public string Name { get; set; }
public bool IsQuery => true;
public string Name { get; set; } = default!;
public int Labels => Name.Split('.').Length;
//UTF8
internal int NameOffset => Name.Split('.').Select(x => x.Length).Sum() + Labels + 1;
public ResourceRecordType Type { get; set; }
public ResourceRecordClass Class { get; set; }
public TimeSpan Ttl { get; set; }
public static ResourceRecord Deserialize(ReadOnlyMemory<byte> data)
public static string DeserializeName(BitEnumerator b)
{
throw new NotImplementedException();
StringBuilder sb = new();
byte len;
while ((len = b.TakeByte()) != 0)
{
sb.Append(Encoding.UTF8.GetString(b.TakeBytes(len))).Append('.');
}
return sb.ToString().Trim('.');
}
public static QueryResourceRecord Deserialize(ReadOnlyMemory<byte> data)
{
BitEnumerator b = new(data);
string name = DeserializeName(b);
ResourceRecordType type = (ResourceRecordType)b.TakeInt16();
ResourceRecordClass clazz = (ResourceRecordClass)b.TakeInt16();
return new QueryResourceRecord()
{
Name = name,
Class = clazz,
Type = type,
};
}
public ReadOnlySpan<byte> SerializeName()
@ -73,7 +100,7 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
throw new ArgumentOutOfRangeException("Name must be less than 255");
}
ArrayBufferWriter<byte> buffer = new(name.Length + 1 + 4);
ArrayBufferWriter<byte> buffer = new(NameOffset);
foreach (string s in name.Split('.'))
{
@ -90,7 +117,7 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
return buffer.WrittenSpan;
}
public ReadOnlyMemory<byte> Serialize()
public virtual ReadOnlyMemory<byte> Serialize()
{
var buffer = new ArrayBufferWriter<byte>();
@ -99,11 +126,53 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
buffer.Advance(2);
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Class);
buffer.Advance(2);
BinaryPrimitives.WriteInt32BigEndian(buffer.GetSpan(), (int)Ttl.TotalSeconds);
buffer.Advance(4);
//TODO: Implement RDATA
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
buffer.Advance(2);
return buffer.WrittenMemory;
}
}
public record ResourceRecord : QueryResourceRecord, IBinarySerializable<ResourceRecord>
{
public TimeSpan Ttl { get; set; }
public byte[] Data { get; set; } = Array.Empty<byte>();
static ResourceRecord IBinarySerializable<ResourceRecord>.Deserialize(ReadOnlyMemory<byte> data)
{
QueryResourceRecord qr = Deserialize(data);
BitEnumerator b = new(data);
b.Skip(qr.NameOffset);
TimeSpan ttl = TimeSpan.FromSeconds(b.TakeInt32());
short dataLen = b.TakeInt16();
byte[] rdata = b.TakeBytes(dataLen);
return new ResourceRecord()
{
Name = qr.Name,
Class = qr.Class,
Type = qr.Type,
Ttl = ttl,
Data = rdata
};
}
public override ReadOnlyMemory<byte> Serialize()
{
var buffer = new ArrayBufferWriter<byte>();
buffer.Write(base.Serialize().Span);
BinaryPrimitives.WriteInt32BigEndian(buffer.GetSpan(), (int)Ttl.TotalSeconds);
buffer.Advance(4);
//TODO: Implement RDATA
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Data.Length);
buffer.Advance(2);
if (Data.Length > 0)
{
buffer.Write(Data);
}
return buffer.WrittenMemory;
}
}

View file

@ -26,6 +26,11 @@ public class BitEnumerator
return data.ToArray();
}
public void Skip(int len)
{
_position += len;
}
public short TakeInt16()
{
short num = BinaryPrimitives.ReadInt16BigEndian(_data.Span[_position..(_position + 2)]);

View file

@ -20,12 +20,11 @@ public class DnsTest
MessageId = 0xbabe,
MessageType = DnsMessageType.Query,
Opcode = DnsMessageOpcode.Query,
Questions = new List<ResourceRecord>()
Questions = new List<QueryResourceRecord>()
{
new ResourceRecord()
new QueryResourceRecord()
{
Class = ResourceRecordClass.IN,
Ttl = TimeSpan.Zero,
Name = "meow.lgbt",
Type = ResourceRecordType.A
},
@ -37,7 +36,7 @@ public class DnsTest
Console.WriteLine("sendt");
msg.IsRecursionDesired = false;
msg.IsAuthoritative = true;
msg.IsAuthoritative = false;
msg.MessageType = DnsMessageType.Reply;
msg.Opcode = DnsMessageOpcode.Status;
msg.ResponseCode = DnsResponseCode.NxDomain;