chore: update dependencies, refactor option types

This commit is contained in:
Christoph 2024-10-15 15:44:47 +02:00
parent 6bb683047e
commit bf9183256a
13 changed files with 253 additions and 400 deletions

4
go.mod
View File

@ -11,14 +11,14 @@ require (
github.com/glebarez/sqlite v1.11.0 github.com/glebarez/sqlite v1.11.0
github.com/go-ldap/ldap/v3 v3.4.8 github.com/go-ldap/ldap/v3 v3.4.8
github.com/prometheus-community/pro-bing v0.4.1 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/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/swaggo/swag v1.16.3 github.com/swaggo/swag v1.16.3
github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f github.com/toorop/gin-logrus v0.0.0-20210225092905-2c785434f26f
github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca
github.com/vardius/message-bus v1.1.5 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/xhit/go-simple-mail/v2 v2.16.0
github.com/yeqown/go-qrcode/v2 v2.2.4 github.com/yeqown/go-qrcode/v2 v2.2.4
golang.org/x/crypto v0.28.0 golang.org/x/crypto v0.28.0

12
go.sum
View File

@ -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/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 h1:aMaJwyifHZO0y+h8+icUz0xbToHbia0wdmzdVZ+Kl3w=
github.com/prometheus-community/pro-bing v0.4.1/go.mod h1:aLsw+zqCaDoa2RLVVSX3+UiCkBBXTMtZC3c7EkfWnAE= 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.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 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 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= 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/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 h1:YSAC2WB4HRlwc4neFPTmT88kzzoiQ+9WRRbej/E/LZc=
github.com/vardius/message-bus v1.1.5/go.mod h1:6xladCV2lMkUAE4bzzS85qKOiB5miV7aBVRafiTJGqw= 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.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= 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-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-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-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-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-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-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.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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.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.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.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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -4,12 +4,13 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"os"
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
"github.com/h44z/wg-portal/internal/lowlevel" "github.com/h44z/wg-portal/internal/lowlevel"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"os"
) )
// WgRepo implements all low-level WireGuard interactions. // WgRepo implements all low-level WireGuard interactions.
@ -74,7 +75,11 @@ func (r *WgRepo) GetPeers(_ context.Context, deviceId domain.InterfaceIdentifier
return peers, nil 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) return r.getPeer(deviceId, id)
} }
@ -90,7 +95,7 @@ func (r *WgRepo) convertWireGuardInterface(device *wgtypes.Device) (domain.Physi
ListenPort: device.ListenPort, ListenPort: device.ListenPort,
Addresses: nil, Addresses: nil,
Mtu: 0, Mtu: 0,
FirewallMark: int32(device.FirewallMark), FirewallMark: uint32(device.FirewallMark),
DeviceUp: false, DeviceUp: false,
ImportSource: "wgctrl", ImportSource: "wgctrl",
DeviceType: device.Type.String(), DeviceType: device.Type.String(),
@ -151,7 +156,11 @@ func (r *WgRepo) convertWireGuardPeer(peer *wgtypes.Peer) (domain.PhysicalPeer,
return peerModel, nil 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) physicalInterface, err := r.getOrCreateInterface(id)
if err != nil { if err != nil {
return err return err
@ -324,7 +333,12 @@ func (r *WgRepo) deleteLowLevelInterface(id domain.InterfaceIdentifier) error {
return nil 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) physicalPeer, err := r.getOrCreatePeer(deviceId, id)
if err != nil { if err != nil {
return err return err
@ -342,7 +356,10 @@ func (r *WgRepo) SavePeer(_ context.Context, deviceId domain.InterfaceIdentifier
return nil 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) peer, err := r.getPeer(deviceId, id)
if err == nil { if err == nil {
return peer, nil return peer, nil
@ -352,9 +369,13 @@ func (r *WgRepo) getOrCreatePeer(deviceId domain.InterfaceIdentifier, id domain.
} }
// create new peer // create new peer
err = r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{Peers: []wgtypes.PeerConfig{{ err = r.wg.ConfigureDevice(string(deviceId), wgtypes.Config{
PublicKey: id.ToPublicKey(), Peers: []wgtypes.PeerConfig{
}}}) {
PublicKey: id.ToPublicKey(),
},
},
})
peer, err = r.getPeer(deviceId, id) peer, err = r.getPeer(deviceId, id)
return peer, nil return peer, nil

View File

@ -5,132 +5,42 @@ import (
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
) )
type StringConfigOption struct { type ConfigOption[T any] struct {
Value string `json:"Value"` Value T `json:"Value"`
Overridable bool `json:"Overridable"` Overridable bool `json:"Overridable"`
} }
func NewStringConfigOption(value string, overridable bool) StringConfigOption { func NewConfigOption[T any](value T, overridable bool) ConfigOption[T] {
return StringConfigOption{ return ConfigOption[T]{
Value: value, Value: value,
Overridable: overridable, Overridable: overridable,
} }
} }
func StringConfigOptionFromDomain(opt domain.StringConfigOption) StringConfigOption { func ConfigOptionFromDomain[T any](opt domain.ConfigOption[T]) ConfigOption[T] {
return StringConfigOption{ return ConfigOption[T]{
Value: opt.Value, Value: opt.Value,
Overridable: opt.Overridable, Overridable: opt.Overridable,
} }
} }
func StringConfigOptionToDomain(opt StringConfigOption) domain.StringConfigOption { func ConfigOptionToDomain[T any](opt ConfigOption[T]) domain.ConfigOption[T] {
return domain.StringConfigOption{ return domain.ConfigOption[T]{
Value: opt.Value, Value: opt.Value,
Overridable: opt.Overridable, Overridable: opt.Overridable,
} }
} }
type StringSliceConfigOption struct { func StringSliceConfigOptionFromDomain(opt domain.ConfigOption[string]) ConfigOption[[]string] {
Value []string `json:"Value"` return ConfigOption[[]string]{
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{
Value: internal.SliceString(opt.Value), Value: internal.SliceString(opt.Value),
Overridable: opt.Overridable, Overridable: opt.Overridable,
} }
} }
func StringSliceConfigOptionToDomain(opt StringSliceConfigOption) domain.StringConfigOption { func StringSliceConfigOptionToDomain(opt ConfigOption[[]string]) domain.ConfigOption[string] {
return domain.StringConfigOption{ return domain.ConfigOption[string]{
Value: internal.SliceToString(opt.Value), Value: internal.SliceToString(opt.Value),
Overridable: opt.Overridable, 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,
}
}

View File

@ -1,9 +1,10 @@
package model package model
import ( import (
"github.com/h44z/wg-portal/internal"
"time" "time"
"github.com/h44z/wg-portal/internal"
"github.com/h44z/wg-portal/internal/domain" "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 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 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 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 RoutingTable string `json:"RoutingTable"` // the routing table
PreUp string `json:"PreUp"` // action that is executed before the device is up 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 PeerDefAllowedIPs []string `json:"PeerDefAllowedIPs"` // the default allowed IP string for the peer
PeerDefMtu int `json:"PeerDefMtu"` // the default device MTU PeerDefMtu int `json:"PeerDefMtu"` // the default device MTU
PeerDefPersistentKeepalive int `json:"PeerDefPersistentKeepalive"` // the default persistent keep-alive Value 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 PeerDefRoutingTable string `json:"PeerDefRoutingTable"` // the default routing table
PeerDefPreUp string `json:"PeerDefPreUp"` // default action that is executed before the device is up PeerDefPreUp string `json:"PeerDefPreUp"` // default action that is executed before the device is up

View File

@ -1,9 +1,10 @@
package model package model
import ( import (
"time"
"github.com/h44z/wg-portal/internal" "github.com/h44z/wg-portal/internal"
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
"time"
) )
const ExpiryDateTimeLayout = "\"2006-01-02\"" const ExpiryDateTimeLayout = "\"2006-01-02\""
@ -48,30 +49,30 @@ type Peer struct {
ExpiresAt ExpiryDate `json:"ExpiresAt,omitempty"` // expiry dates for peers ExpiresAt ExpiryDate `json:"ExpiresAt,omitempty"` // expiry dates for peers
Notes string `json:"Notes"` // a note field for peers Notes string `json:"Notes"` // a note field for peers
Endpoint StringConfigOption `json:"Endpoint"` // the endpoint address Endpoint ConfigOption[string] `json:"Endpoint"` // the endpoint address
EndpointPublicKey StringConfigOption `json:"EndpointPublicKey"` // the endpoint public key EndpointPublicKey ConfigOption[string] `json:"EndpointPublicKey"` // the endpoint public key
AllowedIPs StringSliceConfigOption `json:"AllowedIPs"` // all allowed ip subnets, comma seperated 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 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 PresharedKey string `json:"PresharedKey"` // the pre-shared Key of the peer
PersistentKeepalive IntConfigOption `json:"PersistentKeepalive"` // the persistent keep-alive interval PersistentKeepalive ConfigOption[int] `json:"PersistentKeepalive"` // the persistent keep-alive interval
PrivateKey string `json:"PrivateKey" example:"abcdef=="` // private Key of the server peer PrivateKey string `json:"PrivateKey" example:"abcdef=="` // private Key of the server peer
PublicKey string `json:"PublicKey" example:"abcdef=="` // public 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) Mode string // the peer interface type (server, client, any)
Addresses []string `json:"Addresses"` // the interface ip addresses Addresses []string `json:"Addresses"` // the interface ip addresses
CheckAliveAddress string `json:"CheckAliveAddress"` // optional ip address or DNS name that is used for ping checks 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 Dns ConfigOption[[]string] `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 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 IntConfigOption `json:"Mtu"` // the device MTU Mtu ConfigOption[int] `json:"Mtu"` // the device MTU
FirewallMark Int32ConfigOption `json:"FirewallMark"` // a firewall mark FirewallMark ConfigOption[uint32] `json:"FirewallMark"` // a firewall mark
RoutingTable StringConfigOption `json:"RoutingTable"` // the routing table RoutingTable ConfigOption[string] `json:"RoutingTable"` // the routing table
PreUp StringConfigOption `json:"PreUp"` // action that is executed before the device is up PreUp ConfigOption[string] `json:"PreUp"` // action that is executed before the device is up
PostUp StringConfigOption `json:"PostUp"` // action that is executed after the device is up PostUp ConfigOption[string] `json:"PostUp"` // action that is executed after the device is up
PreDown StringConfigOption `json:"PreDown"` // action that is executed before the device is down PreDown ConfigOption[string] `json:"PreDown"` // action that is executed before the device is down
PostDown StringConfigOption `json:"PostDown"` // action that is executed after the device is down PostDown ConfigOption[string] `json:"PostDown"` // action that is executed after the device is down
} }
func NewPeer(src *domain.Peer) *Peer { func NewPeer(src *domain.Peer) *Peer {
@ -84,12 +85,12 @@ func NewPeer(src *domain.Peer) *Peer {
DisabledReason: src.DisabledReason, DisabledReason: src.DisabledReason,
ExpiresAt: ExpiryDate{src.ExpiresAt}, ExpiresAt: ExpiryDate{src.ExpiresAt},
Notes: src.Notes, Notes: src.Notes,
Endpoint: StringConfigOptionFromDomain(src.Endpoint), Endpoint: ConfigOptionFromDomain(src.Endpoint),
EndpointPublicKey: StringConfigOptionFromDomain(src.EndpointPublicKey), EndpointPublicKey: ConfigOptionFromDomain(src.EndpointPublicKey),
AllowedIPs: StringSliceConfigOptionFromDomain(src.AllowedIPsStr), AllowedIPs: StringSliceConfigOptionFromDomain(src.AllowedIPsStr),
ExtraAllowedIPs: internal.SliceString(src.ExtraAllowedIPsStr), ExtraAllowedIPs: internal.SliceString(src.ExtraAllowedIPsStr),
PresharedKey: string(src.PresharedKey), PresharedKey: string(src.PresharedKey),
PersistentKeepalive: IntConfigOptionFromDomain(src.PersistentKeepalive), PersistentKeepalive: ConfigOptionFromDomain(src.PersistentKeepalive),
PrivateKey: src.Interface.PrivateKey, PrivateKey: src.Interface.PrivateKey,
PublicKey: src.Interface.PublicKey, PublicKey: src.Interface.PublicKey,
Mode: string(src.Interface.Type), Mode: string(src.Interface.Type),
@ -97,13 +98,13 @@ func NewPeer(src *domain.Peer) *Peer {
CheckAliveAddress: src.Interface.CheckAliveAddress, CheckAliveAddress: src.Interface.CheckAliveAddress,
Dns: StringSliceConfigOptionFromDomain(src.Interface.DnsStr), Dns: StringSliceConfigOptionFromDomain(src.Interface.DnsStr),
DnsSearch: StringSliceConfigOptionFromDomain(src.Interface.DnsSearchStr), DnsSearch: StringSliceConfigOptionFromDomain(src.Interface.DnsSearchStr),
Mtu: IntConfigOptionFromDomain(src.Interface.Mtu), Mtu: ConfigOptionFromDomain(src.Interface.Mtu),
FirewallMark: Int32ConfigOptionFromDomain(src.Interface.FirewallMark), FirewallMark: ConfigOptionFromDomain(src.Interface.FirewallMark),
RoutingTable: StringConfigOptionFromDomain(src.Interface.RoutingTable), RoutingTable: ConfigOptionFromDomain(src.Interface.RoutingTable),
PreUp: StringConfigOptionFromDomain(src.Interface.PreUp), PreUp: ConfigOptionFromDomain(src.Interface.PreUp),
PostUp: StringConfigOptionFromDomain(src.Interface.PostUp), PostUp: ConfigOptionFromDomain(src.Interface.PostUp),
PreDown: StringConfigOptionFromDomain(src.Interface.PreDown), PreDown: ConfigOptionFromDomain(src.Interface.PreDown),
PostDown: StringConfigOptionFromDomain(src.Interface.PostDown), PostDown: ConfigOptionFromDomain(src.Interface.PostDown),
} }
} }
@ -123,12 +124,12 @@ func NewDomainPeer(src *Peer) *domain.Peer {
res := &domain.Peer{ res := &domain.Peer{
BaseModel: domain.BaseModel{}, BaseModel: domain.BaseModel{},
Endpoint: StringConfigOptionToDomain(src.Endpoint), Endpoint: ConfigOptionToDomain(src.Endpoint),
EndpointPublicKey: StringConfigOptionToDomain(src.EndpointPublicKey), EndpointPublicKey: ConfigOptionToDomain(src.EndpointPublicKey),
AllowedIPsStr: StringSliceConfigOptionToDomain(src.AllowedIPs), AllowedIPsStr: StringSliceConfigOptionToDomain(src.AllowedIPs),
ExtraAllowedIPsStr: internal.SliceToString(src.ExtraAllowedIPs), ExtraAllowedIPsStr: internal.SliceToString(src.ExtraAllowedIPs),
PresharedKey: domain.PreSharedKey(src.PresharedKey), PresharedKey: domain.PreSharedKey(src.PresharedKey),
PersistentKeepalive: IntConfigOptionToDomain(src.PersistentKeepalive), PersistentKeepalive: ConfigOptionToDomain(src.PersistentKeepalive),
DisplayName: src.DisplayName, DisplayName: src.DisplayName,
Identifier: domain.PeerIdentifier(src.Identifier), Identifier: domain.PeerIdentifier(src.Identifier),
UserIdentifier: domain.UserIdentifier(src.UserIdentifier), UserIdentifier: domain.UserIdentifier(src.UserIdentifier),
@ -147,13 +148,13 @@ func NewDomainPeer(src *Peer) *domain.Peer {
CheckAliveAddress: src.CheckAliveAddress, CheckAliveAddress: src.CheckAliveAddress,
DnsStr: StringSliceConfigOptionToDomain(src.Dns), DnsStr: StringSliceConfigOptionToDomain(src.Dns),
DnsSearchStr: StringSliceConfigOptionToDomain(src.DnsSearch), DnsSearchStr: StringSliceConfigOptionToDomain(src.DnsSearch),
Mtu: IntConfigOptionToDomain(src.Mtu), Mtu: ConfigOptionToDomain(src.Mtu),
FirewallMark: Int32ConfigOptionToDomain(src.FirewallMark), FirewallMark: ConfigOptionToDomain(src.FirewallMark),
RoutingTable: StringConfigOptionToDomain(src.RoutingTable), RoutingTable: ConfigOptionToDomain(src.RoutingTable),
PreUp: StringConfigOptionToDomain(src.PreUp), PreUp: ConfigOptionToDomain(src.PreUp),
PostUp: StringConfigOptionToDomain(src.PostUp), PostUp: ConfigOptionToDomain(src.PostUp),
PreDown: StringConfigOptionToDomain(src.PreDown), PreDown: ConfigOptionToDomain(src.PreDown),
PostDown: StringConfigOptionToDomain(src.PostDown), PostDown: ConfigOptionToDomain(src.PostDown),
}, },
} }

View File

@ -3,13 +3,14 @@ package app
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"time"
"github.com/h44z/wg-portal/internal/adapters" "github.com/h44z/wg-portal/internal/adapters"
"github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/config"
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gorm.io/gorm" "gorm.io/gorm"
"os"
"time"
) )
func migrateFromV1(cfg *config.Config, db *gorm.DB, source, typ string) error { 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 DisplayName string
PrivateKey string PrivateKey string
ListenPort int ListenPort int
FirewallMark int32 FirewallMark uint32
PublicKey string PublicKey string
Mtu int Mtu int
IPsStr string IPsStr string
@ -288,7 +289,8 @@ func migrateV1Peers(oldDb, newDb *gorm.DB) error {
ifaceType = domain.InterfaceTypeAny ifaceType = domain.InterfaceTypeAny
} }
var user domain.User 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) { 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) 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, CreatedAt: oldPeer.CreatedAt,
UpdatedAt: oldPeer.UpdatedAt, UpdatedAt: oldPeer.UpdatedAt,
}, },
Endpoint: domain.StringConfigOption{ Endpoint: domain.NewConfigOption(oldPeer.Endpoint, !oldPeer.IgnoreGlobalSettings),
Value: oldPeer.Endpoint, Overridable: !oldPeer.IgnoreGlobalSettings, EndpointPublicKey: domain.NewConfigOption(iface.PublicKey, !oldPeer.IgnoreGlobalSettings),
}, AllowedIPsStr: domain.NewConfigOption(oldPeer.AllowedIPsStr, !oldPeer.IgnoreGlobalSettings),
EndpointPublicKey: domain.StringConfigOption{ ExtraAllowedIPsStr: oldPeer.AllowedIPsSrvStr,
Value: iface.PublicKey, Overridable: !oldPeer.IgnoreGlobalSettings, PresharedKey: domain.PreSharedKey(oldPeer.PresharedKey),
}, PersistentKeepalive: domain.NewConfigOption(oldPeer.PersistentKeepalive, !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,
},
DisplayName: oldPeer.Identifier, DisplayName: oldPeer.Identifier,
Identifier: domain.PeerIdentifier(oldPeer.PublicKey), Identifier: domain.PeerIdentifier(oldPeer.PublicKey),
UserIdentifier: user.Identifier, UserIdentifier: user.Identifier,
@ -352,35 +346,17 @@ func migrateV1Peers(oldDb, newDb *gorm.DB) error {
PrivateKey: oldPeer.PrivateKey, PrivateKey: oldPeer.PrivateKey,
PublicKey: oldPeer.PublicKey, PublicKey: oldPeer.PublicKey,
}, },
Type: ifaceType, Type: ifaceType,
Addresses: ips, Addresses: ips,
DnsStr: domain.StringConfigOption{ DnsStr: domain.NewConfigOption(oldPeer.DNSStr, !oldPeer.IgnoreGlobalSettings),
Value: oldPeer.DNSStr, Overridable: !oldPeer.IgnoreGlobalSettings, DnsSearchStr: domain.NewConfigOption(iface.PeerDefDnsSearchStr, !oldPeer.IgnoreGlobalSettings),
}, Mtu: domain.NewConfigOption(oldPeer.Mtu, !oldPeer.IgnoreGlobalSettings),
DnsSearchStr: domain.StringConfigOption{ FirewallMark: domain.NewConfigOption(iface.PeerDefFirewallMark, !oldPeer.IgnoreGlobalSettings),
Value: iface.PeerDefDnsSearchStr, Overridable: !oldPeer.IgnoreGlobalSettings, RoutingTable: domain.NewConfigOption(iface.PeerDefRoutingTable, !oldPeer.IgnoreGlobalSettings),
}, PreUp: domain.NewConfigOption(iface.PeerDefPreUp, !oldPeer.IgnoreGlobalSettings),
Mtu: domain.IntConfigOption{ PostUp: domain.NewConfigOption(iface.PeerDefPostUp, !oldPeer.IgnoreGlobalSettings),
Value: oldPeer.Mtu, Overridable: !oldPeer.IgnoreGlobalSettings, PreDown: domain.NewConfigOption(iface.PeerDefPreDown, !oldPeer.IgnoreGlobalSettings),
}, PostDown: domain.NewConfigOption(iface.PeerDefPostDown, !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,
},
}, },
} }

View File

@ -3,6 +3,7 @@ package route
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/h44z/wg-portal/internal/app" "github.com/h44z/wg-portal/internal/app"
"github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/config"
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
@ -17,7 +18,7 @@ import (
type routeRuleInfo struct { type routeRuleInfo struct {
ifaceId domain.InterfaceIdentifier ifaceId domain.InterfaceIdentifier
fwMark int fwMark uint32
table int table int
family int family int
hasDefault bool hasDefault bool
@ -210,7 +211,7 @@ func (m Manager) setFwMarkRules(rules []routeRuleInfo, family int) error {
SuppressIfgroup: -1, SuppressIfgroup: -1,
SuppressPrefixlen: -1, SuppressPrefixlen: -1,
Priority: m.getRulePriority(existingRules), Priority: m.getRulePriority(existingRules),
Mask: -1, Mask: nil,
Goto: -1, Goto: -1,
Flow: -1, Flow: -1,
}); err != nil { }); err != nil {
@ -220,7 +221,7 @@ func (m Manager) setFwMarkRules(rules []routeRuleInfo, family int) error {
return nil 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) existingRules, err := m.nl.RuleList(family)
if err != nil { if err != nil {
return fmt.Errorf("failed to get existing rules for family %d: %w", family, err) 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, SuppressIfgroup: -1,
SuppressPrefixlen: 0, SuppressPrefixlen: 0,
Priority: m.getMainRulePriority(existingRules), Priority: m.getMainRulePriority(existingRules),
Mark: -1, Mark: 0,
Mask: -1, Mask: nil,
Goto: -1, Goto: -1,
Flow: -1, Flow: -1,
}); err != nil { }); err != nil {
@ -424,20 +425,25 @@ func (m Manager) removeDeprecatedRoutes(link netlink.Link, family int, allowedIP
return nil 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() table = iface.GetRoutingTable()
fwmark = int(iface.FirewallMark) fwmark = iface.FirewallMark
if fwmark == 0 { if fwmark == 0 {
fwmark = m.cfg.Advanced.RouteTableOffset + link.Attrs().Index // generate a new (temporary) firewall mark based on the interface index // generate a new (temporary) firewall mark based on the interface index
logrus.Debugf("using fwmark %d to handle routes", table) 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 // apply the temporary fwmark to the wireguard interface
err = m.setFwMark(iface.Identifier, fwmark) err = m.setFwMark(iface.Identifier, int(fwmark))
} }
if table == 0 { if table == 0 {
table = fwmark // generate a new routing table base on interface index table = int(fwmark) // generate a new routing table base on interface index
logrus.Debugf("using routing table %d to handle default routes", table) logrus.Debugf("%s: using routing table %d to handle default routes", iface.Identifier, table)
} }
return return
} }

View File

@ -4,12 +4,13 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"os"
"time"
"github.com/h44z/wg-portal/internal" "github.com/h44z/wg-portal/internal"
"github.com/h44z/wg-portal/internal/app" "github.com/h44z/wg-portal/internal/app"
"github.com/h44z/wg-portal/internal/domain" "github.com/h44z/wg-portal/internal/domain"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"os"
"time"
) )
func (m Manager) GetImportableInterfaces(ctx context.Context) ([]domain.PhysicalInterface, error) { 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 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 { if err := domain.ValidateAdminAccessRights(ctx); err != nil {
return nil, nil, err return nil, nil, err
} }
@ -145,7 +150,11 @@ func (m Manager) ApplyPeerDefaults(ctx context.Context, in *domain.Interface) er
return nil 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 { if err := domain.ValidateAdminAccessRights(ctx); err != nil {
return err return err
} }
@ -177,22 +186,24 @@ func (m Manager) RestoreInterfaceState(ctx context.Context, updateDbOnError bool
if err != nil { if err != nil {
if updateDbOnError { if updateDbOnError {
// disable interface in database as no physical interface exists // disable interface in database as no physical interface exists
_ = m.db.SaveInterface(ctx, iface.Identifier, func(in *domain.Interface) (*domain.Interface, error) { _ = m.db.SaveInterface(ctx, iface.Identifier,
now := time.Now() func(in *domain.Interface) (*domain.Interface, error) {
in.Disabled = &now // set now := time.Now()
in.DisabledReason = domain.DisabledReasonInterfaceMissing in.Disabled = &now // set
return in, nil in.DisabledReason = domain.DisabledReasonInterfaceMissing
}) return in, nil
})
} }
return fmt.Errorf("failed to create physical interface %s: %w", iface.Identifier, err) return fmt.Errorf("failed to create physical interface %s: %w", iface.Identifier, err)
} }
// restore peers // restore peers
for _, peer := range peers { for _, peer := range peers {
err := m.wg.SavePeer(ctx, iface.Identifier, peer.Identifier, func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error) { err := m.wg.SavePeer(ctx, iface.Identifier, peer.Identifier,
domain.MergeToPhysicalPeer(pp, &peer) func(pp *domain.PhysicalPeer) (*domain.PhysicalPeer, error) {
return pp, nil domain.MergeToPhysicalPeer(pp, &peer)
}) return pp, nil
})
if err != nil { if err != nil {
return fmt.Errorf("failed to create physical peer %s: %w", peer.Identifier, err) 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 err != nil {
if updateDbOnError { if updateDbOnError {
// disable interface in database as no physical interface is available // disable interface in database as no physical interface is available
_ = m.db.SaveInterface(ctx, iface.Identifier, func(in *domain.Interface) (*domain.Interface, error) { _ = m.db.SaveInterface(ctx, iface.Identifier,
if iface.IsDisabled() { func(in *domain.Interface) (*domain.Interface, error) {
now := time.Now() if iface.IsDisabled() {
in.Disabled = &now // set now := time.Now()
in.DisabledReason = domain.DisabledReasonInterfaceMissing in.Disabled = &now // set
} else { in.DisabledReason = domain.DisabledReasonInterfaceMissing
in.Disabled = nil } else {
in.DisabledReason = "" in.Disabled = nil
} in.DisabledReason = ""
return in, nil }
}) return in, nil
})
} }
return fmt.Errorf("failed to change physical interface state for %s: %w", iface.Identifier, err) 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) return fmt.Errorf("deletion failure: %w", err)
} }
fwMark := int(existingInterface.FirewallMark) fwMark := existingInterface.FirewallMark
if physicalInterface != nil && fwMark == 0 { if physicalInterface != nil && fwMark == 0 {
fwMark = int(physicalInterface.FirewallMark) fwMark = physicalInterface.FirewallMark
} }
m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{ m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{
FwMark: fwMark, FwMark: fwMark,
@ -410,7 +422,10 @@ func (m Manager) DeleteInterface(ctx context.Context, id domain.InterfaceIdentif
// region helper-functions // 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) stateChanged := m.hasInterfaceStateChanged(ctx, iface)
if err := m.handleInterfacePreSaveHooks(stateChanged, iface); err != nil { 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) { err := m.db.SaveInterface(ctx, iface.Identifier, func(i *domain.Interface) (*domain.Interface, error) {
iface.CopyCalculatedAttributes(i) iface.CopyCalculatedAttributes(i)
err := m.wg.SaveInterface(ctx, iface.Identifier, func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error) { err := m.wg.SaveInterface(ctx, iface.Identifier,
domain.MergeToPhysicalInterface(pi, iface) func(pi *domain.PhysicalInterface) (*domain.PhysicalInterface, error) {
return pi, nil domain.MergeToPhysicalInterface(pi, iface)
}) return pi, nil
})
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to save physical interface %s: %w", iface.Identifier, err) 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)) m.bus.Publish(app.TopicRouteUpdate, "interface updated: "+string(iface.Identifier))
if iface.IsDisabled() { if iface.IsDisabled() {
physicalInterface, _ := m.wg.GetInterface(ctx, iface.Identifier) physicalInterface, _ := m.wg.GetInterface(ctx, iface.Identifier)
fwMark := int(iface.FirewallMark) fwMark := iface.FirewallMark
if physicalInterface != nil && fwMark == 0 { if physicalInterface != nil && fwMark == 0 {
fwMark = int(physicalInterface.FirewallMark) fwMark = physicalInterface.FirewallMark
} }
m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{ m.bus.Publish(app.TopicRouteRemove, domain.RoutingTableInfo{
FwMark: fwMark, FwMark: fwMark,
@ -702,18 +718,18 @@ func (m Manager) importPeer(ctx context.Context, in *domain.Interface, p *domain
} }
peer.InterfaceIdentifier = in.Identifier peer.InterfaceIdentifier = in.Identifier
peer.EndpointPublicKey = domain.StringConfigOption{Value: in.PublicKey, Overridable: true} peer.EndpointPublicKey = domain.NewConfigOption(in.PublicKey, true)
peer.AllowedIPsStr = domain.StringConfigOption{Value: in.PeerDefAllowedIPsStr, Overridable: 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.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.DnsStr = domain.NewConfigOption(in.PeerDefDnsStr, true)
peer.Interface.DnsSearchStr = domain.StringConfigOption{Value: in.PeerDefDnsSearchStr, Overridable: true} peer.Interface.DnsSearchStr = domain.NewConfigOption(in.PeerDefDnsSearchStr, true)
peer.Interface.Mtu = domain.IntConfigOption{Value: in.PeerDefMtu, Overridable: true} peer.Interface.Mtu = domain.NewConfigOption(in.PeerDefMtu, true)
peer.Interface.FirewallMark = domain.Int32ConfigOption{Value: in.PeerDefFirewallMark, Overridable: true} peer.Interface.FirewallMark = domain.NewConfigOption(in.PeerDefFirewallMark, true)
peer.Interface.RoutingTable = domain.StringConfigOption{Value: in.PeerDefRoutingTable, Overridable: true} peer.Interface.RoutingTable = domain.NewConfigOption(in.PeerDefRoutingTable, true)
peer.Interface.PreUp = domain.StringConfigOption{Value: in.PeerDefPreUp, Overridable: true} peer.Interface.PreUp = domain.NewConfigOption(in.PeerDefPreUp, true)
peer.Interface.PostUp = domain.StringConfigOption{Value: in.PeerDefPostUp, Overridable: true} peer.Interface.PostUp = domain.NewConfigOption(in.PeerDefPostUp, true)
peer.Interface.PreDown = domain.StringConfigOption{Value: in.PeerDefPreDown, Overridable: true} peer.Interface.PreDown = domain.NewConfigOption(in.PeerDefPreDown, true)
peer.Interface.PostDown = domain.StringConfigOption{Value: in.PeerDefPostDown, Overridable: true} peer.Interface.PostDown = domain.NewConfigOption(in.PeerDefPostDown, true)
switch in.Type { switch in.Type {
case domain.InterfaceTypeAny: case domain.InterfaceTypeAny:

View File

@ -102,12 +102,12 @@ func (m Manager) PreparePeer(ctx context.Context, id domain.InterfaceIdentifier)
CreatedAt: time.Now(), CreatedAt: time.Now(),
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
}, },
Endpoint: domain.NewStringConfigOption(iface.PeerDefEndpoint, true), Endpoint: domain.NewConfigOption(iface.PeerDefEndpoint, true),
EndpointPublicKey: domain.NewStringConfigOption(iface.PublicKey, true), EndpointPublicKey: domain.NewConfigOption(iface.PublicKey, true),
AllowedIPsStr: domain.NewStringConfigOption(iface.PeerDefAllowedIPsStr, true), AllowedIPsStr: domain.NewConfigOption(iface.PeerDefAllowedIPsStr, true),
ExtraAllowedIPsStr: "", ExtraAllowedIPsStr: "",
PresharedKey: pk, PresharedKey: pk,
PersistentKeepalive: domain.NewIntConfigOption(iface.PeerDefPersistentKeepalive, true), PersistentKeepalive: domain.NewConfigOption(iface.PeerDefPersistentKeepalive, true),
DisplayName: fmt.Sprintf("Peer %s", internal.TruncateString(string(peerId), 8)), DisplayName: fmt.Sprintf("Peer %s", internal.TruncateString(string(peerId), 8)),
Identifier: peerId, Identifier: peerId,
UserIdentifier: currentUser.Id, UserIdentifier: currentUser.Id,
@ -121,15 +121,15 @@ func (m Manager) PreparePeer(ctx context.Context, id domain.InterfaceIdentifier)
Type: peerMode, Type: peerMode,
Addresses: ips, Addresses: ips,
CheckAliveAddress: "", CheckAliveAddress: "",
DnsStr: domain.NewStringConfigOption(iface.PeerDefDnsStr, true), DnsStr: domain.NewConfigOption(iface.PeerDefDnsStr, true),
DnsSearchStr: domain.NewStringConfigOption(iface.PeerDefDnsSearchStr, true), DnsSearchStr: domain.NewConfigOption(iface.PeerDefDnsSearchStr, true),
Mtu: domain.NewIntConfigOption(iface.PeerDefMtu, true), Mtu: domain.NewConfigOption(iface.PeerDefMtu, true),
FirewallMark: domain.NewInt32ConfigOption(iface.PeerDefFirewallMark, true), FirewallMark: domain.NewConfigOption(iface.PeerDefFirewallMark, true),
RoutingTable: domain.NewStringConfigOption(iface.PeerDefRoutingTable, true), RoutingTable: domain.NewConfigOption(iface.PeerDefRoutingTable, true),
PreUp: domain.NewStringConfigOption(iface.PeerDefPreUp, true), PreUp: domain.NewConfigOption(iface.PeerDefPreUp, true),
PostUp: domain.NewStringConfigOption(iface.PeerDefPostUp, true), PostUp: domain.NewConfigOption(iface.PeerDefPostUp, true),
PreDown: domain.NewStringConfigOption(iface.PeerDefPreDown, true), PreDown: domain.NewConfigOption(iface.PeerDefPreDown, true),
PostDown: domain.NewStringConfigOption(iface.PeerDefPostDown, 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 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 { if err := domain.ValidateAdminAccessRights(ctx); err != nil {
return nil, err return nil, err
} }

View File

@ -2,13 +2,14 @@ package domain
import ( import (
"fmt" "fmt"
"github.com/h44z/wg-portal/internal"
"github.com/sirupsen/logrus"
"math" "math"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/h44z/wg-portal/internal"
"github.com/sirupsen/logrus"
) )
const ( 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 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 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 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 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 PeerDefAllowedIPsStr string // the default allowed IP string for the peer
PeerDefMtu int // the default device MTU PeerDefMtu int // the default device MTU
PeerDefPersistentKeepalive int // the default persistent keep-alive Value PeerDefPersistentKeepalive int // the default persistent keep-alive Value
PeerDefFirewallMark int32 // default firewall mark PeerDefFirewallMark uint32 // default firewall mark
PeerDefRoutingTable string // the default routing table PeerDefRoutingTable string // the default routing table
PeerDefPreUp string // default action that is executed before the device is up 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 Addresses []Cidr // the interface ip addresses
Mtu int // the device MTU Mtu int // the device MTU
FirewallMark int32 // a firewall mark FirewallMark uint32 // a firewall mark
DeviceUp bool // device status DeviceUp bool // device status
@ -223,7 +224,7 @@ func MergeToPhysicalInterface(pi *PhysicalInterface, i *Interface) {
} }
type RoutingTableInfo struct { type RoutingTableInfo struct {
FwMark int FwMark uint32
Table int Table int
} }
@ -241,7 +242,7 @@ func (r RoutingTableInfo) ManagementEnabled() bool {
func (r RoutingTableInfo) GetRoutingTable() int { func (r RoutingTableInfo) GetRoutingTable() int {
if r.Table <= 0 { 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 return r.Table

View File

@ -1,47 +1,19 @@
package domain package domain
type StringConfigOption struct { type ConfigOption[T any] struct {
Value string `gorm:"column:v"` Value T `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"`
Overridable bool `gorm:"column:o"` Overridable bool `gorm:"column:o"`
} }
func (o IntConfigOption) GetValue() int { func (o *ConfigOption[T]) GetValue() T {
return o.Value return o.Value
} }
func (o *IntConfigOption) SetValue(value int) { func (o *ConfigOption[T]) SetValue(value T) {
o.Value = value o.Value = value
} }
func (o *IntConfigOption) TrySetValue(value int) bool { func (o *ConfigOption[T]) TrySetValue(value T) bool {
if o.Overridable { if o.Overridable {
o.Value = value o.Value = value
return true return true
@ -49,64 +21,8 @@ func (o *IntConfigOption) TrySetValue(value int) bool {
return false return false
} }
func NewIntConfigOption(value int, overridable bool) IntConfigOption { func NewConfigOption[T any](value T, overridable bool) ConfigOption[T] {
return IntConfigOption{ return ConfigOption[T]{
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{
Value: value, Value: value,
Overridable: overridable, Overridable: overridable,
} }

View File

@ -2,12 +2,13 @@ package domain
import ( import (
"fmt" "fmt"
"github.com/h44z/wg-portal/internal"
"net" "net"
"regexp" "regexp"
"strings" "strings"
"time" "time"
"github.com/h44z/wg-portal/internal"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
@ -31,12 +32,12 @@ type Peer struct {
// WireGuard specific (for the [peer] section of the config file) // WireGuard specific (for the [peer] section of the config file)
Endpoint StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_"` // the endpoint address Endpoint ConfigOption[string] `gorm:"embedded;embeddedPrefix:endpoint_"` // the endpoint address
EndpointPublicKey StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_pubkey_"` // the endpoint public key EndpointPublicKey ConfigOption[string] `gorm:"embedded;embeddedPrefix:endpoint_pubkey_"` // the endpoint public key
AllowedIPsStr StringConfigOption `gorm:"embedded;embeddedPrefix:allowed_ips_str_"` // all allowed ip subnets, comma seperated 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 ExtraAllowedIPsStr string // all allowed ip subnets on the server side, comma seperated
PresharedKey PreSharedKey // the pre-shared Key of the peer PresharedKey PreSharedKey // the pre-shared Key of the peer
PersistentKeepalive IntConfigOption `gorm:"embedded;embeddedPrefix:persistent_keep_alive_"` // the persistent keep-alive interval PersistentKeepalive ConfigOption[int] `gorm:"embedded;embeddedPrefix:persistent_keep_alive_"` // the persistent keep-alive interval
// WG Portal specific // WG Portal specific
@ -124,18 +125,18 @@ type PeerInterfaceConfig struct {
Type InterfaceType `gorm:"column:iface_type"` // the interface type (server, client, any) Type InterfaceType `gorm:"column:iface_type"` // the interface type (server, client, any)
Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses 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 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 DnsStr ConfigOption[string] `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 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 IntConfigOption `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU Mtu ConfigOption[int] `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU
FirewallMark Int32ConfigOption `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark FirewallMark ConfigOption[uint32] `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark
RoutingTable StringConfigOption `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table 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 PreUp ConfigOption[string] `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 PostUp ConfigOption[string] `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 PreDown ConfigOption[string] `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 PostDown ConfigOption[string] `gorm:"embedded;embeddedPrefix:iface_post_down_"` // action that is executed after the device is down
} }
func (p *PeerInterfaceConfig) AddressStr() string { func (p *PeerInterfaceConfig) AddressStr() string {
@ -202,12 +203,12 @@ func (p PhysicalPeer) GetAllowedIPs() []net.IPNet {
func ConvertPhysicalPeer(pp *PhysicalPeer) *Peer { func ConvertPhysicalPeer(pp *PhysicalPeer) *Peer {
peer := &Peer{ peer := &Peer{
Endpoint: StringConfigOption{Value: pp.Endpoint, Overridable: true}, Endpoint: NewConfigOption(pp.Endpoint, true),
EndpointPublicKey: StringConfigOption{Value: "", Overridable: true}, EndpointPublicKey: NewConfigOption("", true),
AllowedIPsStr: StringConfigOption{Value: "", Overridable: true}, AllowedIPsStr: NewConfigOption("", true),
ExtraAllowedIPsStr: "", ExtraAllowedIPsStr: "",
PresharedKey: pp.PresharedKey, PresharedKey: pp.PresharedKey,
PersistentKeepalive: IntConfigOption{Value: pp.PersistentKeepalive, Overridable: true}, PersistentKeepalive: NewConfigOption(pp.PersistentKeepalive, true),
DisplayName: string(pp.Identifier), DisplayName: string(pp.Identifier),
Identifier: pp.Identifier, Identifier: pp.Identifier,
UserIdentifier: "", UserIdentifier: "",