milestone 19: hygiene sweep - dead ecs surface, single-source constants, tls classification, frontend state hazards, docker smoke network fix
CI / test (push) Successful in 1m46s
CI / test-aarch64 (push) Successful in 5m30s
CI / frontend (push) Successful in 46s
CI / cross (push) Successful in 8m12s
CI / docker (push) Successful in 3m46s

This commit is contained in:
2026-08-07 20:39:27 +02:00
parent 6f67940995
commit 6c507992e4
59 changed files with 1020 additions and 382 deletions
+5 -130
View File
@@ -90,59 +90,6 @@ pub fn findOption(packet: []const u8, opt: OptRecord, code: u16) error{BadOption
return null;
}
/// Address families in the EDNS Client Subnet option, from the IANA Address
/// Family Numbers registry.
pub const ecs_family_ipv4: u16 = 1;
pub const ecs_family_ipv6: u16 = 2;
pub const Ecs = struct {
family: u16,
source_prefix: u8,
scope_prefix: u8,
/// The truncated address, `ceil(source_prefix / 8)` bytes, as a slice into
/// the option data.
address: []const u8,
};
pub const EcsError = error{BadEcs};
/// RFC 7871 §6: FAMILY, SOURCE PREFIX-LENGTH, SCOPE PREFIX-LENGTH, then only
/// as many address bytes as the source prefix covers.
pub fn parseEcs(data: []const u8) EcsError!Ecs {
if (data.len < 4) return error.BadEcs;
const family = std.mem.readInt(u16, data[0..2], .big);
const source_prefix = data[2];
const scope_prefix = data[3];
const max_prefix: u16 = switch (family) {
ecs_family_ipv4 => 32,
ecs_family_ipv6 => 128,
// An unknown family has no known address width, so only the encoded
// length can be checked.
else => 255,
};
if (source_prefix > max_prefix) return error.BadEcs;
if (scope_prefix > max_prefix) return error.BadEcs;
// RFC 7871 §6 truncates the address to the source prefix and pads the last
// octet with zero bits, so a prefix of 0 carries no address bytes at all.
const address_len = (@as(usize, source_prefix) + 7) / 8;
if (data.len - 4 != address_len) return error.BadEcs;
const significant_bits: u3 = @intCast(source_prefix % 8);
if (significant_bits != 0) {
const padding_mask = @as(u8, 0xff) >> significant_bits;
if (data[3 + address_len] & padding_mask != 0) return error.BadEcs;
}
return .{
.family = family,
.source_prefix = source_prefix,
.scope_prefix = scope_prefix,
.address = data[4..],
};
}
/// Writes the OPT record: root owner name, type OPT, the payload size in
/// CLASS, the flags in TTL, then the option list verbatim.
pub fn encodeOpt(opt: OptRecord, options_bytes: []const u8, w: *Writer) (Writer.Error || error{OptionsTooLong})!void {
@@ -386,81 +333,6 @@ test "parseOpt rejects a malformed option list" {
try testing.expectError(error.BadOption, parseOpt(partial, rp.record));
}
test "parseEcs reads an IPv4 subnet" {
const ecs = try parseEcs("\x00\x01\x18\x00\xc0\x00\x02");
try testing.expectEqual(ecs_family_ipv4, ecs.family);
try testing.expectEqual(@as(u8, 24), ecs.source_prefix);
try testing.expectEqual(@as(u8, 0), ecs.scope_prefix);
try testing.expectEqualSlices(u8, "\xc0\x00\x02", ecs.address);
}
test "parseEcs reads an IPv6 subnet" {
const ecs = try parseEcs("\x00\x02\x38\x38\x20\x01\x0d\xb8\x00\x00\x00");
try testing.expectEqual(ecs_family_ipv6, ecs.family);
try testing.expectEqual(@as(u8, 56), ecs.source_prefix);
try testing.expectEqual(@as(u8, 56), ecs.scope_prefix);
try testing.expectEqual(@as(usize, 7), ecs.address.len);
}
test "parseEcs reads a zero-length prefix" {
const ecs = try parseEcs("\x00\x01\x00\x00");
try testing.expectEqual(@as(u8, 0), ecs.source_prefix);
try testing.expectEqual(@as(usize, 0), ecs.address.len);
// A prefix of 0 covers no address byte, so any address byte is a length
// mismatch.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x00\x00\x00"));
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x00\x00\xc0\x00\x02\x00"));
}
test "parseEcs rejects nonzero padding bits past the source prefix" {
// IPv4 /25: the low seven bits of the fourth address byte must be zero.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x19\x00\xc0\x00\x02\x01"));
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x19\x00\xc0\x00\x02\xff"));
const zero_padded = try parseEcs("\x00\x01\x19\x00\xc0\x00\x02\x80");
try testing.expectEqual(@as(u8, 25), zero_padded.source_prefix);
try testing.expectEqualSlices(u8, "\xc0\x00\x02\x80", zero_padded.address);
// IPv4 /20: the low four bits of the third address byte must be zero.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x14\x00\xc0\x00\x0f"));
try testing.expectEqualSlices(u8, "\xc0\x00\x00", (try parseEcs("\x00\x01\x14\x00\xc0\x00\x00")).address);
// IPv6 /57: the low seven bits of the eighth address byte must be zero.
try testing.expectError(error.BadEcs, parseEcs("\x00\x02\x39\x00\x20\x01\x0d\xb8\x00\x00\x00\x7f"));
try testing.expectEqualSlices(
u8,
"\x20\x01\x0d\xb8\x00\x00\x00\x80",
(try parseEcs("\x00\x02\x39\x00\x20\x01\x0d\xb8\x00\x00\x00\x80")).address,
);
// An unknown family uses the same encoding, so the rule holds there too.
try testing.expectError(error.BadEcs, parseEcs("\x12\x34\x03\x00\xff"));
try testing.expectEqualSlices(u8, "\xe0", (try parseEcs("\x12\x34\x03\x00\xe0")).address);
}
test "parseEcs rejects malformed options" {
// Shorter than the fixed fields.
try testing.expectError(error.BadEcs, parseEcs(""));
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x18"));
// Prefix wider than the family allows.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x21" ++ "\x00\x00\x00\x00\x00"));
try testing.expectError(error.BadEcs, parseEcs("\x00\x02\x81" ++ "\x00" ** 17));
// Scope wider than the family allows.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x18\x21\xc0\x00\x02"));
// Address shorter than the prefix needs.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x18\x00\xc0\x00"));
// Address longer than the prefix needs.
try testing.expectError(error.BadEcs, parseEcs("\x00\x01\x18\x00\xc0\x00\x02\x00"));
}
test "parseEcs accepts an unknown family with a consistent length" {
const ecs = try parseEcs("\x12\x34\x08\x00\xff");
try testing.expectEqual(@as(u16, 0x1234), ecs.family);
try testing.expectEqualSlices(u8, "\xff", ecs.address);
try testing.expectError(error.BadEcs, parseEcs("\x12\x34\x08\x00\xff\xff"));
}
test "encodeOpt round-trips through record parse and parseOpt" {
const original: OptRecord = .{
.udp_payload_size = 1232,
@@ -485,8 +357,11 @@ test "encodeOpt round-trips through record parse and parseOpt" {
try testing.expectEqual(original.do_bit, opt.do_bit);
try testing.expectEqualSlices(u8, options_bytes, opt.options.slice(bytes));
const ecs = try parseEcs((try findOption(bytes, opt, ecs_option_code)).?.data);
try testing.expectEqual(@as(u8, 24), ecs.source_prefix);
try testing.expectEqualSlices(
u8,
"\x00\x01\x18\x00\xc0\x00\x02",
(try findOption(bytes, opt, ecs_option_code)).?.data,
);
}
test "encodeOpt round-trips both DO states" {