diff --git a/go.mod b/go.mod index 820f5f9..32aad00 100644 --- a/go.mod +++ b/go.mod @@ -11,14 +11,14 @@ require ( github.com/glebarez/sqlite v1.11.0 github.com/go-ldap/ldap/v3 v3.4.8 github.com/prometheus-community/pro-bing v0.4.1 - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/swaggo/swag v1.16.3 github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca github.com/vardius/message-bus v1.1.5 - github.com/vishvananda/netlink v1.1.0 + github.com/vishvananda/netlink v1.3.0 github.com/xhit/go-simple-mail/v2 v2.16.0 github.com/yeqown/go-qrcode/v2 v2.2.4 golang.org/x/crypto v0.28.0 diff --git a/go.sum b/go.sum index 21885c9..7996776 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus-community/pro-bing v0.4.1 h1:aMaJwyifHZO0y+h8+icUz0xbToHbia0wdmzdVZ+Kl3w= github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= @@ -281,9 +281,8 @@ github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca h1:lpvAjPK+PcxnbcB github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca/go.mod h1:XXKxNbpoLihvvT7orUZbs/iZayg1n4ip7iJakJPAwA8= github.com/vardius/message-bus v1.1.5 h1:YSAC2WB4HRlwc4neFPTmT88kzzoiQ+9WRRbej/E/LZc= github.com/vardius/message-bus v1.1.5/go.mod h1:6xladCV2lMkUAE4bzzS85qKOiB5miV7aBVRafiTJGqw= -github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= +github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= @@ -337,7 +336,6 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -345,9 +343,11 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/adapters/wireguard.go b/internal/adapters/wireguard.go index c6dd54d..9978d46 100644 --- a/internal/adapters/wireguard.go +++ b/internal/adapters/wireguard.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" + "os" + "github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/lowlevel" "github.com/vishvananda/netlink" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - "os" ) // WgRepo implements all low-level WireGuard interactions. @@ -74,7 +75,11 @@ func (r *WgRepo) GetPeers(_ context.Context, deviceId domain.InterfaceIdentifier return peers, nil } -func (r *WgRepo) GetPeer(_ context.Context, deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier) (*domain.PhysicalPeer, error) { +func (r *WgRepo) GetPeer( + _ context.Context, + deviceId domain.InterfaceIdentifier, + id domain.PeerIdentifier, +) (*domain.PhysicalPeer, error) { return r.getPeer(deviceId, id) } @@ -90,7 +95,7 @@ func (r *WgRepo) convertWireGuardInterface(device *wgtypes.Device) (domain.Physi ListenPort: device.ListenPort, Addresses: nil, Mtu: 0, - FirewallMark: int32(device.FirewallMark), + FirewallMark: uint32(device.FirewallMark), DeviceUp: false, ImportSource: "wgctrl", DeviceType: device.Type.String(), @@ -151,7 +156,11 @@ func (r *WgRepo) convertWireGuardPeer(peer *wgtypes.Peer) (domain.PhysicalPeer, return peerModel, nil } -func (r *WgRepo) SaveInterface(_ context.Context, id domain.InterfaceIdentifier, updateFunc func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error)) error { +func (r *WgRepo) SaveInterface( + _ context.Context, + id domain.InterfaceIdentifier, + updateFunc func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error), +) error { physicalInterface, err := r.getOrCreateInterface(id) if err != nil { return err @@ -324,7 +333,12 @@ func (r *WgRepo) deleteLowLevelInterface(id domain.InterfaceIdentifier) error { return nil } -func (r *WgRepo) SavePeer(_ context.Context, deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier, updateFunc func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error)) error { +func (r *WgRepo) SavePeer( + _ context.Context, + deviceId domain.InterfaceIdentifier, + id domain.PeerIdentifier, + updateFunc func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error), +) error { physicalPeer, err := r.getOrCreatePeer(deviceId, id) if err != nil { return err @@ -342,7 +356,10 @@ func (r *WgRepo) SavePeer(_ context.Context, deviceId domain.InterfaceIdentifier return nil } -func (r *WgRepo) getOrCreatePeer(deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier) (*domain.PhysicalPeer, error) { +func (r *WgRepo) getOrCreatePeer(deviceId domain.InterfaceIdentifier, id domain.PeerIdentifier) ( + *domain.PhysicalPeer, + error, +) { peer, err := r.getPeer(deviceId, id) if err == nil { return peer, nil @@ -352,9 +369,13 @@ func (r *WgRepo) getOrCreatePeer(deviceId domain.InterfaceIdentifier, id domain. } // create new peer - err = r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{Peers: []wgtypes.PeerConfig{{ - PublicKey: id.ToPublicKey(), - }}}) + err = r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{ + Peers: []wgtypes.PeerConfig{ + { + PublicKey: id.ToPublicKey(), + }, + }, + }) peer, err = r.getPeer(deviceId, id) return peer, nil diff --git a/internal/app/api/v0/model/model_options.go b/internal/app/api/v0/model/model_options.go index b0be72f..a884f79 100644 --- a/internal/app/api/v0/model/model_options.go +++ b/internal/app/api/v0/model/model_options.go @@ -5,132 +5,42 @@ import ( "github.com/h44z/wg-portal/internal/domain" ) -type StringConfigOption struct { - Value string `json:"Value"` - Overridable bool `json:"Overridable"` +type ConfigOption[T any] struct { + Value T `json:"Value"` + Overridable bool `json:"Overridable"` } -func NewStringConfigOption(value string, overridable bool) StringConfigOption { - return StringConfigOption{ +func NewConfigOption[T any](value T, overridable bool) ConfigOption[T] { + return ConfigOption[T]{ Value: value, Overridable: overridable, } } -func StringConfigOptionFromDomain(opt domain.StringConfigOption) StringConfigOption { - return StringConfigOption{ +func ConfigOptionFromDomain[T any](opt domain.ConfigOption[T]) ConfigOption[T] { + return ConfigOption[T]{ Value: opt.Value, Overridable: opt.Overridable, } } -func StringConfigOptionToDomain(opt StringConfigOption) domain.StringConfigOption { - return domain.StringConfigOption{ +func ConfigOptionToDomain[T any](opt ConfigOption[T]) domain.ConfigOption[T] { + return domain.ConfigOption[T]{ Value: opt.Value, Overridable: opt.Overridable, } } -type StringSliceConfigOption struct { - Value []string `json:"Value"` - Overridable bool `json:"Overridable"` -} - -func NewStringSliceConfigOption(value []string, overridable bool) StringSliceConfigOption { - return StringSliceConfigOption{ - Value: value, - Overridable: overridable, - } -} - -func StringSliceConfigOptionFromDomain(opt domain.StringConfigOption) StringSliceConfigOption { - return StringSliceConfigOption{ +func StringSliceConfigOptionFromDomain(opt domain.ConfigOption[string]) ConfigOption[[]string] { + return ConfigOption[[]string]{ Value: internal.SliceString(opt.Value), Overridable: opt.Overridable, } } -func StringSliceConfigOptionToDomain(opt StringSliceConfigOption) domain.StringConfigOption { - return domain.StringConfigOption{ +func StringSliceConfigOptionToDomain(opt ConfigOption[[]string]) domain.ConfigOption[string] { + return domain.ConfigOption[string]{ Value: internal.SliceToString(opt.Value), Overridable: opt.Overridable, } } - -type IntConfigOption struct { - Value int `json:"Value"` - Overridable bool `json:"Overridable"` -} - -func NewIntConfigOption(value int, overridable bool) IntConfigOption { - return IntConfigOption{ - Value: value, - Overridable: overridable, - } -} - -func IntConfigOptionFromDomain(opt domain.IntConfigOption) IntConfigOption { - return IntConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} - -func IntConfigOptionToDomain(opt IntConfigOption) domain.IntConfigOption { - return domain.IntConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} - -type Int32ConfigOption struct { - Value int32 `json:"Value"` - Overridable bool `json:"Overridable"` -} - -func NewInt32ConfigOption(value int32, overridable bool) Int32ConfigOption { - return Int32ConfigOption{ - Value: value, - Overridable: overridable, - } -} - -func Int32ConfigOptionFromDomain(opt domain.Int32ConfigOption) Int32ConfigOption { - return Int32ConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} - -func Int32ConfigOptionToDomain(opt Int32ConfigOption) domain.Int32ConfigOption { - return domain.Int32ConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} - -type BoolConfigOption struct { - Value bool `json:"Value"` - Overridable bool `json:"Overridable"` -} - -func NewBoolConfigOption(value bool, overridable bool) BoolConfigOption { - return BoolConfigOption{ - Value: value, - Overridable: overridable, - } -} - -func BoolConfigOptionFromDomain(opt domain.BoolConfigOption) BoolConfigOption { - return BoolConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} - -func BoolConfigOptionToDomain(opt BoolConfigOption) domain.BoolConfigOption { - return domain.BoolConfigOption{ - Value: opt.Value, - Overridable: opt.Overridable, - } -} diff --git a/internal/app/api/v0/model/models_interface.go b/internal/app/api/v0/model/models_interface.go index 5755304..aef336d 100644 --- a/internal/app/api/v0/model/models_interface.go +++ b/internal/app/api/v0/model/models_interface.go @@ -1,9 +1,10 @@ package model import ( - "github.com/h44z/wg-portal/internal" "time" + "github.com/h44z/wg-portal/internal" + "github.com/h44z/wg-portal/internal/domain" ) @@ -22,7 +23,7 @@ type Interface struct { Dns []string `json:"Dns"` // the dns server that should be set if the interface is up, comma separated DnsSearch []string `json:"DnsSearch"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr Mtu int `json:"Mtu"` // the device MTU - FirewallMark int32 `json:"FirewallMark"` // a firewall mark + FirewallMark uint32 `json:"FirewallMark"` // a firewall mark RoutingTable string `json:"RoutingTable"` // the routing table PreUp string `json:"PreUp"` // action that is executed before the device is up @@ -37,7 +38,7 @@ type Interface struct { PeerDefAllowedIPs []string `json:"PeerDefAllowedIPs"` // the default allowed IP string for the peer PeerDefMtu int `json:"PeerDefMtu"` // the default device MTU PeerDefPersistentKeepalive int `json:"PeerDefPersistentKeepalive"` // the default persistent keep-alive Value - PeerDefFirewallMark int32 `json:"PeerDefFirewallMark"` // default firewall mark + PeerDefFirewallMark uint32 `json:"PeerDefFirewallMark"` // default firewall mark PeerDefRoutingTable string `json:"PeerDefRoutingTable"` // the default routing table PeerDefPreUp string `json:"PeerDefPreUp"` // default action that is executed before the device is up diff --git a/internal/app/api/v0/model/models_peer.go b/internal/app/api/v0/model/models_peer.go index 50f2640..aca304d 100644 --- a/internal/app/api/v0/model/models_peer.go +++ b/internal/app/api/v0/model/models_peer.go @@ -1,9 +1,10 @@ package model import ( + "time" + "github.com/h44z/wg-portal/internal" "github.com/h44z/wg-portal/internal/domain" - "time" ) const ExpiryDateTimeLayout = "\"2006-01-02\"" @@ -48,30 +49,30 @@ type Peer struct { ExpiresAt ExpiryDate `json:"ExpiresAt,omitempty"` // expiry dates for peers Notes string `json:"Notes"` // a note field for peers - Endpoint StringConfigOption `json:"Endpoint"` // the endpoint address - EndpointPublicKey StringConfigOption `json:"EndpointPublicKey"` // the endpoint public key - AllowedIPs StringSliceConfigOption `json:"AllowedIPs"` // all allowed ip subnets, comma seperated - ExtraAllowedIPs []string `json:"ExtraAllowedIPs"` // all allowed ip subnets on the server side, comma seperated - PresharedKey string `json:"PresharedKey"` // the pre-shared Key of the peer - PersistentKeepalive IntConfigOption `json:"PersistentKeepalive"` // the persistent keep-alive interval + Endpoint ConfigOption[string] `json:"Endpoint"` // the endpoint address + EndpointPublicKey ConfigOption[string] `json:"EndpointPublicKey"` // the endpoint public key + AllowedIPs ConfigOption[[]string] `json:"AllowedIPs"` // all allowed ip subnets, comma seperated + ExtraAllowedIPs []string `json:"ExtraAllowedIPs"` // all allowed ip subnets on the server side, comma seperated + PresharedKey string `json:"PresharedKey"` // the pre-shared Key of the peer + PersistentKeepalive ConfigOption[int] `json:"PersistentKeepalive"` // the persistent keep-alive interval PrivateKey string `json:"PrivateKey" example:"abcdef=="` // private Key of the server peer PublicKey string `json:"PublicKey" example:"abcdef=="` // public Key of the server peer Mode string // the peer interface type (server, client, any) - Addresses []string `json:"Addresses"` // the interface ip addresses - CheckAliveAddress string `json:"CheckAliveAddress"` // optional ip address or DNS name that is used for ping checks - Dns StringSliceConfigOption `json:"Dns"` // the dns server that should be set if the interface is up, comma separated - DnsSearch StringSliceConfigOption `json:"DnsSearch"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr - Mtu IntConfigOption `json:"Mtu"` // the device MTU - FirewallMark Int32ConfigOption `json:"FirewallMark"` // a firewall mark - RoutingTable StringConfigOption `json:"RoutingTable"` // the routing table + Addresses []string `json:"Addresses"` // the interface ip addresses + CheckAliveAddress string `json:"CheckAliveAddress"` // optional ip address or DNS name that is used for ping checks + Dns ConfigOption[[]string] `json:"Dns"` // the dns server that should be set if the interface is up, comma separated + DnsSearch ConfigOption[[]string] `json:"DnsSearch"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr + Mtu ConfigOption[int] `json:"Mtu"` // the device MTU + FirewallMark ConfigOption[uint32] `json:"FirewallMark"` // a firewall mark + RoutingTable ConfigOption[string] `json:"RoutingTable"` // the routing table - PreUp StringConfigOption `json:"PreUp"` // action that is executed before the device is up - PostUp StringConfigOption `json:"PostUp"` // action that is executed after the device is up - PreDown StringConfigOption `json:"PreDown"` // action that is executed before the device is down - PostDown StringConfigOption `json:"PostDown"` // action that is executed after the device is down + PreUp ConfigOption[string] `json:"PreUp"` // action that is executed before the device is up + PostUp ConfigOption[string] `json:"PostUp"` // action that is executed after the device is up + PreDown ConfigOption[string] `json:"PreDown"` // action that is executed before the device is down + PostDown ConfigOption[string] `json:"PostDown"` // action that is executed after the device is down } func NewPeer(src *domain.Peer) *Peer { @@ -84,12 +85,12 @@ func NewPeer(src *domain.Peer) *Peer { DisabledReason: src.DisabledReason, ExpiresAt: ExpiryDate{src.ExpiresAt}, Notes: src.Notes, - Endpoint: StringConfigOptionFromDomain(src.Endpoint), - EndpointPublicKey: StringConfigOptionFromDomain(src.EndpointPublicKey), + Endpoint: ConfigOptionFromDomain(src.Endpoint), + EndpointPublicKey: ConfigOptionFromDomain(src.EndpointPublicKey), AllowedIPs: StringSliceConfigOptionFromDomain(src.AllowedIPsStr), ExtraAllowedIPs: internal.SliceString(src.ExtraAllowedIPsStr), PresharedKey: string(src.PresharedKey), - PersistentKeepalive: IntConfigOptionFromDomain(src.PersistentKeepalive), + PersistentKeepalive: ConfigOptionFromDomain(src.PersistentKeepalive), PrivateKey: src.Interface.PrivateKey, PublicKey: src.Interface.PublicKey, Mode: string(src.Interface.Type), @@ -97,13 +98,13 @@ func NewPeer(src *domain.Peer) *Peer { CheckAliveAddress: src.Interface.CheckAliveAddress, Dns: StringSliceConfigOptionFromDomain(src.Interface.DnsStr), DnsSearch: StringSliceConfigOptionFromDomain(src.Interface.DnsSearchStr), - Mtu: IntConfigOptionFromDomain(src.Interface.Mtu), - FirewallMark: Int32ConfigOptionFromDomain(src.Interface.FirewallMark), - RoutingTable: StringConfigOptionFromDomain(src.Interface.RoutingTable), - PreUp: StringConfigOptionFromDomain(src.Interface.PreUp), - PostUp: StringConfigOptionFromDomain(src.Interface.PostUp), - PreDown: StringConfigOptionFromDomain(src.Interface.PreDown), - PostDown: StringConfigOptionFromDomain(src.Interface.PostDown), + Mtu: ConfigOptionFromDomain(src.Interface.Mtu), + FirewallMark: ConfigOptionFromDomain(src.Interface.FirewallMark), + RoutingTable: ConfigOptionFromDomain(src.Interface.RoutingTable), + PreUp: ConfigOptionFromDomain(src.Interface.PreUp), + PostUp: ConfigOptionFromDomain(src.Interface.PostUp), + PreDown: ConfigOptionFromDomain(src.Interface.PreDown), + PostDown: ConfigOptionFromDomain(src.Interface.PostDown), } } @@ -123,12 +124,12 @@ func NewDomainPeer(src *Peer) *domain.Peer { res := &domain.Peer{ BaseModel: domain.BaseModel{}, - Endpoint: StringConfigOptionToDomain(src.Endpoint), - EndpointPublicKey: StringConfigOptionToDomain(src.EndpointPublicKey), + Endpoint: ConfigOptionToDomain(src.Endpoint), + EndpointPublicKey: ConfigOptionToDomain(src.EndpointPublicKey), AllowedIPsStr: StringSliceConfigOptionToDomain(src.AllowedIPs), ExtraAllowedIPsStr: internal.SliceToString(src.ExtraAllowedIPs), PresharedKey: domain.PreSharedKey(src.PresharedKey), - PersistentKeepalive: IntConfigOptionToDomain(src.PersistentKeepalive), + PersistentKeepalive: ConfigOptionToDomain(src.PersistentKeepalive), DisplayName: src.DisplayName, Identifier: domain.PeerIdentifier(src.Identifier), UserIdentifier: domain.UserIdentifier(src.UserIdentifier), @@ -147,13 +148,13 @@ func NewDomainPeer(src *Peer) *domain.Peer { CheckAliveAddress: src.CheckAliveAddress, DnsStr: StringSliceConfigOptionToDomain(src.Dns), DnsSearchStr: StringSliceConfigOptionToDomain(src.DnsSearch), - Mtu: IntConfigOptionToDomain(src.Mtu), - FirewallMark: Int32ConfigOptionToDomain(src.FirewallMark), - RoutingTable: StringConfigOptionToDomain(src.RoutingTable), - PreUp: StringConfigOptionToDomain(src.PreUp), - PostUp: StringConfigOptionToDomain(src.PostUp), - PreDown: StringConfigOptionToDomain(src.PreDown), - PostDown: StringConfigOptionToDomain(src.PostDown), + Mtu: ConfigOptionToDomain(src.Mtu), + FirewallMark: ConfigOptionToDomain(src.FirewallMark), + RoutingTable: ConfigOptionToDomain(src.RoutingTable), + PreUp: ConfigOptionToDomain(src.PreUp), + PostUp: ConfigOptionToDomain(src.PostUp), + PreDown: ConfigOptionToDomain(src.PreDown), + PostDown: ConfigOptionToDomain(src.PostDown), }, } diff --git a/internal/app/migrate_v1.go b/internal/app/migrate_v1.go index 3251f18..e5ca6b4 100644 --- a/internal/app/migrate_v1.go +++ b/internal/app/migrate_v1.go @@ -3,13 +3,14 @@ package app import ( "errors" "fmt" + "os" + "time" + "github.com/h44z/wg-portal/internal/adapters" "github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/domain" "github.com/sirupsen/logrus" "gorm.io/gorm" - "os" - "time" ) func migrateFromV1(cfg *config.Config, db *gorm.DB, source, typ string) error { @@ -137,7 +138,7 @@ func migrateV1Interfaces(oldDb, newDb *gorm.DB) error { DisplayName string PrivateKey string ListenPort int - FirewallMark int32 + FirewallMark uint32 PublicKey string Mtu int IPsStr string @@ -288,7 +289,8 @@ func migrateV1Peers(oldDb, newDb *gorm.DB) error { ifaceType = domain.InterfaceTypeAny } var user domain.User - err = newDb.First(&user, "identifier = ?", oldPeer.Email).Error // migrated users use the email address as identifier + err = newDb.First(&user, "identifier = ?", + oldPeer.Email).Error // migrated users use the email address as identifier if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("failed to find user %s for peer %s: %w", oldPeer.Email, oldPeer.PublicKey, err) } @@ -325,20 +327,12 @@ func migrateV1Peers(oldDb, newDb *gorm.DB) error { CreatedAt: oldPeer.CreatedAt, UpdatedAt: oldPeer.UpdatedAt, }, - Endpoint: domain.StringConfigOption{ - Value: oldPeer.Endpoint, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - EndpointPublicKey: domain.StringConfigOption{ - Value: iface.PublicKey, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - AllowedIPsStr: domain.StringConfigOption{ - Value: oldPeer.AllowedIPsStr, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - ExtraAllowedIPsStr: oldPeer.AllowedIPsSrvStr, - PresharedKey: domain.PreSharedKey(oldPeer.PresharedKey), - PersistentKeepalive: domain.IntConfigOption{ - Value: oldPeer.PersistentKeepalive, Overridable: !oldPeer.IgnoreGlobalSettings, - }, + Endpoint: domain.NewConfigOption(oldPeer.Endpoint, !oldPeer.IgnoreGlobalSettings), + EndpointPublicKey: domain.NewConfigOption(iface.PublicKey, !oldPeer.IgnoreGlobalSettings), + AllowedIPsStr: domain.NewConfigOption(oldPeer.AllowedIPsStr, !oldPeer.IgnoreGlobalSettings), + ExtraAllowedIPsStr: oldPeer.AllowedIPsSrvStr, + PresharedKey: domain.PreSharedKey(oldPeer.PresharedKey), + PersistentKeepalive: domain.NewConfigOption(oldPeer.PersistentKeepalive, !oldPeer.IgnoreGlobalSettings), DisplayName: oldPeer.Identifier, Identifier: domain.PeerIdentifier(oldPeer.PublicKey), UserIdentifier: user.Identifier, @@ -352,35 +346,17 @@ func migrateV1Peers(oldDb, newDb *gorm.DB) error { PrivateKey: oldPeer.PrivateKey, PublicKey: oldPeer.PublicKey, }, - Type: ifaceType, - Addresses: ips, - DnsStr: domain.StringConfigOption{ - Value: oldPeer.DNSStr, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - DnsSearchStr: domain.StringConfigOption{ - Value: iface.PeerDefDnsSearchStr, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - Mtu: domain.IntConfigOption{ - Value: oldPeer.Mtu, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - FirewallMark: domain.Int32ConfigOption{ - Value: iface.PeerDefFirewallMark, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - RoutingTable: domain.StringConfigOption{ - Value: iface.PeerDefRoutingTable, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - PreUp: domain.StringConfigOption{ - Value: iface.PeerDefPreUp, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - PostUp: domain.StringConfigOption{ - Value: iface.PeerDefPostUp, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - PreDown: domain.StringConfigOption{ - Value: iface.PeerDefPreDown, Overridable: !oldPeer.IgnoreGlobalSettings, - }, - PostDown: domain.StringConfigOption{ - Value: iface.PeerDefPostDown, Overridable: !oldPeer.IgnoreGlobalSettings, - }, + Type: ifaceType, + Addresses: ips, + DnsStr: domain.NewConfigOption(oldPeer.DNSStr, !oldPeer.IgnoreGlobalSettings), + DnsSearchStr: domain.NewConfigOption(iface.PeerDefDnsSearchStr, !oldPeer.IgnoreGlobalSettings), + Mtu: domain.NewConfigOption(oldPeer.Mtu, !oldPeer.IgnoreGlobalSettings), + FirewallMark: domain.NewConfigOption(iface.PeerDefFirewallMark, !oldPeer.IgnoreGlobalSettings), + RoutingTable: domain.NewConfigOption(iface.PeerDefRoutingTable, !oldPeer.IgnoreGlobalSettings), + PreUp: domain.NewConfigOption(iface.PeerDefPreUp, !oldPeer.IgnoreGlobalSettings), + PostUp: domain.NewConfigOption(iface.PeerDefPostUp, !oldPeer.IgnoreGlobalSettings), + PreDown: domain.NewConfigOption(iface.PeerDefPreDown, !oldPeer.IgnoreGlobalSettings), + PostDown: domain.NewConfigOption(iface.PeerDefPostDown, !oldPeer.IgnoreGlobalSettings), }, } diff --git a/internal/app/route/routes.go b/internal/app/route/routes.go index ee5b0ae..9d94d5b 100644 --- a/internal/app/route/routes.go +++ b/internal/app/route/routes.go @@ -3,6 +3,7 @@ package route import ( "context" "fmt" + "github.com/h44z/wg-portal/internal/app" "github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/domain" @@ -17,7 +18,7 @@ import ( type routeRuleInfo struct { ifaceId domain.InterfaceIdentifier - fwMark int + fwMark uint32 table int family int hasDefault bool @@ -210,7 +211,7 @@ func (m Manager) setFwMarkRules(rules []routeRuleInfo, family int) error { SuppressIfgroup: -1, SuppressPrefixlen: -1, Priority: m.getRulePriority(existingRules), - Mask: -1, + Mask: nil, Goto: -1, Flow: -1, }); err != nil { @@ -220,7 +221,7 @@ func (m Manager) setFwMarkRules(rules []routeRuleInfo, family int) error { return nil } -func (m Manager) removeFwMarkRules(fwmark, table int, family int) error { +func (m Manager) removeFwMarkRules(fwmark uint32, table int, family int) error { existingRules, err := m.nl.RuleList(family) if err != nil { return fmt.Errorf("failed to get existing rules for family %d: %w", family, err) @@ -272,8 +273,8 @@ func (m Manager) setMainRule(rules []routeRuleInfo, family int) error { SuppressIfgroup: -1, SuppressPrefixlen: 0, Priority: m.getMainRulePriority(existingRules), - Mark: -1, - Mask: -1, + Mark: 0, + Mask: nil, Goto: -1, Flow: -1, }); err != nil { @@ -424,20 +425,25 @@ func (m Manager) removeDeprecatedRoutes(link netlink.Link, family int, allowedIP return nil } -func (m Manager) getRoutingTableAndFwMark(iface *domain.Interface, allowedIPs []domain.Cidr, link netlink.Link) (table, fwmark int, err error) { +func (m Manager) getRoutingTableAndFwMark( + iface *domain.Interface, + allowedIPs []domain.Cidr, + link netlink.Link, +) (table int, fwmark uint32, err error) { table = iface.GetRoutingTable() - fwmark = int(iface.FirewallMark) + fwmark = iface.FirewallMark if fwmark == 0 { - fwmark = m.cfg.Advanced.RouteTableOffset + link.Attrs().Index // generate a new (temporary) firewall mark based on the interface index - logrus.Debugf("using fwmark %d to handle routes", table) + // generate a new (temporary) firewall mark based on the interface index + fwmark = uint32(m.cfg.Advanced.RouteTableOffset + link.Attrs().Index) + logrus.Debugf("%s: using fwmark %d to handle routes", iface.Identifier, table) // apply the temporary fwmark to the wireguard interface - err = m.setFwMark(iface.Identifier, fwmark) + err = m.setFwMark(iface.Identifier, int(fwmark)) } if table == 0 { - table = fwmark // generate a new routing table base on interface index - logrus.Debugf("using routing table %d to handle default routes", table) + table = int(fwmark) // generate a new routing table base on interface index + logrus.Debugf("%s: using routing table %d to handle default routes", iface.Identifier, table) } return } diff --git a/internal/app/wireguard/wireguard_interfaces.go b/internal/app/wireguard/wireguard_interfaces.go index 48d4225..d26d5e9 100644 --- a/internal/app/wireguard/wireguard_interfaces.go +++ b/internal/app/wireguard/wireguard_interfaces.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" + "os" + "time" + "github.com/h44z/wg-portal/internal" "github.com/h44z/wg-portal/internal/app" "github.com/h44z/wg-portal/internal/domain" "github.com/sirupsen/logrus" - "os" - "time" ) func (m Manager) GetImportableInterfaces(ctx context.Context) ([]domain.PhysicalInterface, error) { @@ -25,7 +26,11 @@ func (m Manager) GetImportableInterfaces(ctx context.Context) ([]domain.Physical return physicalInterfaces, nil } -func (m Manager) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error) { +func (m Manager) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) ( + *domain.Interface, + []domain.Peer, + error, +) { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return nil, nil, err } @@ -145,7 +150,11 @@ func (m Manager) ApplyPeerDefaults(ctx context.Context, in *domain.Interface) er return nil } -func (m Manager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool, filter ...domain.InterfaceIdentifier) error { +func (m Manager) RestoreInterfaceState( + ctx context.Context, + updateDbOnError bool, + filter ...domain.InterfaceIdentifier, +) error { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return err } @@ -177,22 +186,24 @@ func (m Manager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool if err != nil { if updateDbOnError { // disable interface in database as no physical interface exists - _ = m.db.SaveInterface(ctx, iface.Identifier, func(in *domain.Interface) (*domain.Interface, error) { - now := time.Now() - in.Disabled = &now // set - in.DisabledReason = domain.DisabledReasonInterfaceMissing - return in, nil - }) + _ = m.db.SaveInterface(ctx, iface.Identifier, + func(in *domain.Interface) (*domain.Interface, error) { + now := time.Now() + in.Disabled = &now // set + in.DisabledReason = domain.DisabledReasonInterfaceMissing + return in, nil + }) } return fmt.Errorf("failed to create physical interface %s: %w", iface.Identifier, err) } // restore peers for _, peer := range peers { - err := m.wg.SavePeer(ctx, iface.Identifier, peer.Identifier, func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error) { - domain.MergeToPhysicalPeer(pp, &peer) - return pp, nil - }) + err := m.wg.SavePeer(ctx, iface.Identifier, peer.Identifier, + func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error) { + domain.MergeToPhysicalPeer(pp, &peer) + return pp, nil + }) if err != nil { return fmt.Errorf("failed to create physical peer %s: %w", peer.Identifier, err) } @@ -205,17 +216,18 @@ func (m Manager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool if err != nil { if updateDbOnError { // disable interface in database as no physical interface is available - _ = m.db.SaveInterface(ctx, iface.Identifier, func(in *domain.Interface) (*domain.Interface, error) { - if iface.IsDisabled() { - now := time.Now() - in.Disabled = &now // set - in.DisabledReason = domain.DisabledReasonInterfaceMissing - } else { - in.Disabled = nil - in.DisabledReason = "" - } - return in, nil - }) + _ = m.db.SaveInterface(ctx, iface.Identifier, + func(in *domain.Interface) (*domain.Interface, error) { + if iface.IsDisabled() { + now := time.Now() + in.Disabled = &now // set + in.DisabledReason = domain.DisabledReasonInterfaceMissing + } else { + in.Disabled = nil + in.DisabledReason = "" + } + return in, nil + }) } return fmt.Errorf("failed to change physical interface state for %s: %w", iface.Identifier, err) } @@ -392,9 +404,9 @@ func (m Manager) DeleteInterface(ctx context.Context, id domain.InterfaceIdentif return fmt.Errorf("deletion failure: %w", err) } - fwMark := int(existingInterface.FirewallMark) + fwMark := existingInterface.FirewallMark if physicalInterface != nil && fwMark == 0 { - fwMark = int(physicalInterface.FirewallMark) + fwMark = physicalInterface.FirewallMark } m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{ FwMark: fwMark, @@ -410,7 +422,10 @@ func (m Manager) DeleteInterface(ctx context.Context, id domain.InterfaceIdentif // region helper-functions -func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface, peers []domain.Peer) (*domain.Interface, error) { +func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface, peers []domain.Peer) ( + *domain.Interface, + error, +) { stateChanged := m.hasInterfaceStateChanged(ctx, iface) if err := m.handleInterfacePreSaveHooks(stateChanged, iface); err != nil { @@ -424,10 +439,11 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface, pee err := m.db.SaveInterface(ctx, iface.Identifier, func(i *domain.Interface) (*domain.Interface, error) { iface.CopyCalculatedAttributes(i) - err := m.wg.SaveInterface(ctx, iface.Identifier, func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error) { - domain.MergeToPhysicalInterface(pi, iface) - return pi, nil - }) + err := m.wg.SaveInterface(ctx, iface.Identifier, + func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error) { + domain.MergeToPhysicalInterface(pi, iface) + return pi, nil + }) if err != nil { return nil, fmt.Errorf("failed to save physical interface %s: %w", iface.Identifier, err) } @@ -441,9 +457,9 @@ func (m Manager) saveInterface(ctx context.Context, iface *domain.Interface, pee m.bus.Publish(app.TopicRouteUpdate, "interface updated: "+string(iface.Identifier)) if iface.IsDisabled() { physicalInterface, _ := m.wg.GetInterface(ctx, iface.Identifier) - fwMark := int(iface.FirewallMark) + fwMark := iface.FirewallMark if physicalInterface != nil && fwMark == 0 { - fwMark = int(physicalInterface.FirewallMark) + fwMark = physicalInterface.FirewallMark } m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{ FwMark: fwMark, @@ -702,18 +718,18 @@ func (m Manager) importPeer(ctx context.Context, in *domain.Interface, p *domain } peer.InterfaceIdentifier = in.Identifier - peer.EndpointPublicKey = domain.StringConfigOption{Value: in.PublicKey, Overridable: true} - peer.AllowedIPsStr = domain.StringConfigOption{Value: in.PeerDefAllowedIPsStr, Overridable: true} + peer.EndpointPublicKey = domain.NewConfigOption(in.PublicKey, true) + peer.AllowedIPsStr = domain.NewConfigOption(in.PeerDefAllowedIPsStr, true) peer.Interface.Addresses = p.AllowedIPs // use allowed IP's as the peer IP's TODO: Should this also match server interface address' prefix length? - peer.Interface.DnsStr = domain.StringConfigOption{Value: in.PeerDefDnsStr, Overridable: true} - peer.Interface.DnsSearchStr = domain.StringConfigOption{Value: in.PeerDefDnsSearchStr, Overridable: true} - peer.Interface.Mtu = domain.IntConfigOption{Value: in.PeerDefMtu, Overridable: true} - peer.Interface.FirewallMark = domain.Int32ConfigOption{Value: in.PeerDefFirewallMark, Overridable: true} - peer.Interface.RoutingTable = domain.StringConfigOption{Value: in.PeerDefRoutingTable, Overridable: true} - peer.Interface.PreUp = domain.StringConfigOption{Value: in.PeerDefPreUp, Overridable: true} - peer.Interface.PostUp = domain.StringConfigOption{Value: in.PeerDefPostUp, Overridable: true} - peer.Interface.PreDown = domain.StringConfigOption{Value: in.PeerDefPreDown, Overridable: true} - peer.Interface.PostDown = domain.StringConfigOption{Value: in.PeerDefPostDown, Overridable: true} + peer.Interface.DnsStr = domain.NewConfigOption(in.PeerDefDnsStr, true) + peer.Interface.DnsSearchStr = domain.NewConfigOption(in.PeerDefDnsSearchStr, true) + peer.Interface.Mtu = domain.NewConfigOption(in.PeerDefMtu, true) + peer.Interface.FirewallMark = domain.NewConfigOption(in.PeerDefFirewallMark, true) + peer.Interface.RoutingTable = domain.NewConfigOption(in.PeerDefRoutingTable, true) + peer.Interface.PreUp = domain.NewConfigOption(in.PeerDefPreUp, true) + peer.Interface.PostUp = domain.NewConfigOption(in.PeerDefPostUp, true) + peer.Interface.PreDown = domain.NewConfigOption(in.PeerDefPreDown, true) + peer.Interface.PostDown = domain.NewConfigOption(in.PeerDefPostDown, true) switch in.Type { case domain.InterfaceTypeAny: diff --git a/internal/app/wireguard/wireguard_peers.go b/internal/app/wireguard/wireguard_peers.go index b4764d2..a9b6f07 100644 --- a/internal/app/wireguard/wireguard_peers.go +++ b/internal/app/wireguard/wireguard_peers.go @@ -102,12 +102,12 @@ func (m Manager) PreparePeer(ctx context.Context, id domain.InterfaceIdentifier) CreatedAt: time.Now(), UpdatedAt: time.Now(), }, - Endpoint: domain.NewStringConfigOption(iface.PeerDefEndpoint, true), - EndpointPublicKey: domain.NewStringConfigOption(iface.PublicKey, true), - AllowedIPsStr: domain.NewStringConfigOption(iface.PeerDefAllowedIPsStr, true), + Endpoint: domain.NewConfigOption(iface.PeerDefEndpoint, true), + EndpointPublicKey: domain.NewConfigOption(iface.PublicKey, true), + AllowedIPsStr: domain.NewConfigOption(iface.PeerDefAllowedIPsStr, true), ExtraAllowedIPsStr: "", PresharedKey: pk, - PersistentKeepalive: domain.NewIntConfigOption(iface.PeerDefPersistentKeepalive, true), + PersistentKeepalive: domain.NewConfigOption(iface.PeerDefPersistentKeepalive, true), DisplayName: fmt.Sprintf("Peer %s", internal.TruncateString(string(peerId), 8)), Identifier: peerId, UserIdentifier: currentUser.Id, @@ -121,15 +121,15 @@ func (m Manager) PreparePeer(ctx context.Context, id domain.InterfaceIdentifier) Type: peerMode, Addresses: ips, CheckAliveAddress: "", - DnsStr: domain.NewStringConfigOption(iface.PeerDefDnsStr, true), - DnsSearchStr: domain.NewStringConfigOption(iface.PeerDefDnsSearchStr, true), - Mtu: domain.NewIntConfigOption(iface.PeerDefMtu, true), - FirewallMark: domain.NewInt32ConfigOption(iface.PeerDefFirewallMark, true), - RoutingTable: domain.NewStringConfigOption(iface.PeerDefRoutingTable, true), - PreUp: domain.NewStringConfigOption(iface.PeerDefPreUp, true), - PostUp: domain.NewStringConfigOption(iface.PeerDefPostUp, true), - PreDown: domain.NewStringConfigOption(iface.PeerDefPreDown, true), - PostDown: domain.NewStringConfigOption(iface.PeerDefPostDown, true), + DnsStr: domain.NewConfigOption(iface.PeerDefDnsStr, true), + DnsSearchStr: domain.NewConfigOption(iface.PeerDefDnsSearchStr, true), + Mtu: domain.NewConfigOption(iface.PeerDefMtu, true), + FirewallMark: domain.NewConfigOption(iface.PeerDefFirewallMark, true), + RoutingTable: domain.NewConfigOption(iface.PeerDefRoutingTable, true), + PreUp: domain.NewConfigOption(iface.PeerDefPreUp, true), + PostUp: domain.NewConfigOption(iface.PeerDefPostUp, true), + PreDown: domain.NewConfigOption(iface.PeerDefPreDown, true), + PostDown: domain.NewConfigOption(iface.PeerDefPostDown, true), }, } @@ -174,7 +174,11 @@ func (m Manager) CreatePeer(ctx context.Context, peer *domain.Peer) (*domain.Pee return peer, nil } -func (m Manager) CreateMultiplePeers(ctx context.Context, interfaceId domain.InterfaceIdentifier, r *domain.PeerCreationRequest) ([]domain.Peer, error) { +func (m Manager) CreateMultiplePeers( + ctx context.Context, + interfaceId domain.InterfaceIdentifier, + r *domain.PeerCreationRequest, +) ([]domain.Peer, error) { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return nil, err } diff --git a/internal/domain/interface.go b/internal/domain/interface.go index ecda7ab..0547db7 100644 --- a/internal/domain/interface.go +++ b/internal/domain/interface.go @@ -2,13 +2,14 @@ package domain import ( "fmt" - "github.com/h44z/wg-portal/internal" - "github.com/sirupsen/logrus" "math" "regexp" "strconv" "strings" "time" + + "github.com/h44z/wg-portal/internal" + "github.com/sirupsen/logrus" ) const ( @@ -34,7 +35,7 @@ type Interface struct { DnsSearchStr string // the dns search option string that should be set if the interface is up, will be appended to DnsStr Mtu int // the device MTU - FirewallMark int32 // a firewall mark + FirewallMark uint32 // a firewall mark RoutingTable string // the routing table number or "off" if the routing table should not be managed PreUp string // action that is executed before the device is up @@ -61,7 +62,7 @@ type Interface struct { PeerDefAllowedIPsStr string // the default allowed IP string for the peer PeerDefMtu int // the default device MTU PeerDefPersistentKeepalive int // the default persistent keep-alive Value - PeerDefFirewallMark int32 // default firewall mark + PeerDefFirewallMark uint32 // default firewall mark PeerDefRoutingTable string // the default routing table PeerDefPreUp string // default action that is executed before the device is up @@ -161,8 +162,8 @@ type PhysicalInterface struct { Addresses []Cidr // the interface ip addresses - Mtu int // the device MTU - FirewallMark int32 // a firewall mark + Mtu int // the device MTU + FirewallMark uint32 // a firewall mark DeviceUp bool // device status @@ -223,7 +224,7 @@ func MergeToPhysicalInterface(pi *PhysicalInterface, i *Interface) { } type RoutingTableInfo struct { - FwMark int + FwMark uint32 Table int } @@ -241,7 +242,7 @@ func (r RoutingTableInfo) ManagementEnabled() bool { func (r RoutingTableInfo) GetRoutingTable() int { if r.Table <= 0 { - return r.FwMark // use the dynamic routing table which has the same number as the firewall mark + return int(r.FwMark) // use the dynamic routing table which has the same number as the firewall mark } return r.Table diff --git a/internal/domain/options.go b/internal/domain/options.go index b0fddf3..7f90ea7 100644 --- a/internal/domain/options.go +++ b/internal/domain/options.go @@ -1,47 +1,19 @@ package domain -type StringConfigOption struct { - Value string `gorm:"column:v"` - Overridable bool `gorm:"column:o"` -} - -func (o StringConfigOption) GetValue() string { - return o.Value -} - -func (o *StringConfigOption) SetValue(value string) { - o.Value = value -} - -func (o *StringConfigOption) TrySetValue(value string) bool { - if o.Overridable { - o.Value = value - return true - } - return false -} - -func NewStringConfigOption(value string, overridable bool) StringConfigOption { - return StringConfigOption{ - Value: value, - Overridable: overridable, - } -} - -type IntConfigOption struct { - Value int `gorm:"column:v"` +type ConfigOption[T any] struct { + Value T `gorm:"column:v"` Overridable bool `gorm:"column:o"` } -func (o IntConfigOption) GetValue() int { +func (o *ConfigOption[T]) GetValue() T { return o.Value } -func (o *IntConfigOption) SetValue(value int) { +func (o *ConfigOption[T]) SetValue(value T) { o.Value = value } -func (o *IntConfigOption) TrySetValue(value int) bool { +func (o *ConfigOption[T]) TrySetValue(value T) bool { if o.Overridable { o.Value = value return true @@ -49,64 +21,8 @@ func (o *IntConfigOption) TrySetValue(value int) bool { return false } -func NewIntConfigOption(value int, overridable bool) IntConfigOption { - return IntConfigOption{ - Value: value, - Overridable: overridable, - } -} - -type Int32ConfigOption struct { - Value int32 `gorm:"column:v"` - Overridable bool `gorm:"column:o"` -} - -func (o Int32ConfigOption) GetValue() int32 { - return o.Value -} - -func (o *Int32ConfigOption) SetValue(value int32) { - o.Value = value -} - -func (o *Int32ConfigOption) TrySetValue(value int32) bool { - if o.Overridable { - o.Value = value - return true - } - return false -} - -func NewInt32ConfigOption(value int32, overridable bool) Int32ConfigOption { - return Int32ConfigOption{ - Value: value, - Overridable: overridable, - } -} - -type BoolConfigOption struct { - Value bool `gorm:"column:v"` - Overridable bool `gorm:"column:o"` -} - -func (o BoolConfigOption) GetValue() bool { - return o.Value -} - -func (o *BoolConfigOption) SetValue(value bool) { - o.Value = value -} - -func (o *BoolConfigOption) TrySetValue(value bool) bool { - if o.Overridable { - o.Value = value - return true - } - return false -} - -func NewBoolConfigOption(value bool, overridable bool) BoolConfigOption { - return BoolConfigOption{ +func NewConfigOption[T any](value T, overridable bool) ConfigOption[T] { + return ConfigOption[T]{ Value: value, Overridable: overridable, } diff --git a/internal/domain/peer.go b/internal/domain/peer.go index 7bf988e..9be8f17 100644 --- a/internal/domain/peer.go +++ b/internal/domain/peer.go @@ -2,12 +2,13 @@ package domain import ( "fmt" - "github.com/h44z/wg-portal/internal" "net" "regexp" "strings" "time" + "github.com/h44z/wg-portal/internal" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -31,12 +32,12 @@ type Peer struct { // WireGuard specific (for the [peer] section of the config file) - Endpoint StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_"` // the endpoint address - EndpointPublicKey StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_pubkey_"` // the endpoint public key - AllowedIPsStr StringConfigOption `gorm:"embedded;embeddedPrefix:allowed_ips_str_"` // all allowed ip subnets, comma seperated - ExtraAllowedIPsStr string // all allowed ip subnets on the server side, comma seperated - PresharedKey PreSharedKey // the pre-shared Key of the peer - PersistentKeepalive IntConfigOption `gorm:"embedded;embeddedPrefix:persistent_keep_alive_"` // the persistent keep-alive interval + Endpoint ConfigOption[string] `gorm:"embedded;embeddedPrefix:endpoint_"` // the endpoint address + EndpointPublicKey ConfigOption[string] `gorm:"embedded;embeddedPrefix:endpoint_pubkey_"` // the endpoint public key + AllowedIPsStr ConfigOption[string] `gorm:"embedded;embeddedPrefix:allowed_ips_str_"` // all allowed ip subnets, comma seperated + ExtraAllowedIPsStr string // all allowed ip subnets on the server side, comma seperated + PresharedKey PreSharedKey // the pre-shared Key of the peer + PersistentKeepalive ConfigOption[int] `gorm:"embedded;embeddedPrefix:persistent_keep_alive_"` // the persistent keep-alive interval // WG Portal specific @@ -124,18 +125,18 @@ type PeerInterfaceConfig struct { Type InterfaceType `gorm:"column:iface_type"` // the interface type (server, client, any) - Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses - CheckAliveAddress string `gorm:"column:check_alive_address"` // optional ip address or DNS name that is used for ping checks - DnsStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_str_"` // the dns server that should be set if the interface is up, comma separated - DnsSearchStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_search_str_"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr - Mtu IntConfigOption `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU - FirewallMark Int32ConfigOption `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark - RoutingTable StringConfigOption `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table + Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses + CheckAliveAddress string `gorm:"column:check_alive_address"` // optional ip address or DNS name that is used for ping checks + DnsStr ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_dns_str_"` // the dns server that should be set if the interface is up, comma separated + DnsSearchStr ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_dns_search_str_"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr + Mtu ConfigOption[int] `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU + FirewallMark ConfigOption[uint32] `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark + RoutingTable ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table - PreUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_pre_up_"` // action that is executed before the device is up - PostUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_post_up_"` // action that is executed after the device is up - PreDown StringConfigOption `gorm:"embedded;embeddedPrefix:iface_pre_down_"` // action that is executed before the device is down - PostDown StringConfigOption `gorm:"embedded;embeddedPrefix:iface_post_down_"` // action that is executed after the device is down + PreUp ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_pre_up_"` // action that is executed before the device is up + PostUp ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_post_up_"` // action that is executed after the device is up + PreDown ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_pre_down_"` // action that is executed before the device is down + PostDown ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_post_down_"` // action that is executed after the device is down } func (p *PeerInterfaceConfig) AddressStr() string { @@ -202,12 +203,12 @@ func (p PhysicalPeer) GetAllowedIPs() []net.IPNet { func ConvertPhysicalPeer(pp *PhysicalPeer) *Peer { peer := &Peer{ - Endpoint: StringConfigOption{Value: pp.Endpoint, Overridable: true}, - EndpointPublicKey: StringConfigOption{Value: "", Overridable: true}, - AllowedIPsStr: StringConfigOption{Value: "", Overridable: true}, + Endpoint: NewConfigOption(pp.Endpoint, true), + EndpointPublicKey: NewConfigOption("", true), + AllowedIPsStr: NewConfigOption("", true), ExtraAllowedIPsStr: "", PresharedKey: pp.PresharedKey, - PersistentKeepalive: IntConfigOption{Value: pp.PersistentKeepalive, Overridable: true}, + PersistentKeepalive: NewConfigOption(pp.PersistentKeepalive, true), DisplayName: string(pp.Identifier), Identifier: pp.Identifier, UserIdentifier: "",