Skip to content

Commit

Permalink
Adds DnsCaaResource.
Browse files Browse the repository at this point in the history
  • Loading branch information
alanedwardes committed Mar 29, 2024
1 parent 8b11ae0 commit 23701ec
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 10 deletions.
36 changes: 26 additions & 10 deletions src/Ae.Dns.Protocol/DnsByteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,20 @@ public static ReadOnlyMemory<byte> ReadBytes(ReadOnlyMemory<byte> bytes, int len
return data;
}

private static string ReadStringSimple(ReadOnlyMemory<byte> bytes, ref int offset)
private static string ReadStringFromBuffer(ReadOnlySpan<byte> bytes)
{
byte labelLength = bytes.Span[offset];
offset += 1;
#if NETSTANDARD2_0
var str = Encoding.ASCII.GetString(bytes.Slice(offset, labelLength).ToArray());
return Encoding.ASCII.GetString(bytes.ToArray());
#else
var str = Encoding.ASCII.GetString(bytes.Slice(offset, labelLength).Span);
return Encoding.ASCII.GetString(bytes);
#endif
}

public static string ReadStringWithLengthPrefix(ReadOnlyMemory<byte> bytes, ref int offset)
{
byte labelLength = bytes.Span[offset];
offset += 1;
var str = ReadStringFromBuffer(bytes.Slice(offset, labelLength).Span);
offset += labelLength;
return str;
}
Expand Down Expand Up @@ -106,7 +111,7 @@ private static List<string> ReadString(ReadOnlyMemory<byte> bytes, ref int offse
offset = ReadUInt16(bytes.Span[offset + 1], (byte)(bytes.Span[offset] & (1 << 6) - 1));
}

parts.Add(ReadStringSimple(bytes, ref offset));
parts.Add(ReadStringWithLengthPrefix(bytes, ref offset));
}

if (preCompressionOffset.HasValue)
Expand Down Expand Up @@ -171,16 +176,27 @@ public static ArraySegment<byte> Slice(this ArraySegment<byte> buffer, int start
return reader;
}

public static void ToBytes(string value, Memory<byte> buffer, ref int offset)
private static int ToBytesNoLengthPrefix(string value, Memory<byte> buffer, ref int offset)
{
// First write the value 1 byte from the offset to leave room for the length byte
#if NETSTANDARD2_0
var stringBytes = Encoding.ASCII.GetBytes(value);
stringBytes.CopyTo(buffer.Slice(offset + 1, value.Length));
stringBytes.CopyTo(buffer.Slice(offset, value.Length));
var length = stringBytes.Length;
#else
var length = Encoding.ASCII.GetBytes(value, buffer.Slice(offset + 1, value.Length).Span);
var length = Encoding.ASCII.GetBytes(value, buffer.Slice(offset, value.Length).Span);
#endif
// Finally advance the offset past the length and value
offset += length;

return length;
}

public static void ToBytes(string value, Memory<byte> buffer, ref int offset)
{
// First write the value 1 byte from the offset to leave room for the length byte
var offsetPlusOne = offset + 1;
var length = ToBytesNoLengthPrefix(value, buffer, ref offsetPlusOne);


// Then write the length before the value
buffer.Span[offset] = (byte)length;
Expand Down
71 changes: 71 additions & 0 deletions src/Ae.Dns.Protocol/Records/DnsCaaResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Text;

namespace Ae.Dns.Protocol.Records
{
/// <summary>
/// A Certification Authority Authorization (CAA) record is a type of DNS
/// resource record that specifies which certificate authorities (CAs) are
/// allowed to issue certificates for a domain. The CAA record format is
/// specified in RFC 6844.
/// </summary>
public sealed class DnsCaaResource : IDnsResource, IEquatable<DnsCaaResource>
{
/// <summary>
/// Issuer Critical: If set to '1', indicates that the corresponding
/// property tag MUST be understood if the semantics of the CAA record
/// are to be correctly interpreted by an issuer.
/// Issuers MUST NOT issue certificates for a domain if the relevant
/// CAA Resource Record set contains unknown property tags that have
/// the Critical bit set.
/// </summary>
public byte Flag { get; set; }
/// <summary>
/// The property identifier, a sequence of US-ASCII characters.
/// </summary>
public string? Tag { get; set; }
/// <summary>
/// A sequence of octets representing the property value.
/// </summary>
public ReadOnlyMemory<byte> Value { get; set; }

/// <inheritdoc/>
public bool Equals(DnsCaaResource? other)
{
if (other == null)
{
return false;
}

return Equals(Flag, other.Flag) && Equals(Tag, other.Tag) && Value.Span.SequenceEqual(other.Value.Span);
}

/// <inheritdoc/>
public override bool Equals(object? obj) => obj is DnsCaaResource record ? Equals(record) : base.Equals(obj);

/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(Flag, Tag, Value);

/// <inheritdoc/>
public void ReadBytes(ReadOnlyMemory<byte> bytes, ref int offset, int length)
{
var bufferEndPosition = offset + length;
Flag = bytes.Span[offset++];
Tag = DnsByteExtensions.ReadStringWithLengthPrefix(bytes, ref offset);
Value = bytes.Slice(offset, bufferEndPosition - offset);
offset = bufferEndPosition;
}

/// <inheritdoc/>
public override string ToString() => $"{Flag} {Tag} {Encoding.ASCII.GetString(Value.ToArray())}";

/// <inheritdoc/>
public void WriteBytes(Memory<byte> bytes, ref int offset)
{
bytes.Span[offset++] = Flag;
DnsByteExtensions.ToBytes(Tag ?? string.Empty, bytes, ref offset);
Value.CopyTo(bytes.Slice(offset));
offset += Value.Length;
}
}
}
1 change: 1 addition & 0 deletions src/Ae.Dns.Protocol/Records/DnsResourceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static IDnsResource CreateResource(DnsQueryType recordType)
DnsQueryType.OPT => new DnsOptResource(),
DnsQueryType.HTTPS => new DnsServiceBindingResource(),
DnsQueryType.SVCB => new DnsServiceBindingResource(),
DnsQueryType.CAA => new DnsCaaResource(),
_ => new DnsUnknownResource(),
};
}
Expand Down

0 comments on commit 23701ec

Please sign in to comment.