Delete a forwarded opening the way ufw accepts it, and read a fresh machine's resolver as not in use — both measured on a lab machine (hq ADR 0100)

This commit is contained in:
2026-09-22 17:37:01 +02:00
parent 5e3dd3f59c
commit 3e0e6e6b7e
9 changed files with 699 additions and 17 deletions
+93 -2
View File
@@ -180,9 +180,17 @@ func (f *fakeUFW) run(_ context.Context, name string, args ...string) (string, e
case args[0] == "disable":
f.active = false
return "Firewall stopped and disabled on system startup\n", nil
case args[0] == "delete":
case args[0] == "delete" && len(args) > 1 && args[1] == "route":
// As the real ufw answers it (captured in testdata/ufw-delete.txt): a route rule is
// deleted with `route delete`, never `delete route`.
return "", errors.New("ERROR: Invalid syntax")
case args[0] == "delete", args[0] == "route" && len(args) > 1 && args[1] == "delete":
rest := args[1:]
if args[0] == "route" {
rest = append([]string{"route"}, args[2:]...)
}
for i, r := range f.rules {
if strings.Join(words(r), "\x00") == strings.Join(args[1:], "\x00") {
if strings.Join(words(r), "\x00") == strings.Join(rest, "\x00") {
f.rules = append(f.rules[:i], f.rules[i+1:]...)
return "Rule deleted\n", nil
}
@@ -333,3 +341,86 @@ func TestDetectingTheFoundFirewall(t *testing.T) {
}
}
}
// The fixtures below were captured from a real ufw 0.36.2 on a lab machine, not written by hand:
// ufw prints a rule back in its own shorter form, so the mark in the comment is the only thing the
// host relies on.
func TestTheMarksAreReadFromWhatUfwReallyPrints(t *testing.T) {
raw, err := os.ReadFile("testdata/ufw-show-added.txt")
if err != nil {
t.Fatal(err)
}
run := func(ctx context.Context, name string, args ...string) (string, error) { return string(raw), nil }
rules, err := added(context.Background(), run)
if err != nil {
t.Fatal(err)
}
if len(rules) != 7 {
t.Fatalf("read %d rules, want 7: %q", len(rules), rules)
}
marked := 0
for _, r := range rules {
if strings.HasPrefix(comment(r), "mesh-host ") {
marked++
}
}
if marked != 5 {
t.Errorf("read %d marked rules, want 5", marked)
}
if !markedFor(comment(rules[5]), "adoption.opening-tcp-8443-forwarded") {
t.Errorf("the forwarded rule from the mesh lost its mark: %q", rules[5])
}
}
func TestEveryRealRuleIsDeletedInTheFormUfwAccepts(t *testing.T) {
raw, err := os.ReadFile("testdata/ufw-show-added.txt")
if err != nil {
t.Fatal(err)
}
run := func(ctx context.Context, name string, args ...string) (string, error) { return string(raw), nil }
rules, _ := added(context.Background(), run)
// Each of these was run on the lab machine and answered "Rule deleted" (testdata/ufw-delete.txt).
want := map[string]string{
"allow 5671/tcp comment 'mesh-host adoption.opening-tcp-5671-incoming 1a2b3c4d'": "delete allow 5671/tcp comment|mesh-host adoption.opening-tcp-5671-incoming 1a2b3c4d",
"allow in on mesh0 to any port 5432 proto tcp comment 'mesh-host adoption.opening-tcp-5432-incoming deadbeef'": "delete allow in on mesh0 to any port 5432 proto tcp comment|mesh-host adoption.opening-tcp-5432-incoming deadbeef",
"route allow 80/tcp comment 'mesh-host adoption.opening-tcp-8081-forwarded 0badf00d'": "route delete allow 80/tcp comment|mesh-host adoption.opening-tcp-8081-forwarded 0badf00d",
"route allow in on mesh0 to any port 443 proto tcp comment 'mesh-host adoption.opening-tcp-8443-forwarded cafe0001'": "route delete allow in on mesh0 to any port 443 proto tcp comment|mesh-host adoption.opening-tcp-8443-forwarded cafe0001",
}
seen := 0
for _, r := range rules {
w, ok := want[r]
if !ok {
continue
}
seen++
d := deletion(r)
got := strings.Join(d[:len(d)-1], " ") + "|" + d[len(d)-1]
if got != w {
t.Errorf("deleting %q\n got %s\n want %s", r, got, w)
}
}
if seen != len(want) {
t.Errorf("matched %d of %d captured rules", seen, len(want))
}
}
func TestARealUfwRulesetIsUfw(t *testing.T) {
raw, err := os.ReadFile("testdata/ufw-active.nft")
if err != nil {
t.Fatal(err)
}
status, err := os.ReadFile("testdata/ufw-status-active.txt")
if err != nil {
t.Fatal(err)
}
if !statusActive(string(status)) {
t.Fatal("the captured status does not read as active")
}
if refusing := Refusing(string(raw), true); len(refusing) > 0 {
t.Errorf("a machine with ufw active and nothing else read as refusing in %v", refusing)
}
if refusing := Refusing(string(raw), false); len(refusing) == 0 {
t.Error("ufw's drop chains, with ufw not known to be active, read as refusing nothing")
}
}