package firewall import ( "net/netip" "testing" "git.wntrmute.dev/kyle/mc-proxy/internal/config" ) func TestEmptyFirewall(t *testing.T) { fw, err := New(config.Firewall{}) if err != nil { t.Fatalf("unexpected error: %v", err) } defer fw.Close() addrs := []string{"192.168.1.1", "10.0.0.1", "::1", "2001:db8::1"} for _, a := range addrs { addr := netip.MustParseAddr(a) if fw.Blocked(addr) { t.Fatalf("empty firewall blocked %s", addr) } } } func TestIPBlocking(t *testing.T) { fw, err := New(config.Firewall{ BlockedIPs: []string{"192.0.2.1", "2001:db8::dead"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } defer fw.Close() tests := []struct { addr string blocked bool }{ {"192.0.2.1", true}, {"192.0.2.2", false}, {"2001:db8::dead", true}, {"2001:db8::beef", false}, } for _, tt := range tests { addr := netip.MustParseAddr(tt.addr) if got := fw.Blocked(addr); got != tt.blocked { t.Fatalf("Blocked(%s) = %v, want %v", tt.addr, got, tt.blocked) } } } func TestCIDRBlocking(t *testing.T) { fw, err := New(config.Firewall{ BlockedCIDRs: []string{"198.51.100.0/24", "2001:db8::/32"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } defer fw.Close() tests := []struct { addr string blocked bool }{ {"198.51.100.1", true}, {"198.51.100.254", true}, {"198.51.101.1", false}, {"2001:db8::1", true}, {"2001:db9::1", false}, } for _, tt := range tests { addr := netip.MustParseAddr(tt.addr) if got := fw.Blocked(addr); got != tt.blocked { t.Fatalf("Blocked(%s) = %v, want %v", tt.addr, got, tt.blocked) } } } func TestIPv4MappedIPv6(t *testing.T) { fw, err := New(config.Firewall{ BlockedIPs: []string{"192.0.2.1"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } defer fw.Close() // IPv4-mapped IPv6 representation of 192.0.2.1. addr := netip.MustParseAddr("::ffff:192.0.2.1") if !fw.Blocked(addr) { t.Fatal("expected IPv4-mapped IPv6 address to be blocked") } } func TestInvalidIP(t *testing.T) { _, err := New(config.Firewall{ BlockedIPs: []string{"not-an-ip"}, }) if err == nil { t.Fatal("expected error for invalid IP") } } func TestInvalidCIDR(t *testing.T) { _, err := New(config.Firewall{ BlockedCIDRs: []string{"not-a-cidr"}, }) if err == nil { t.Fatal("expected error for invalid CIDR") } } func TestCombinedRules(t *testing.T) { fw, err := New(config.Firewall{ BlockedIPs: []string{"10.0.0.1"}, BlockedCIDRs: []string{"192.168.0.0/16"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } defer fw.Close() tests := []struct { addr string blocked bool }{ {"10.0.0.1", true}, // IP match {"10.0.0.2", false}, // no match {"192.168.1.1", true}, // CIDR match {"172.16.0.1", false}, // no match } for _, tt := range tests { addr := netip.MustParseAddr(tt.addr) if got := fw.Blocked(addr); got != tt.blocked { t.Fatalf("Blocked(%s) = %v, want %v", tt.addr, got, tt.blocked) } } }