Skip to content

Commit

Permalink
Fixes bug in DnsCachingClient when identifying the lowest TTL entry.
Browse files Browse the repository at this point in the history
  • Loading branch information
alanedwardes committed Jul 30, 2023
1 parent a8533cb commit aae6136
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Ae.Dns.Client/DnsCachingClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private class DnsCacheEntry
{
public DnsCacheEntry(DnsMessage answer)
{
var allRecords = new[] { answer.Answers, answer.Nameservers };
var allRecords = new[] { answer.Answers, answer.Nameservers, answer.Additional };

LowestRecordTimeToLive = TimeSpan.FromSeconds(allRecords.SelectMany(x => x).Min(x => x.TimeToLive));
Data = DnsByteExtensions.AllocateAndWrite(answer);
Expand Down
66 changes: 66 additions & 0 deletions tests/Ae.Dns.Tests/Client/DnsCachingClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Ae.Dns.Client;
using Ae.Dns.Protocol;
using Ae.Dns.Protocol.Enums;
using Ae.Dns.Protocol.Records;
using Moq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.Caching;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Ae.Dns.Tests.Client
{
public sealed class DnsCachingClientTests : IDisposable
{
private readonly MockRepository _repository = new MockRepository(MockBehavior.Strict);

public void Dispose() => _repository.VerifyAll();

[Fact]
public async Task TestCacheEntryWithOnlyAdditionalRecords()
{
var mockClient = _repository.Create<IDnsClient>();

var query1 = DnsQueryFactory.CreateQuery("example.com", DnsQueryType.A);

// query1 will be passed through to the inner client
mockClient.Setup(x => x.Query(query1, CancellationToken.None))
.ReturnsAsync(new DnsMessage
{
Additional = new List<DnsResourceRecord>
{
// This is an unrealistic example
new DnsResourceRecord
{
Host = "example.com",
Type = DnsQueryType.A,
Resource = new DnsIpAddressResource{IPAddress = IPAddress.Loopback},
TimeToLive = 5
}
},
Header = new DnsHeader { AdditionalRecordCount = 1, Id = query1.Header.Id }
});

using var cache = new MemoryCache("wibble");

IDnsClient client = new DnsCachingClient(mockClient.Object, cache);

Assert.Empty(cache);

var answer1 = await client.Query(query1, CancellationToken.None);

Assert.Equal(query1.Header.Id, answer1.Header.Id);
Assert.Single(cache);

// Will be served from the cache
var query2 = DnsQueryFactory.CreateQuery("example.com", DnsQueryType.A);
var answer2 = await client.Query(query2, CancellationToken.None);

Assert.Equal(query2.Header.Id, answer2.Header.Id);
Assert.Single(cache);
}
}
}

0 comments on commit aae6136

Please sign in to comment.