milestone 16: behavioral fixes for silent failures, locks, counters and the query log
This commit is contained in:
Vendored
+28
@@ -103,8 +103,15 @@ pub const Class = struct {
|
||||
///
|
||||
/// `negative_ttl_max == 0` disables negative caching outright: the response is
|
||||
/// not stored at all (milestone-6 ruling 6).
|
||||
///
|
||||
/// A TC=1 response is never cached, whatever its rcode. It is a partial message
|
||||
/// whose tail the sender dropped, and RFC 2181 §9 forbids keeping one: served
|
||||
/// from the cache the TC bit reaches a client that has no truncation to recover
|
||||
/// from, and a client that retries over TCP is answered with the same truncated
|
||||
/// bytes again.
|
||||
pub fn classify(response: []const u8, negative_ttl_max: u32) ?Class {
|
||||
const p = packet.parse(response) catch return null;
|
||||
if (p.header.flags.tc) return null;
|
||||
const rcode = p.header.flags.rcode;
|
||||
|
||||
if (rcode == .no_error and p.header.ancount > 0) {
|
||||
@@ -643,6 +650,27 @@ test "classify refuses a zero ttl and unparsable bytes" {
|
||||
try testing.expectEqual(@as(?Class, null), classify(response[0 .. response.len - 1], 3600));
|
||||
}
|
||||
|
||||
/// The TC bit is bit 9 of the flags word, which is the second 16-bit word of
|
||||
/// the header.
|
||||
fn setTruncated(bytes: []u8) []u8 {
|
||||
const flags = std.mem.readInt(u16, bytes[2..4], .big);
|
||||
std.mem.writeInt(u16, bytes[2..4], flags | 0x0200, .big);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
test "classify refuses a truncated response whatever its rcode" {
|
||||
var buf: [512]u8 = undefined;
|
||||
const answer = try buildAnswer(&buf, &.{300});
|
||||
try testing.expectEqual(@as(u32, 300), classify(answer, 3600).?.ttl_seconds);
|
||||
try testing.expectEqual(@as(?Class, null), classify(setTruncated(answer), 3600));
|
||||
|
||||
// The negative path reads the same bit: a truncated NXDOMAIN is a partial
|
||||
// message too.
|
||||
var nx_buf: [nxdomain_bytes.len]u8 = undefined;
|
||||
@memcpy(&nx_buf, nxdomain_bytes);
|
||||
try testing.expectEqual(@as(?Class, null), classify(setTruncated(&nx_buf), 3600));
|
||||
}
|
||||
|
||||
test "classify caches NXDOMAIN with the SOA minimum" {
|
||||
const class = classify(nxdomain_bytes, 3600).?;
|
||||
try testing.expectEqual(@as(u32, 600), class.ttl_seconds);
|
||||
|
||||
Reference in New Issue
Block a user