mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
common/helpers: correctly validate netip.Addr/netip.Prefix
validate is only able to validate non-struct types (or recurse inside struct). So, if we want to use "required" on some of them, we need a custom type. Fix #263
This commit is contained in:
@@ -5,6 +5,7 @@ package helpers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -31,6 +32,23 @@ func RegisterSubnetMapValidation[V any]() {
|
|||||||
Validate.RegisterCustomTypeFunc(validatorFunc, zero)
|
Validate.RegisterCustomTypeFunc(validatorFunc, zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// netipValidation validates netip.Addr and netip.Prefix by turning them into a string.
|
||||||
|
func netipValidation(fl reflect.Value) interface{} {
|
||||||
|
switch netipSomething := fl.Interface().(type) {
|
||||||
|
case netip.Addr:
|
||||||
|
if (netipSomething == netip.Addr{}) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return netipSomething.String()
|
||||||
|
case netip.Prefix:
|
||||||
|
if (netipSomething == netip.Prefix{}) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return netipSomething.String()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// isListen validates a <dns>:<port> combination for fields typically used for listening address
|
// isListen validates a <dns>:<port> combination for fields typically used for listening address
|
||||||
func isListen(fl validator.FieldLevel) bool {
|
func isListen(fl validator.FieldLevel) bool {
|
||||||
val := fl.Field().String()
|
val := fl.Field().String()
|
||||||
@@ -53,5 +71,6 @@ func isListen(fl validator.FieldLevel) bool {
|
|||||||
func init() {
|
func init() {
|
||||||
Validate = validator.New()
|
Validate = validator.New()
|
||||||
Validate.RegisterValidation("listen", isListen)
|
Validate.RegisterValidation("listen", isListen)
|
||||||
|
Validate.RegisterCustomTypeFunc(netipValidation, netip.Addr{}, netip.Prefix{})
|
||||||
RegisterSubnetMapValidation[string]()
|
RegisterSubnetMapValidation[string]()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package helpers_test
|
package helpers_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
"akvorado/common/helpers"
|
||||||
@@ -86,3 +87,59 @@ func TestSubnetMapValidator(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNetIPValidation(t *testing.T) {
|
||||||
|
type SomeStruct struct {
|
||||||
|
Src netip.Addr `validate:"required"`
|
||||||
|
DstNet netip.Prefix `validate:"required"`
|
||||||
|
Nothing netip.Addr `validate:"isdefault"`
|
||||||
|
}
|
||||||
|
cases := []struct {
|
||||||
|
Description string
|
||||||
|
Value interface{}
|
||||||
|
Error bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Description: "Valid SomeStruct",
|
||||||
|
Value: SomeStruct{
|
||||||
|
Src: netip.MustParseAddr("203.0.113.14"),
|
||||||
|
DstNet: netip.MustParsePrefix("203.0.113.0/24"),
|
||||||
|
Nothing: netip.Addr{},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Description: "Missing netip.Addr",
|
||||||
|
Value: SomeStruct{
|
||||||
|
Src: netip.Addr{},
|
||||||
|
DstNet: netip.MustParsePrefix("203.0.113.0/24"),
|
||||||
|
Nothing: netip.Addr{},
|
||||||
|
},
|
||||||
|
Error: true,
|
||||||
|
}, {
|
||||||
|
Description: "Missing netip.Prefix",
|
||||||
|
Value: SomeStruct{
|
||||||
|
Src: netip.MustParseAddr("203.0.113.14"),
|
||||||
|
DstNet: netip.Prefix{},
|
||||||
|
Nothing: netip.Addr{},
|
||||||
|
},
|
||||||
|
Error: true,
|
||||||
|
}, {
|
||||||
|
Description: "Non-default netip.Addr",
|
||||||
|
Value: SomeStruct{
|
||||||
|
Src: netip.MustParseAddr("203.0.113.14"),
|
||||||
|
DstNet: netip.MustParsePrefix("203.0.113.0/24"),
|
||||||
|
Nothing: netip.MustParseAddr("2001:db8::1"),
|
||||||
|
},
|
||||||
|
Error: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.Description, func(t *testing.T) {
|
||||||
|
err := helpers.Validate.Struct(tc.Value)
|
||||||
|
if err != nil && !tc.Error {
|
||||||
|
t.Fatalf("Validate() error:\n%+v", err)
|
||||||
|
} else if err == nil && tc.Error {
|
||||||
|
t.Fatal("Validate() did not error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package flows
|
package flows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -19,6 +20,8 @@ func TestDefaultConfiguration(t *testing.T) {
|
|||||||
OutIfIndex: []int{2},
|
OutIfIndex: []int{2},
|
||||||
PeakHour: 21 * time.Hour,
|
PeakHour: 21 * time.Hour,
|
||||||
Multiplier: 3.0,
|
Multiplier: 3.0,
|
||||||
|
SrcNet: netip.MustParsePrefix("2001:db8:1::/64"),
|
||||||
|
DstNet: netip.MustParsePrefix("2001:db8:2::/64"),
|
||||||
SrcAS: []uint32{2906},
|
SrcAS: []uint32{2906},
|
||||||
DstAS: []uint32{12322},
|
DstAS: []uint32{12322},
|
||||||
SrcPort: []uint16{443},
|
SrcPort: []uint16{443},
|
||||||
|
|||||||
Reference in New Issue
Block a user