-
-
+
-
-
Client's global configuration
-
diff --git a/internal/server/handlers_common.go b/internal/server/handlers_common.go
index 84e028a..2fa1087 100644
--- a/internal/server/handlers_common.go
+++ b/internal/server/handlers_common.go
@@ -160,6 +160,7 @@ func (s *Server) updateFormInSession(c *gin.Context, formData interface{}) error
func (s *Server) setNewPeerFormInSession(c *gin.Context) (SessionData, error) {
currentSession := GetSessionData(c)
+
// If session does not contain a peer form ignore update
// If url contains a formerr parameter reset the form
if currentSession.FormData == nil || c.Query("formerr") == "" {
diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go
index cf20c15..96f477e 100644
--- a/internal/server/handlers_interface.go
+++ b/internal/server/handlers_interface.go
@@ -58,8 +58,6 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) {
formDevice.DefaultPersistentKeepalive = 0
formDevice.SaveConfig = false
case wireguard.DeviceTypeServer:
- formDevice.SaveConfig = false
- case wireguard.DeviceTypeCustom:
}
// Update WireGuard device
@@ -127,6 +125,21 @@ func (s *Server) GetInterfaceConfig(c *gin.Context) {
return
}
+func (s *Server) GetSaveConfig(c *gin.Context) {
+ currentSession := GetSessionData(c)
+
+ err := s.WriteWireGuardConfigFile(currentSession.DeviceName)
+ if err != nil {
+ SetFlashMessage(c, "Failed to save WireGuard config-file: "+err.Error(), "danger")
+ c.Redirect(http.StatusSeeOther, "/admin/")
+ return
+ }
+
+ SetFlashMessage(c, "Updated WireGuard config-file", "success")
+ c.Redirect(http.StatusSeeOther, "/admin/")
+ return
+}
+
func (s *Server) GetApplyGlobalConfig(c *gin.Context) {
currentSession := GetSessionData(c)
device := s.peers.GetDevice(currentSession.DeviceName)
@@ -149,10 +162,7 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) {
peer.PersistentKeepalive = device.DefaultPersistentKeepalive
peer.DNSStr = device.DNSStr
peer.Mtu = device.Mtu
-
- if device.Type == wireguard.DeviceTypeServer {
- peer.EndpointPublicKey = device.PublicKey
- }
+ peer.EndpointPublicKey = device.PublicKey
if err := s.peers.UpdatePeer(peer); err != nil {
SetFlashMessage(c, err.Error(), "danger")
diff --git a/internal/server/routes.go b/internal/server/routes.go
index 03cf998..6eb47ac 100644
--- a/internal/server/routes.go
+++ b/internal/server/routes.go
@@ -32,6 +32,7 @@ func SetupRoutes(s *Server) {
admin.GET("/device/edit", s.GetAdminEditInterface)
admin.POST("/device/edit", s.PostAdminEditInterface)
admin.GET("/device/download", s.GetInterfaceConfig)
+ admin.GET("/device/write", s.GetSaveConfig)
admin.GET("/device/applyglobals", s.GetApplyGlobalConfig)
admin.GET("/peer/edit", s.GetAdminEditPeer)
admin.POST("/peer/edit", s.PostAdminEditPeer)
diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go
index e94a04f..5eec6b3 100644
--- a/internal/server/server_helper.go
+++ b/internal/server/server_helper.go
@@ -46,8 +46,6 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) {
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey)))
switch dev.Type {
- case wireguard.DeviceTypeCustom:
- fallthrough
case wireguard.DeviceTypeServer:
peer.EndpointPublicKey = dev.PublicKey
peer.Endpoint = dev.DefaultEndpoint
@@ -121,7 +119,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
// Create WireGuard interface
if peer.DeactivatedAt == nil {
- if err := s.wg.AddPeer(device, peer.GetConfig()); err != nil {
+ if err := s.wg.AddPeer(device, peer.GetConfig(&dev)); err != nil {
return errors.WithMessage(err, "failed to add WireGuard peer")
}
}
@@ -137,6 +135,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
// UpdatePeer updates the physical WireGuard interface and the database.
func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error {
currentPeer := s.peers.GetPeerByKey(peer.PublicKey)
+ dev := s.peers.GetDevice(peer.DeviceName)
// Update WireGuard device
var err error
@@ -144,9 +143,9 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error {
case peer.DeactivatedAt == &updateTime:
err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey)
case peer.DeactivatedAt == nil && currentPeer.Peer != nil:
- err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig())
+ err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev))
case peer.DeactivatedAt == nil && currentPeer.Peer == nil:
- err = s.wg.AddPeer(peer.DeviceName, peer.GetConfig())
+ err = s.wg.AddPeer(peer.DeviceName, peer.GetConfig(&dev))
}
if err != nil {
return errors.WithMessage(err, "failed to update WireGuard peer")
@@ -178,10 +177,11 @@ func (s *Server) DeletePeer(peer wireguard.Peer) error {
// RestoreWireGuardInterface restores the state of the physical WireGuard interface from the database.
func (s *Server) RestoreWireGuardInterface(device string) error {
activePeers := s.peers.GetActivePeers(device)
+ dev := s.peers.GetDevice(device)
for i := range activePeers {
if activePeers[i].Peer == nil {
- if err := s.wg.AddPeer(device, activePeers[i].GetConfig()); err != nil {
+ if err := s.wg.AddPeer(device, activePeers[i].GetConfig(&dev)); err != nil {
return errors.WithMessage(err, "failed to add WireGuard peer")
}
}
diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go
index de6bc3e..56a8dfd 100644
--- a/internal/wireguard/peermanager.go
+++ b/internal/wireguard/peermanager.go
@@ -126,8 +126,15 @@ func (p Peer) GetAllowedIPs() []string {
return common.ParseStringList(p.AllowedIPsStr)
}
-func (p Peer) GetConfig() wgtypes.PeerConfig {
- publicKey, _ := wgtypes.ParseKey(p.PublicKey)
+func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig {
+ var publicKey wgtypes.Key
+ switch dev.Type {
+ case DeviceTypeServer:
+ publicKey, _ = wgtypes.ParseKey(p.PublicKey)
+ case DeviceTypeClient:
+ publicKey, _ = wgtypes.ParseKey(p.EndpointPublicKey)
+ }
+
var presharedKey *wgtypes.Key
if p.PresharedKey != "" {
presharedKeyTmp, _ := wgtypes.ParseKey(p.PresharedKey)
@@ -218,7 +225,6 @@ type DeviceType string
const (
DeviceTypeServer DeviceType = "server"
DeviceTypeClient DeviceType = "client"
- DeviceTypeCustom DeviceType = "custom"
)
type Device struct {
@@ -272,7 +278,6 @@ func (d Device) IsValid() bool {
if len(d.GetIPAddresses()) == 0 {
return false
}
- case DeviceTypeCustom:
}
return true
@@ -360,6 +365,17 @@ func NewPeerManager(db *gorm.DB, wg *Manager) (*PeerManager, error) {
}
}
+ // validate and update existing peers if needed
+ for _, deviceName := range wg.Cfg.DeviceNames {
+ dev := pm.GetDevice(deviceName)
+ peers = pm.GetAllPeers(deviceName)
+ for i := range peers {
+ if err := pm.fixPeerDefaultData(&peers[i], &dev); err != nil {
+ return nil, errors.WithMessagef(err, "unable to fix peers for interface %s", deviceName)
+ }
+ }
+ }
+
return pm, nil
}
@@ -406,16 +422,33 @@ func (m *PeerManager) InitFromPhysicalInterface() error {
// assumption: server mode is used
func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) error {
peer := Peer{}
- m.db.Where("public_key = ?", wgPeer.PublicKey.String()).FirstOrInit(&peer)
+ m.db.Where("public_key = ? OR endpoint_public_key = ?", wgPeer.PublicKey.String(), wgPeer.PublicKey.String()).FirstOrInit(&peer)
+
+ dev := m.GetDevice(device)
if peer.PublicKey == "" { // peer not found, create
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(wgPeer.PublicKey.String())))
- peer.PublicKey = wgPeer.PublicKey.String()
+ if dev.Type == DeviceTypeServer {
+ peer.PublicKey = wgPeer.PublicKey.String()
+ peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")"
+ } else if dev.Type == DeviceTypeClient {
+ // create a new key pair, not really needed but otherwise our "client exists" detection does not work...
+ key, err := wgtypes.GeneratePrivateKey()
+ if err != nil {
+ return errors.Wrap(err, "failed to generate dummy private key")
+ }
+ peer.PrivateKey = key.String()
+ peer.PublicKey = key.PublicKey().String()
+ peer.EndpointPublicKey = wgPeer.PublicKey.String()
+ if wgPeer.Endpoint != nil {
+ peer.Endpoint = wgPeer.Endpoint.String()
+ }
+ peer.Identifier = "Autodetected Endpoint (" + peer.EndpointPublicKey[0:8] + ")"
+ }
if wgPeer.PresharedKey != (wgtypes.Key{}) {
peer.PresharedKey = wgPeer.PresharedKey.String()
}
peer.Email = "autodetected@example.com"
- peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")"
peer.UpdatedAt = time.Now()
peer.CreatedAt = time.Now()
IPs := make([]string, len(wgPeer.AllowedIPs)) // use allowed IP's as the peer IP's
@@ -424,9 +457,6 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e
}
peer.SetIPAddresses(IPs...)
peer.DeviceName = device
- if wgPeer.Endpoint != nil {
- peer.Endpoint = wgPeer.Endpoint.String() // TODO: do we need to import this for server mode?
- }
res := m.db.Create(&peer)
if res.Error != nil {
@@ -494,6 +524,29 @@ func (m *PeerManager) populatePeerData(peer *Peer) {
peer.IsOnline = false
}
+// fixPeerDefaultData tries to fill all required fields for the given peer
+func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error {
+ updatePeer := false
+
+ switch device.Type {
+ case DeviceTypeServer:
+ if peer.Endpoint == "" {
+ peer.Endpoint = device.DefaultEndpoint
+ updatePeer = true
+ }
+ if peer.EndpointPublicKey == "" {
+ peer.EndpointPublicKey = device.PublicKey
+ updatePeer = true
+ }
+ case DeviceTypeClient:
+ }
+
+ if updatePeer {
+ return m.UpdatePeer(*peer)
+ }
+ return nil
+}
+
// populateDeviceData enriches the device struct with WireGuard live data like interface information
func (m *PeerManager) populateDeviceData(device *Device) {
// set data from WireGuard interface
diff --git a/internal/wireguard/tpl/interface.tpl b/internal/wireguard/tpl/interface.tpl
index e851b14..f8aa3d2 100644
--- a/internal/wireguard/tpl/interface.tpl
+++ b/internal/wireguard/tpl/interface.tpl
@@ -10,13 +10,16 @@
PrivateKey = {{ .Interface.PrivateKey }}
Address = {{ .Interface.IPsStr }}
-# Misc. settings
+# Misc. settings (optional)
{{- if ne .Interface.ListenPort 0}}
ListenPort = {{ .Interface.ListenPort }}
{{- end}}
{{- if ne .Interface.Mtu 0}}
MTU = {{.Interface.Mtu}}
{{- end}}
+{{- if and (ne .Interface.DNSStr "") (eq $.Interface.Type "client")}}
+DNS = {{ .Interface.DNSStr }}
+{{- end}}
{{- if ne .Interface.FirewallMark 0}}
FwMark = {{.Interface.FirewallMark}}
{{- end}}
@@ -27,11 +30,19 @@ Table = {{.Interface.RoutingTable}}
SaveConfig = true
{{- end}}
-# Interface hooks
+# Interface hooks (optional)
+{{- if .Interface.PreUp}}
PreUp = {{ .Interface.PreUp }}
+{{- end}}
+{{- if .Interface.PostUp}}
PostUp = {{ .Interface.PostUp }}
+{{- end}}
+{{- if .Interface.PreDown}}
PreDown = {{ .Interface.PreDown }}
+{{- end}}
+{{- if .Interface.PostDown}}
PostDown = {{ .Interface.PostDown }}
+{{- end}}
#
# Peers
@@ -43,12 +54,24 @@ PostDown = {{ .Interface.PostDown }}
# -WGP- Peer email: {{.Email}}
# -WGP- PrivateKey: {{.PrivateKey}}
[Peer]
+{{- if eq $.Interface.Type "server"}}
PublicKey = {{ .PublicKey }}
+{{- end}}
+{{- if eq $.Interface.Type "client"}}
+PublicKey = {{ .EndpointPublicKey }}
+{{- end}}
{{- if .PresharedKey}}
PresharedKey = {{ .PresharedKey }}
{{- end}}
+{{- if eq $.Interface.Type "server"}}
+AllowedIPs = {{ .IPsStr }}
+{{- end}}
+{{- if eq $.Interface.Type "client"}}
+{{- if .AllowedIPsStr}}
AllowedIPs = {{ .AllowedIPsStr }}
-{{- if and (ne .Endpoint "") (ne $.Interface.Type "server")}}
+{{- end}}
+{{- end}}
+{{- if and (ne .Endpoint "") (eq $.Interface.Type "client")}}
Endpoint = {{ .Endpoint }}
{{- end}}
{{- if ne .PersistentKeepalive 0}}
diff --git a/internal/wireguard/tpl/peer.tpl b/internal/wireguard/tpl/peer.tpl
index 68e40c3..5899308 100644
--- a/internal/wireguard/tpl/peer.tpl
+++ b/internal/wireguard/tpl/peer.tpl
@@ -8,7 +8,7 @@
PrivateKey = {{ .Peer.PrivateKey }}
Address = {{ .Peer.IPsStr }}
-# Misc. settings
+# Misc. settings (optional)
{{- if .Peer.DNSStr}}
DNS = {{ .Peer.DNSStr }}
{{- end}}