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 DnsMessageType MessageType { get; set; }
|
||||||
public DnsMessageOpcode Opcode { get; set; }
|
public DnsMessageOpcode Opcode { get; set; }
|
||||||
public DnsResponseCode ResponseCode { 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)
|
public static DnsMessage Deserialize(ReadOnlyMemory<byte> data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,17 +51,44 @@ public enum ResourceRecordClass : short
|
||||||
HS = 4,
|
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 ResourceRecordType Type { get; set; }
|
||||||
public ResourceRecordClass Class { 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()
|
public ReadOnlySpan<byte> SerializeName()
|
||||||
|
@ -73,7 +100,7 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
|
||||||
throw new ArgumentOutOfRangeException("Name must be less than 255");
|
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('.'))
|
foreach (string s in name.Split('.'))
|
||||||
{
|
{
|
||||||
|
@ -90,7 +117,7 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
|
||||||
return buffer.WrittenSpan;
|
return buffer.WrittenSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyMemory<byte> Serialize()
|
public virtual ReadOnlyMemory<byte> Serialize()
|
||||||
{
|
{
|
||||||
var buffer = new ArrayBufferWriter<byte>();
|
var buffer = new ArrayBufferWriter<byte>();
|
||||||
|
|
||||||
|
@ -99,11 +126,53 @@ public struct ResourceRecord : IBinarySerializable<ResourceRecord>
|
||||||
buffer.Advance(2);
|
buffer.Advance(2);
|
||||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Class);
|
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Class);
|
||||||
buffer.Advance(2);
|
buffer.Advance(2);
|
||||||
BinaryPrimitives.WriteInt32BigEndian(buffer.GetSpan(), (int)Ttl.TotalSeconds);
|
|
||||||
buffer.Advance(4);
|
return buffer.WrittenMemory;
|
||||||
//TODO: Implement RDATA
|
}
|
||||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
|
}
|
||||||
buffer.Advance(2);
|
|
||||||
|
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;
|
return buffer.WrittenMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,11 @@ public class BitEnumerator
|
||||||
return data.ToArray();
|
return data.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Skip(int len)
|
||||||
|
{
|
||||||
|
_position += len;
|
||||||
|
}
|
||||||
|
|
||||||
public short TakeInt16()
|
public short TakeInt16()
|
||||||
{
|
{
|
||||||
short num = BinaryPrimitives.ReadInt16BigEndian(_data.Span[_position..(_position + 2)]);
|
short num = BinaryPrimitives.ReadInt16BigEndian(_data.Span[_position..(_position + 2)]);
|
||||||
|
|
|
@ -20,12 +20,11 @@ public class DnsTest
|
||||||
MessageId = 0xbabe,
|
MessageId = 0xbabe,
|
||||||
MessageType = DnsMessageType.Query,
|
MessageType = DnsMessageType.Query,
|
||||||
Opcode = DnsMessageOpcode.Query,
|
Opcode = DnsMessageOpcode.Query,
|
||||||
Questions = new List<ResourceRecord>()
|
Questions = new List<QueryResourceRecord>()
|
||||||
{
|
{
|
||||||
new ResourceRecord()
|
new QueryResourceRecord()
|
||||||
{
|
{
|
||||||
Class = ResourceRecordClass.IN,
|
Class = ResourceRecordClass.IN,
|
||||||
Ttl = TimeSpan.Zero,
|
|
||||||
Name = "meow.lgbt",
|
Name = "meow.lgbt",
|
||||||
Type = ResourceRecordType.A
|
Type = ResourceRecordType.A
|
||||||
},
|
},
|
||||||
|
@ -37,7 +36,7 @@ public class DnsTest
|
||||||
Console.WriteLine("sendt");
|
Console.WriteLine("sendt");
|
||||||
|
|
||||||
msg.IsRecursionDesired = false;
|
msg.IsRecursionDesired = false;
|
||||||
msg.IsAuthoritative = true;
|
msg.IsAuthoritative = false;
|
||||||
msg.MessageType = DnsMessageType.Reply;
|
msg.MessageType = DnsMessageType.Reply;
|
||||||
msg.Opcode = DnsMessageOpcode.Status;
|
msg.Opcode = DnsMessageOpcode.Status;
|
||||||
msg.ResponseCode = DnsResponseCode.NxDomain;
|
msg.ResponseCode = DnsResponseCode.NxDomain;
|
||||||
|
|
Loading…
Reference in a new issue