2 Commits
Author SHA1 Message Date
clawbot 11a6f5a60a Read a blocked_networks entry in the IPv4-mapped form as its IPv4 range (closes #301)
check / check (push) Canceled after 0s
The fetcher matches an IPv4-mapped address (::ffff:a.b.c.d) as the
IPv4 address it holds, so a blocked_networks entry written in that form
was accepted and matched nothing. Such an entry is now kept as the IPv4
range it covers: ::ffff:10.0.0.0/104 becomes 10.0.0.0/8. One shorter
than /96 covers more than IPv4 addresses and aborts startup naming the
setting. trusted_proxies shares the list parser and is unchanged.
README.md says both.

Model: opus-5-5
2026-10-19 00:31:43 +00:00
clawbot 9c47f11fd6 Test that a blocked_networks entry in the IPv4-mapped form is read as its IPv4 range
Two new tests, failing until the fix. Entries such as
::ffff:10.0.0.0/104 and ::ffff:0:0/96 must load as 10.0.0.0/8 and
0.0.0.0/0, since the fetcher matches an IPv4-mapped address as the IPv4
address it holds. An entry in that form shorter than /96, such as
::ffff:0:0/95, must abort startup naming blocked_networks.

Model: opus-5-5
2026-10-19 00:31:43 +00:00
@@ -92,25 +92,29 @@ func TestBlockedNetworksInvalidAbortsStartup(t *testing.T) {
// TestBlockedNetworksMappedEntryIsIPv4Range checks that an entry written in // TestBlockedNetworksMappedEntryIsIPv4Range checks that an entry written in
// the IPv4-mapped form (::ffff:a.b.c.d) is kept as the IPv4 range it covers, // the IPv4-mapped form (::ffff:a.b.c.d) is kept as the IPv4 range it covers,
// since the fetcher matches an IPv4-mapped address as the IPv4 address it // since the fetcher matches an IPv4-mapped address as the IPv4 address it
// holds. // holds. /96, the shortest such entry, covers every IPv4 address.
func TestBlockedNetworksMappedEntryIsIPv4Range(t *testing.T) { func TestBlockedNetworksMappedEntryIsIPv4Range(t *testing.T) {
t.Parallel() t.Parallel()
yamlContent := signingKeyLine + `blocked_networks: yamlContent := signingKeyLine + `blocked_networks:
- "::ffff:10.0.0.0/104" - "::ffff:10.0.0.0/104"
- "::ffff:0:0/96"
` `
c, err := configFromYAML(t, yamlContent) c, err := configFromYAML(t, yamlContent)
if err != nil { if err != nil {
t.Fatalf("an IPv4-mapped blocked_networks entry should load, got error: %v", err) t.Fatalf("IPv4-mapped blocked_networks entries should load, got error: %v", err)
} }
if len(c.BlockedNetworks) != 1 { want := []string{"10.0.0.0/8", "0.0.0.0/0"}
t.Fatalf("BlockedNetworks = %v, want 1 entry", c.BlockedNetworks) if len(c.BlockedNetworks) != len(want) {
t.Fatalf("BlockedNetworks = %v, want %d entries", c.BlockedNetworks, len(want))
} }
if got := c.BlockedNetworks[0].String(); got != "10.0.0.0/8" { for i, w := range want {
t.Errorf("BlockedNetworks[0] = %q, want %q", got, "10.0.0.0/8") if got := c.BlockedNetworks[i].String(); got != w {
t.Errorf("BlockedNetworks[%d] = %q, want %q", i, got, w)
}
} }
} }
@@ -128,5 +132,12 @@ func TestBlockedNetworksMappedEntryShorterThan96AbortsStartup(t *testing.T) {
`, `,
wantErrSubstrings: []string{keyBlockedNetworks, "::ffff:0.0.0.0/80"}, wantErrSubstrings: []string{keyBlockedNetworks, "::ffff:0.0.0.0/80"},
}, },
{
name: "mapped-95",
yaml: signingKeyLine + `blocked_networks:
- "::ffff:0:0/95"
`,
wantErrSubstrings: []string{keyBlockedNetworks},
},
}) })
} }