package config import ( "github.com/go-playground/validator/v10" "log" "net" "strings" ) var v = validator.New() func init() { if err := v.RegisterValidation("iface", func(fl validator.FieldLevel) bool { name, ok := fl.Field().Interface().(string) if ok && name != "" { ifaces, err := net.Interfaces() if err != nil { log.Printf("error getting interfaces: %v", err) return false } for _, i := range ifaces { if i.Name == name { return true } } } return false }); err != nil { panic(err) } } type Configuration struct { Host Host Peers []Peer `validate:"dive"` } type Host struct { Crypto string `validate:"required,oneof=None Blake2s"` SharedKey string `validate:"required_if=Crypto Blake2s"` MTU uint `validate:"required,min=576"` } type Peer struct { Method string `validate:"oneof=TCP UDP"` LocalHost string `validate:"omitempty,ip|iface"` LocalPort uint `validate:"max=65535"` RemoteHost string `validate:"required_with=RemotePort,omitempty,fqdn|ip"` RemotePort uint `validate:"required_with=RemoteHost,omitempty,max=65535"` Congestion string `validate:"required_unless=Method TCP,omitempty,oneof=NewReno None"` KeepAlive uint Timeout uint RetryWait uint } func (p Peer) GetLocalHost() string { if p.LocalHost == "" { return "" } if err := v.Var(p.LocalHost, "ip"); err == nil { return p.LocalHost } iface, err := net.InterfaceByName(p.LocalHost) if err != nil { panic(err) } if iface != nil { addrs, err := iface.Addrs() if err != nil { panic(err) } if len(addrs) > 0 { addr := addrs[0].String() addr = strings.Split(addr, "/")[0] log.Printf("resolved interface `%s` to `%v`", p.LocalHost, addr) return addr } } return "invalid" } func (c Configuration) Validate() error { return v.Struct(c) }