milestone 16: behavioral fixes for silent failures, locks, counters and the query log
CI / test (push) Failing after 11s
CI / test-aarch64 (push) Failing after 2m22s
CI / frontend (push) Successful in 43s
CI / cross (push) Failing after 25s
CI / docker (push) Failing after 24s

This commit is contained in:
2026-08-07 01:54:40 +02:00
parent 5802148887
commit 25455e5ae2
31 changed files with 2054 additions and 297 deletions
+104 -1
View File
@@ -85,13 +85,43 @@ pub fn isComment(line: []const u8) bool {
/// The element-hiding separators, which may also follow a domain list
/// (`example.com##.ad-banner`).
///
/// Where the separator sits decides, because `#` is also the hosts comment
/// marker and a hosts file banner is drawn out of the same two characters. A
/// `##` counts only where an element-hiding rule can put one: at the start of
/// the line with a selector behind it, or straight after the domain list it
/// applies to. `## Title`, `####` and `see ## below` are therefore text, and a
/// hosts file that opens with a banner keeps sniffing as hosts.
///
/// Guarding this with `isComment` instead would decide nothing: `isComment`
/// asks this function.
pub fn isElementHiding(line: []const u8) bool {
for ([_][]const u8{ "##", "#@#", "#?#", "#$#", "#%#" }) |marker| {
if (std.mem.find(u8, line, marker) != null) return true;
var from: usize = 0;
while (std.mem.find(u8, line[from..], marker)) |offset| {
const at = from + offset;
if (separatorStartsRule(line, at, marker.len)) return true;
from = at + 1;
}
}
return false;
}
/// Whether the separator of `marker_len` bytes at `at` is a rule's separator
/// rather than two characters of prose.
fn separatorStartsRule(line: []const u8, at: usize, marker_len: usize) bool {
if (at == 0) {
// A generic rule carries its selector here. A banner carries a space,
// another `#`, or nothing at all.
if (line.len == marker_len) return false;
const after = line[marker_len];
return after != '#' and !std.ascii.isWhitespace(after);
}
// A domain list ends where the separator begins, with no space between.
const before = line[at - 1];
return before != '#' and !std.ascii.isWhitespace(before);
}
fn hasAbpMarker(line: []const u8) bool {
if (std.mem.startsWith(u8, line, "||")) return true;
if (std.mem.startsWith(u8, line, "@@")) return true;
@@ -188,6 +218,79 @@ test "detectFormat is not fooled by a dollar sign in a comment" {
try testing.expectEqual(Format.hosts, detectFormat(sample));
}
/// The banner style a hosts list published for malware URLs opens with: a rule
/// of `#` characters around a titled header block. Every line of it contains
/// `##`, and reading those as element hiding used to sniff the whole file as
/// ABP — which put `0.0.0.0` in the domain set and dropped every hosts line
/// that carried an inline comment.
const urlhaus_banner_sample =
\\################################################################
\\# URLhaus Malicious Hosts File #
\\# Last updated: 2026-08-05 06:05:04 (UTC) #
\\# #
\\# Terms Of Use: https://urlhaus.abuse.ch/api/ #
\\################################################################
\\0.0.0.0 bad1.example.com # https://urlhaus.abuse.ch/url/1/
\\0.0.0.0 bad2.example.net # https://urlhaus.abuse.ch/url/2/
\\0.0.0.0 bad3.example.org # https://urlhaus.abuse.ch/url/3/
\\
;
test "detectFormat reads a hosts file behind a hash banner as hosts" {
try testing.expectEqual(Format.hosts, detectFormat(urlhaus_banner_sample));
// The lines the banner is made of are comments, so the sample the format
// is decided from is the three hosts lines alone.
var it = std.mem.splitScalar(u8, urlhaus_banner_sample, '\n');
while (it.next()) |line| {
if (line.len == 0) continue;
if (line[0] != '#') continue;
try testing.expect(isComment(line));
try testing.expect(!isElementHiding(line));
}
}
test "detectFormat still recognizes a generic element-hiding rule" {
const sample =
\\##.ad-banner
\\example.com
\\
;
try testing.expectEqual(Format.abp, detectFormat(sample));
try testing.expect(isElementHiding("##.ad-banner"));
}
test "detectFormat recognizes element hiding after a domain list" {
const sample =
\\example.com##.ad
\\other.example.net
\\
;
try testing.expectEqual(Format.abp, detectFormat(sample));
try testing.expect(isElementHiding("example.com##.ad"));
}
test "detectFormat recognizes an exception separator after a domain" {
const sample =
\\example.com#@#.sponsored
\\other.example.net
\\
;
try testing.expectEqual(Format.abp, detectFormat(sample));
try testing.expect(isElementHiding("example.com#@#.sponsored"));
}
test "a comment line that mentions a separator stays a comment" {
const line = "# the ##.ad rules live in the other list";
try testing.expect(isComment(line));
try testing.expect(!isElementHiding(line));
// A bare separator and a rule of hashes are text as well.
try testing.expect(!isElementHiding("##"));
try testing.expect(!isElementHiding("####"));
try testing.expect(!isElementHiding("## Title"));
}
test "parseLine dispatches to the hosts parser" {
const line = parseLine(.hosts, "0.0.0.0 ads.example.com");
try testing.expectEqual(Kind.domain, line.kind);