Subdivide ResourceRecord types
This commit is contained in:
parent
efdf871b4e
commit
359c370b49
5 changed files with 91 additions and 18 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue