diff --git a/cmd/main.go b/cmd/main.go index 8760cbd..4d488d1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,6 +9,7 @@ import ( "time" "golang.org/x/exp/slog" + "nfsense.net/nfsense/pkg/definitions" "nfsense.net/nfsense/pkg/jsonrpc" "nfsense.net/nfsense/pkg/server" ) @@ -27,6 +28,14 @@ func main() { slog.Info("Config Loaded", "config", conf) + err = definitions.ValidateConfig(conf) + if err != nil { + slog.Error("Validating Config", err) + os.Exit(1) + } + + slog.Info("Validating Config") + if *applyPtr { slog.Info("Applying Config...") err := apply(conf) diff --git a/go.mod b/go.mod index f25b83d..ba80e2c 100644 --- a/go.mod +++ b/go.mod @@ -9,4 +9,13 @@ require ( nhooyr.io/websocket v1.8.7 ) -require github.com/klauspost/compress v1.10.3 // indirect +require ( + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/klauspost/compress v1.10.3 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect +) diff --git a/go.sum b/go.sum index d9ac8a3..3dda176 100644 --- a/go.sum +++ b/go.sum @@ -7,10 +7,16 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= @@ -33,6 +39,8 @@ github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eT github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= @@ -43,17 +51,24 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -61,5 +76,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/pkg/definitions/address.go b/pkg/definitions/address.go index d5be589..9394a2f 100644 --- a/pkg/definitions/address.go +++ b/pkg/definitions/address.go @@ -8,11 +8,11 @@ import ( ) type Address struct { - Type AddressType `json:"type"` + Type AddressType `json:"type" validate:"min=0,max=3"` Comment string `json:"comment,omitempty"` - Host *netip.Addr `json:"host,omitempty"` - Range *netipx.IPRange `json:"range,omitempty"` - Network *IPNet `json:"network,omitempty"` + Host *netip.Addr `json:"host,omitempty" validate:"excluded_unless=Type 0"` + Range *netipx.IPRange `json:"range,omitempty" validate:"excluded_unless=Type 1"` + Network *IPNet `json:"network,omitempty" validate:"excluded_unless=Type 2"` Children *[]string `json:"children,omitempty"` } diff --git a/pkg/definitions/config.go b/pkg/definitions/config.go index 8674a65..f1faa7a 100644 --- a/pkg/definitions/config.go +++ b/pkg/definitions/config.go @@ -1,6 +1,37 @@ package definitions +import ( + "fmt" + + "github.com/go-playground/validator/v10" + "golang.org/x/exp/slog" +) + type Config struct { - ConfigVersion uint64 `json:"config_version"` - Firewall Firewall `json:"firewall"` + ConfigVersion uint64 `json:"config_version" validate:"required,eq=1"` + Firewall Firewall `json:"firewall" validate:"required,dive"` +} + +func ValidateConfig(conf *Config) error { + val := validator.New() + slog.Info("Registering validator") + val.RegisterValidation("test", nilIfOtherNil) + return val.Struct(conf) +} + +func nilIfOtherNil(fl validator.FieldLevel) bool { + slog.Info("Start", "field", fl.FieldName(), "param", fl.Param()) + if !fl.Field().IsNil() { + slog.Info("Field is not nil", "field", fl.FieldName()) + f := fl.Parent().FieldByName(fl.Param()) + if f.IsZero() { + panic(fmt.Errorf("Param %v is not a Valid Field", fl.Param())) + } + if !f.IsNil() { + slog.Info("Fail", "field", fl.FieldName(), "param", fl.Param()) + return false + } + } + slog.Info("Success", "field", fl.FieldName(), "param", fl.Param()) + return true } diff --git a/pkg/definitions/firewall.go b/pkg/definitions/firewall.go index d1bfcca..c5c695d 100644 --- a/pkg/definitions/firewall.go +++ b/pkg/definitions/firewall.go @@ -1,9 +1,9 @@ package definitions type Firewall struct { - ForwardRules []ForwardRule `json:"forward_rules"` - DestinationNATRules []DestinationNATRule `json:"destination_nat_rules"` - SourceNATRules []SourceNATRule `json:"source_nat_rules"` - Addresses map[string]Address `json:"addresses"` - Services map[string]Service `json:"services"` + ForwardRules []ForwardRule `json:"forward_rules" validate:"required,dive"` + DestinationNATRules []DestinationNATRule `json:"destination_nat_rules" validate:"required,dive"` + SourceNATRules []SourceNATRule `json:"source_nat_rules" validate:"required,dive"` + Addresses map[string]Address `json:"addresses" validate:"required,dive"` + Services map[string]Service `json:"services" validate:"required,dive"` } diff --git a/pkg/definitions/rule.go b/pkg/definitions/rule.go index 65ae33a..18e07e4 100644 --- a/pkg/definitions/rule.go +++ b/pkg/definitions/rule.go @@ -3,15 +3,15 @@ package definitions import "encoding/json" type Rule struct { - Name string `json:"name"` - Match Match `json:"match"` + Name string `json:"name" validate:"required"` + Match Match `json:"match" validate:"required,dive"` Comment string `json:"comment,omitempty"` Counter bool `json:"counter,omitempty"` } type ForwardRule struct { Rule - Verdict Verdict `json:"verdict"` + Verdict Verdict `json:"verdict" validate:"min=0,max=2"` } type Verdict int diff --git a/pkg/definitions/service.go b/pkg/definitions/service.go index bf8f1d5..7a0ede0 100644 --- a/pkg/definitions/service.go +++ b/pkg/definitions/service.go @@ -6,13 +6,13 @@ import ( ) type Service struct { - Type ServiceType `json:"type"` + Type ServiceType `json:"type" validate:"min=0,max=3"` Comment string `json:"comment,omitempty"` - SPortStart *uint32 `json:"sport_start,omitempty"` + SPortStart *uint32 `json:"sport_start,omitempty" validate:"excluded_unless=Type 0|excluded_unless=Type 1"` SPortEnd *uint32 `json:"sport_end,omitempty"` - DPortStart *uint32 `json:"dport_start,omitempty"` + DPortStart *uint32 `json:"dport_start,omitempty" validate:"excluded_unless=Type 0|excluded_unless=Type 1"` DPortEnd *uint32 `json:"dport_end,omitempty"` - ICMPCode *uint32 `json:"icmp_code,omitempty"` + ICMPCode *uint32 `json:"icmp_code,omitempty" validate:"excluded_unless=Type 2"` Children *[]string `json:"children,omitempty"` } diff --git a/pkg/definitions/source_nat.go b/pkg/definitions/source_nat.go index 5678b29..ce1ad61 100644 --- a/pkg/definitions/source_nat.go +++ b/pkg/definitions/source_nat.go @@ -4,7 +4,7 @@ import "encoding/json" type SourceNATRule struct { Rule - Type SnatType `json:"type"` + Type SnatType `json:"type" validate:"min=0,max=1"` Address string `json:"address,omitempty"` Service string `json:"service,omitempty"` }