package render import ( "context" "os" "os/exec" "strings" "testing" "housecarl/internal/model" ) func TestFallback(t *testing.T) { st := router() text := Fallback(st) for _, want := range []string{ "delete table inet housecarl", "type filter hook input priority filter; policy accept;", `iifname "wan" counter drop comment "hc:fallback-input"`, `iifname "wan" counter drop comment "hc:fallback-forward"`, `iifname "wan" ip6 saddr fe80::/10 udp dport 546 counter accept`, `ip6 hoplimit 255 counter accept`, `oifname "wan" tcp flags syn tcp option maxseg size set rt mtu`, `meta nfproto ipv4 oifname "wan" counter masquerade comment "hc:fallback-masquerade"`, } { if !strings.Contains(text, want) { t.Errorf("no %q in\n%s", want, text) } } // Nothing that could fail to load before the network is up. for _, not := range []string{"flowtable", "@", "\tset ", "enp2s0", "wg0"} { if strings.Contains(text, not) { t.Errorf("%q in the fallback:\n%s", not, text) } } // Established connections are accepted before the drops. if strings.Index(text, "ct state established,related accept") > strings.Index(text, "hc:fallback-input") { t.Errorf("established after the drop:\n%s", text) } // No source NAT: no masquerade. st.SNATs = nil if text := Fallback(st); strings.Contains(text, "masquerade") { t.Errorf("masquerade without source NAT:\n%s", text) } // No external zone: everything but loopback is dropped. for _, z := range st.Zones { z.External = false } text = Fallback(st) if strings.Count(text, "policy drop;") != 2 || strings.Contains(text, "policy accept") || strings.Contains(text, "established") { t.Errorf("no external zone:\n%s", text) } } func TestFallbackPassesNft(t *testing.T) { cmd := strings.Fields(os.Getenv("HOUSECARL_NFT")) if len(cmd) == 0 { t.Skip("HOUSECARL_NFT not set") } closed := router() for _, z := range closed.Zones { z.External = false } wild := router() wild.Zones = append(wild.Zones, &model.Zone{ID: 99, Name: "lte", Interfaces: []string{"wwan*"}, External: true}) for name, st := range map[string]*model.State{"router": router(), "closed": closed, "wildcard": wild} { c := exec.CommandContext(context.Background(), cmd[0], append(cmd[1:], "-c", "-f", "/dev/stdin")...) c.Stdin = strings.NewReader(Fallback(st)) if out, err := c.CombinedOutput(); err != nil { t.Errorf("%s: nft -c: %v\n%s\n%s", name, err, out, Fallback(st)) } } }