mirror of
				https://github.com/h44z/wg-portal.git
				synced 2025-11-03 23:56:18 +00:00 
			
		
		
		
	chore: update dependencies, refactor option types
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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),
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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:      "",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user