mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-12 03:28:45 +00:00
239 lines
4.3 KiB
Go
239 lines
4.3 KiB
Go
package remoteaddress
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/netip"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/TecharoHQ/anubis/internal"
|
|
"github.com/TecharoHQ/anubis/lib/checker"
|
|
"github.com/TecharoHQ/anubis/lib/policy"
|
|
"github.com/TecharoHQ/anubis/lib/policy/config"
|
|
"github.com/gaissmai/bart"
|
|
)
|
|
|
|
func TestFactoryIsCheckerFactory(t *testing.T) {
|
|
if _, ok := (any(Factory{})).(checker.Factory); !ok {
|
|
t.Fatal("Factory is not an instance of checker.Factory")
|
|
}
|
|
}
|
|
|
|
func TestFactoryValidateConfig(t *testing.T) {
|
|
f := Factory{}
|
|
|
|
for _, tt := range []struct {
|
|
name string
|
|
data []byte
|
|
err error
|
|
}{
|
|
{
|
|
name: "basic valid",
|
|
data: []byte(`{
|
|
"remote_addresses": [
|
|
"1.1.1.1/32"
|
|
]
|
|
}`),
|
|
},
|
|
{
|
|
name: "not json",
|
|
data: []byte(`]`),
|
|
err: config.ErrUnparseableConfig,
|
|
},
|
|
{
|
|
name: "no cidr",
|
|
data: []byte(`{
|
|
"remote_addresses": []
|
|
}`),
|
|
err: ErrNoRemoteAddresses,
|
|
},
|
|
{
|
|
name: "bad cidr",
|
|
data: []byte(`{
|
|
"remote_addresses": [
|
|
"according to all laws of aviation"
|
|
]
|
|
}`),
|
|
err: config.ErrInvalidCIDR,
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data := json.RawMessage(tt.data)
|
|
|
|
if err := f.ValidateConfig(data); !errors.Is(err, tt.err) {
|
|
t.Logf("want: %v", tt.err)
|
|
t.Logf("got: %v", err)
|
|
t.Fatal("validation didn't do what was expected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFactoryCreate(t *testing.T) {
|
|
f := Factory{}
|
|
|
|
for _, tt := range []struct {
|
|
name string
|
|
data []byte
|
|
err error
|
|
ip string
|
|
match bool
|
|
}{
|
|
{
|
|
name: "basic valid",
|
|
data: []byte(`{
|
|
"remote_addresses": [
|
|
"1.1.1.1/32"
|
|
]
|
|
}`),
|
|
ip: "1.1.1.1",
|
|
match: true,
|
|
},
|
|
{
|
|
name: "bad cidr",
|
|
data: []byte(`{
|
|
"remote_addresses": [
|
|
"according to all laws of aviation"
|
|
]
|
|
}`),
|
|
err: config.ErrUnparseableConfig,
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data := json.RawMessage(tt.data)
|
|
|
|
impl, err := f.Create(data)
|
|
if !errors.Is(err, tt.err) {
|
|
t.Logf("want: %v", tt.err)
|
|
t.Logf("got: %v", err)
|
|
t.Fatal("creation didn't do what was expected")
|
|
}
|
|
|
|
if tt.err != nil {
|
|
return
|
|
}
|
|
|
|
r, err := http.NewRequest(http.MethodGet, "/", nil)
|
|
if err != nil {
|
|
t.Fatalf("can't make request: %v", err)
|
|
}
|
|
|
|
if tt.ip != "" {
|
|
r.Header.Add("X-Real-Ip", tt.ip)
|
|
}
|
|
|
|
match, err := impl.Check(r)
|
|
|
|
if tt.match != match {
|
|
t.Errorf("match: %v, wanted: %v", match, tt.match)
|
|
}
|
|
|
|
if err != nil && tt.err != nil && !errors.Is(err, tt.err) {
|
|
t.Errorf("err: %v, wanted: %v", err, tt.err)
|
|
}
|
|
|
|
if impl.Hash() == "" {
|
|
t.Error("hash method returns empty string")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func racFromCidrs(t *testing.T, inp []string) *Impl {
|
|
t.Helper()
|
|
|
|
var result Impl
|
|
result.prefixTable = new(bart.Lite)
|
|
result.hash = internal.FastHash(strings.Join(inp, ","))
|
|
|
|
for _, cidr := range inp {
|
|
pfx, err := netip.ParsePrefix(cidr)
|
|
if err != nil {
|
|
t.Errorf("prefix %q is invalid: %v", cidr, err)
|
|
continue
|
|
}
|
|
|
|
result.prefixTable.Insert(pfx)
|
|
}
|
|
|
|
return &result
|
|
}
|
|
|
|
func TestRemoteAddrChecker(t *testing.T) {
|
|
for _, tt := range []struct {
|
|
err error
|
|
name string
|
|
ip string
|
|
cidrs []string
|
|
ok bool
|
|
}{
|
|
{
|
|
name: "match_ipv4",
|
|
cidrs: []string{"0.0.0.0/0"},
|
|
ip: "1.1.1.1",
|
|
ok: true,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "match_ipv6",
|
|
cidrs: []string{"::/0"},
|
|
ip: "cafe:babe::",
|
|
ok: true,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "not_match_ipv4",
|
|
cidrs: []string{"1.1.1.1/32"},
|
|
ip: "1.1.1.2",
|
|
ok: false,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "not_match_ipv6",
|
|
cidrs: []string{"cafe:babe::/128"},
|
|
ip: "cafe:babe:4::/128",
|
|
ok: false,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "no_ip_set",
|
|
cidrs: []string{"::/0"},
|
|
ok: false,
|
|
err: policy.ErrMisconfiguration,
|
|
},
|
|
{
|
|
name: "invalid_ip",
|
|
cidrs: []string{"::/0"},
|
|
ip: "According to all natural laws of aviation",
|
|
ok: false,
|
|
err: policy.ErrMisconfiguration,
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
rac := racFromCidrs(t, tt.cidrs)
|
|
|
|
r, err := http.NewRequest(http.MethodGet, "/", nil)
|
|
if err != nil {
|
|
t.Fatalf("can't make request: %v", err)
|
|
}
|
|
|
|
if tt.ip != "" {
|
|
r.Header.Add("X-Real-Ip", tt.ip)
|
|
}
|
|
|
|
ok, err := rac.Check(r)
|
|
|
|
if tt.ok != ok {
|
|
t.Errorf("ok: %v, wanted: %v", ok, tt.ok)
|
|
}
|
|
|
|
if err != nil && tt.err != nil && !errors.Is(err, tt.err) {
|
|
t.Errorf("err: %v, wanted: %v", err, tt.err)
|
|
}
|
|
})
|
|
}
|
|
}
|