Skip to content

Commit 316ad66

Browse files
committed
Calculated ttl rework. Updated unit tests after PR merge #30
Reorganized testing zone files
1 parent fc057d5 commit 316ad66

11 files changed

Lines changed: 840 additions & 883 deletions

File tree

src/DnsClient/DnsMessageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
6767
writer.WriteHostName("");
6868
writer.WriteUInt16NetworkOrder((ushort)opt.RecordType);
6969
writer.WriteUInt16NetworkOrder((ushort)opt.RecordClass);
70-
writer.WriteUInt32NetworkOrder((ushort)opt.TimeToLive);
70+
writer.WriteUInt32NetworkOrder((ushort)opt.InitialTimeToLive);
7171
writer.WriteUInt16NetworkOrder(0);
7272
}
7373

src/DnsClient/DnsRecordFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ private DnsResourceRecord ResolveUriRecord(ResourceRecordInfo info)
173173

174174
private DnsResourceRecord ResolveOptRecord(ResourceRecordInfo info)
175175
{
176-
return new OptRecord((int)info.RecordClass, info.TimeToLive, info.RawDataLength);
176+
return new OptRecord((int)info.RecordClass, info.InitialTimeToLive, info.RawDataLength);
177177
}
178178

179179
private DnsResourceRecord ResolveWksRecord(ResourceRecordInfo info)

src/DnsClient/Protocol/DnsResourceRecord.cs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public DnsResourceRecord(ResourceRecordInfo info)
1818
info?.DomainName ?? throw new ArgumentNullException(nameof(info)),
1919
info?.RecordType ?? throw new ArgumentNullException(nameof(info)),
2020
info?.RecordClass ?? throw new ArgumentNullException(nameof(info)),
21-
info?.TimeToLive ?? throw new ArgumentNullException(nameof(info)),
21+
info?.InitialTimeToLive ?? throw new ArgumentNullException(nameof(info)),
2222
info?.RawDataLength ?? throw new ArgumentNullException(nameof(info)))
2323
{
2424
}
@@ -46,12 +46,6 @@ public virtual string ToString(int offset = 0)
4646
RecordToString());
4747
}
4848

49-
/// <inheritdoc />
50-
public DnsResourceRecord Clone()
51-
{
52-
return (DnsResourceRecord)MemberwiseClone();
53-
}
54-
5549
/// <summary>
5650
/// Returns a string representation of the record's value only.
5751
/// <see cref="ToString(int)"/> uses this to compose the full string value of this instance.
@@ -65,6 +59,8 @@ public DnsResourceRecord Clone()
6559
/// </summary>
6660
public class ResourceRecordInfo
6761
{
62+
private readonly int _ticks;
63+
6864
/// <summary>
6965
/// The domain name used to query.
7066
/// </summary>
@@ -81,9 +77,27 @@ public class ResourceRecordInfo
8177
public QueryClass RecordClass { get; }
8278

8379
/// <summary>
84-
/// The TTL value for the record set by the server.
80+
/// Gets the current time to live value for the record.
81+
/// </summary>
82+
public int TimeToLive
83+
{
84+
get
85+
{
86+
var curTicks = Environment.TickCount & int.MaxValue;
87+
if (curTicks < _ticks)
88+
{
89+
return 0;
90+
}
91+
92+
var ttl = InitialTimeToLive - ((curTicks - _ticks) / 1000);
93+
return ttl < 0 ? 0 : ttl;
94+
}
95+
}
96+
97+
/// <summary>
98+
/// Gets or sets the original time to live returned from the server.
8599
/// </summary>
86-
public int TimeToLive { get; internal set; }
100+
public int InitialTimeToLive { get; internal set; }
87101

88102
/// <summary>
89103
/// Gets the number of bytes for this resource record stored in RDATA
@@ -118,8 +132,9 @@ public ResourceRecordInfo(DnsString domainName, ResourceRecordType recordType, Q
118132
DomainName = domainName ?? throw new ArgumentNullException(nameof(domainName));
119133
RecordType = recordType;
120134
RecordClass = recordClass;
121-
TimeToLive = timeToLive;
122135
RawDataLength = rawDataLength;
136+
InitialTimeToLive = timeToLive;
137+
_ticks = Environment.TickCount;
123138
}
124139
}
125140
}

src/DnsClient/Protocol/Options/OptRecord.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ public DnsResponseCode ResponseCodeEx
7676
{
7777
get
7878
{
79-
return (DnsResponseCode)((TimeToLive & ResponseCodeMask) >> ResponseCodeShift);
79+
return (DnsResponseCode)((InitialTimeToLive & ResponseCodeMask) >> ResponseCodeShift);
8080
}
8181
set
8282
{
83-
TimeToLive &= (int)~ResponseCodeMask;
84-
TimeToLive |= (int)(((int)value << ResponseCodeShift) & ResponseCodeMask);
83+
InitialTimeToLive &= (int)~ResponseCodeMask;
84+
InitialTimeToLive |= (int)(((int)value << ResponseCodeShift) & ResponseCodeMask);
8585
}
8686
}
8787

@@ -94,27 +94,27 @@ public byte Version
9494
{
9595
get
9696
{
97-
return (byte)((TimeToLive & VersionMask) >> VersionShift);
97+
return (byte)((InitialTimeToLive & VersionMask) >> VersionShift);
9898
}
9999
set
100100
{
101-
TimeToLive = (int)((uint)TimeToLive & ~VersionMask);
102-
TimeToLive |= (int)((value << VersionShift) & VersionMask);
101+
InitialTimeToLive = (int)((uint)InitialTimeToLive & ~VersionMask);
102+
InitialTimeToLive |= (int)((value << VersionShift) & VersionMask);
103103
}
104104
}
105105

106106
public bool IsDnsSecOk
107107
{
108-
get { return (TimeToLive & 0x8000) != 0; }
108+
get { return (InitialTimeToLive & 0x8000) != 0; }
109109
set
110110
{
111111
if (value)
112112
{
113-
TimeToLive |= 0x8000;
113+
InitialTimeToLive |= 0x8000;
114114
}
115115
else
116116
{
117-
TimeToLive &= 0x7fff;
117+
InitialTimeToLive &= 0x7fff;
118118
}
119119
}
120120
}

src/DnsClient/ResponseCache.cs

Lines changed: 4 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public IDnsQueryResponse Get(string key, out double? effectiveTtl)
8181
else
8282
{
8383
StartCleanup();
84-
return entry.GetResponse();
84+
return entry.Response;
8585
}
8686
}
8787

@@ -97,7 +97,7 @@ public bool Add(string key, IDnsQueryResponse response)
9797
if (all.Any())
9898
{
9999
// in millis
100-
double minTtl = all.Min(p => p.TimeToLive) * 1000d;
100+
double minTtl = all.Min(p => p.InitialTimeToLive) * 1000d;
101101

102102
if (MinimumTimout == Timeout.InfiniteTimeSpan)
103103
{
@@ -171,8 +171,6 @@ private void StartCleanup()
171171

172172
private class ResponseEntry
173173
{
174-
private readonly IDnsQueryResponse _response;
175-
176174
public bool IsExpiredFor(DateTimeOffset forDate) => forDate >= ExpiresAt;
177175

178176
public DateTimeOffset ExpiresAt { get; }
@@ -181,73 +179,14 @@ private class ResponseEntry
181179

182180
public double TTL { get; set; }
183181

184-
// returns in seconds, not MS!
185-
public int Elapsed(DateTimeOffset? since = null)
186-
{
187-
if (since == null)
188-
{
189-
since = DateTimeOffset.UtcNow;
190-
}
191-
192-
var elapsedMillis = (int)(since.Value - Created).TotalMilliseconds;
193-
if (elapsedMillis < 0)
194-
{
195-
return 0;
196-
}
197-
198-
return elapsedMillis / 1000;
199-
}
200-
201-
public IDnsQueryResponse GetResponse()
202-
{
203-
var elapsed = Elapsed();
204-
if (elapsed <= 0)
205-
{
206-
return _response;
207-
}
208-
209-
var response = new DnsResponseMessage(_response.Header, _response.MessageSize)
210-
{
211-
Audit = (_response as DnsQueryResponse)?.Audit ?? new LookupClientAudit()
212-
};
213-
214-
foreach (var record in _response.Questions)
215-
{
216-
response.AddQuestion(record);
217-
}
218-
219-
foreach (var record in _response.Answers)
220-
{
221-
var clone = record.Clone();
222-
clone.TimeToLive = clone.TimeToLive - elapsed;
223-
response.AddAnswer(clone);
224-
}
225-
226-
foreach (var record in _response.Additionals)
227-
{
228-
var clone = record.Clone();
229-
clone.TimeToLive = clone.TimeToLive - elapsed;
230-
response.AddAnswer(clone);
231-
}
232-
233-
foreach (var record in _response.Authorities)
234-
{
235-
var clone = record.Clone();
236-
clone.TimeToLive = clone.TimeToLive - elapsed;
237-
response.AddAnswer(clone);
238-
}
239-
240-
var qr = response.AsQueryResponse(_response.NameServer);
241-
242-
return qr;
243-
}
182+
public IDnsQueryResponse Response { get; }
244183

245184
public ResponseEntry(IDnsQueryResponse response, double ttlInMS)
246185
{
247186
Debug.Assert(response != null);
248187
Debug.Assert(ttlInMS >= 0);
249188

250-
_response = response;
189+
Response = response;
251190
TTL = ttlInMS;
252191
Created = DateTimeOffset.UtcNow;
253192
ExpiresAt = Created.AddMilliseconds(TTL);

test/DnsClient.Tests/DnsMessageHandlerTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public void DnsRecordFactory_ResolveARecord()
3636
Assert.Equal(4, resultAnswer.RawDataLength);
3737
Assert.Equal(QueryClass.IN, resultAnswer.RecordClass);
3838
Assert.Equal(ResourceRecordType.A, resultAnswer.RecordType);
39-
Assert.True(resultAnswer.TimeToLive == 100);
39+
Assert.True(resultAnswer.InitialTimeToLive == 100);
4040
Assert.True(result.Header.Id == 42);
4141
Assert.True(result.Header.AnswerCount == 1);
4242
}
@@ -60,7 +60,7 @@ private static byte[] GetResponseBytes(DnsQueryResponse message, byte[] answerDa
6060
writer.WriteHostName(answer.DomainName.Value);
6161
writer.WriteUInt16NetworkOrder((ushort)answer.RecordType);
6262
writer.WriteUInt16NetworkOrder((ushort)answer.RecordClass);
63-
writer.WriteUInt32NetworkOrder((uint)answer.TimeToLive);
63+
writer.WriteUInt32NetworkOrder((uint)answer.InitialTimeToLive);
6464
writer.WriteUInt16NetworkOrder((ushort)answerData.Length);
6565

6666
//writer.Extend(answerData.Length); // the following data->length

test/DnsClient.Tests/DnsResponseParsingTest.cs

Lines changed: 18 additions & 69 deletions
Large diffs are not rendered by default.

test/DnsClient.Tests/ResponseCacheTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public async Task Cache_DoesCacheWithMinimumDefined()
4848
{
4949
var minTtl = 2000;
5050
var cache = new ResponseCache(true, TimeSpan.FromMilliseconds(minTtl));
51-
var record = new EmptyRecord(new ResourceRecordInfo("a", ResourceRecordType.A, QueryClass.IN, 0, 100));
51+
var record = new EmptyRecord(new ResourceRecordInfo("a", ResourceRecordType.A, QueryClass.IN, 1, 100));
5252
var response = new DnsResponseMessage(new DnsResponseHeader(1, 256, 1, 1, 0, 0), 0)
5353
{
5454
Audit = new LookupClientAudit()
@@ -57,12 +57,12 @@ public async Task Cache_DoesCacheWithMinimumDefined()
5757

5858
cache.Add("key", response.AsQueryResponse(new NameServer(IPAddress.Any)));
5959

60-
await Task.Delay(1000);
60+
await Task.Delay(1200);
6161
var item = cache.Get("key", out double? effectiveTtl);
6262

6363
// should not be null although TTL is zero, mimimum timeout is set to 2000ms
64-
// TTL of the record should be negative because the initial TTL is 0
65-
Assert.True(item.Answers.First().TimeToLive < 0);
64+
// TTL of the record should be zero because the initial TTL is 100
65+
Assert.Equal(0, item.Answers.First().TimeToLive);
6666
Assert.Equal(minTtl, effectiveTtl);
6767
}
6868

tools/etc/named.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,10 @@ zone "mcnet.com" IN {
4545
file "db.192.168.178.txt";
4646
allow-transfer {192.168.178.1; localhost;};
4747
};
48+
49+
zone "generated.com" IN {
50+
type master;
51+
file "10.0.x.txt";
52+
allow-transfer {192.168.178.1; localhost;};
53+
};
54+

0 commit comments

Comments
 (0)