diff --git a/assets/tpl/admin_create_clients.html b/assets/tpl/admin_create_clients.html index e2a3b06..5278323 100644 --- a/assets/tpl/admin_create_clients.html +++ b/assets/tpl/admin_create_clients.html @@ -24,13 +24,13 @@
- +
- +
diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 10fc99c..c34b419 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -28,7 +28,8 @@ - + + {{if .EditableKeys}}
@@ -39,13 +40,13 @@
- +
- +
{{else}} @@ -61,19 +62,19 @@
- +
- +
- +
@@ -95,7 +96,7 @@
- +
@@ -108,7 +109,7 @@
- + @@ -146,7 +147,7 @@
- +
@@ -168,19 +169,19 @@
- +
- +
- +
@@ -236,7 +237,7 @@
- +
@@ -258,13 +259,13 @@
- +
- +
@@ -276,7 +277,7 @@
- +
@@ -304,7 +305,7 @@
- +
diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index dc1cf39..50c3e6b 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -24,7 +24,7 @@ Client Mode @@ -34,7 +34,7 @@
- +

Server's interface configuration

@@ -46,13 +46,13 @@
- +
- +
{{else}} @@ -67,18 +67,18 @@
- +
- +

Client's global configuration

- +
@@ -138,7 +138,7 @@ - +

Client's interface configuration

@@ -150,13 +150,13 @@
- +
- +
{{else}} @@ -171,7 +171,7 @@
- +
@@ -220,7 +220,6 @@ Cancel - Apply Global Settings to peers
@@ -229,7 +228,7 @@
- +

Custom interface configuration

@@ -241,13 +240,13 @@
- +
- +
{{else}} @@ -266,21 +265,7 @@
- -
-
-
-
- - -
-
-
- - -
+
@@ -293,6 +278,16 @@
+
+
+
+ + +
+
+

Peer's global configuration

@@ -314,6 +309,12 @@
+
+
+ + +
+

Interface configuration hooks

diff --git a/assets/tpl/admin_edit_user.html b/assets/tpl/admin_edit_user.html index e42de7a..80a7324 100644 --- a/assets/tpl/admin_edit_user.html +++ b/assets/tpl/admin_edit_user.html @@ -27,7 +27,7 @@
- +
{{else}} @@ -36,13 +36,13 @@
- +
- +
@@ -54,7 +54,7 @@
- +
diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 085477c..67a0cb6 100644 --- a/internal/server/handlers_interface.go +++ b/internal/server/handlers_interface.go @@ -1,6 +1,7 @@ package server import ( + "fmt" "net/http" "strings" @@ -48,6 +49,21 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) { formDevice.DefaultAllowedIPsStr = common.ListToString(common.ParseStringList(formDevice.DefaultAllowedIPsStr)) formDevice.DNSStr = common.ListToString(common.ParseStringList(formDevice.DNSStr)) + // Clean interface parameters based on interface type + switch formDevice.Type { + case wireguard.DeviceTypeClient: + formDevice.ListenPort = 0 + formDevice.DefaultEndpoint = "" + formDevice.DefaultAllowedIPsStr = "" + formDevice.DefaultPersistentKeepalive = 0 + formDevice.SaveConfig = false + case wireguard.DeviceTypeServer: + formDevice.FirewallMark = 0 + formDevice.RoutingTable = "" + formDevice.SaveConfig = false + case wireguard.DeviceTypeCustom: + } + // Update WireGuard device err := s.wg.UpdateDevice(formDevice.DeviceName, formDevice.GetConfig()) if err != nil { @@ -118,15 +134,37 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) { device := s.peers.GetDevice(currentSession.DeviceName) peers := s.peers.GetAllPeers(device.DeviceName) + if device.Type == wireguard.DeviceTypeClient { + SetFlashMessage(c, "Cannot apply global configuration while interface is in client mode.", "danger") + c.Redirect(http.StatusSeeOther, "/admin/device/edit") + return + } + + updateCounter := 0 for _, peer := range peers { + if peer.IgnoreGlobalSettings { + continue + } + peer.AllowedIPsStr = device.DefaultAllowedIPsStr + peer.Endpoint = device.DefaultEndpoint + peer.PersistentKeepalive = device.DefaultPersistentKeepalive + peer.DNSStr = device.DNSStr + peer.Mtu = device.Mtu + + if device.Type == wireguard.DeviceTypeServer { + peer.EndpointPublicKey = device.PublicKey + } + if err := s.peers.UpdatePeer(peer); err != nil { SetFlashMessage(c, err.Error(), "danger") c.Redirect(http.StatusSeeOther, "/admin/device/edit") + return } + updateCounter++ } - SetFlashMessage(c, "Allowed IP's updated for all clients.", "success") + SetFlashMessage(c, fmt.Sprintf("Global configuration updated for %d clients.", updateCounter), "success") c.Redirect(http.StatusSeeOther, "/admin/device/edit") return } diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index 9304a65..e94a04f 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -23,7 +23,6 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { peer := wireguard.Peer{} peer.IsNew = true - peer.AllowedIPsStr = dev.DefaultAllowedIPsStr peerIPs := make([]string, len(deviceIPs)) for i := range deviceIPs { freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) @@ -46,24 +45,36 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { peer.PublicKey = key.PublicKey().String() 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 + peer.DNSStr = dev.DNSStr + peer.PersistentKeepalive = dev.DefaultPersistentKeepalive + peer.AllowedIPsStr = dev.DefaultAllowedIPsStr + peer.Mtu = dev.Mtu + case wireguard.DeviceTypeClient: + } + return peer, nil } -// CreatePeerByEmail creates a new peer for the given email. If no user with the specified email was found, a new one -// will be created. +// CreatePeerByEmail creates a new peer for the given email. func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disabled bool) error { - user, err := s.users.GetOrCreateUser(email) - if err != nil { - return errors.WithMessagef(err, "failed to load/create related user %s", email) - } + user := s.users.GetUser(email) peer, err := s.PrepareNewPeer(device) if err != nil { return errors.WithMessage(err, "failed to prepare new peer") } peer.Email = email - peer.Identifier = fmt.Sprintf("%s %s (%s)", user.Firstname, user.Lastname, identifierSuffix) - + if user != nil { + peer.Identifier = fmt.Sprintf("%s %s (%s)", user.Firstname, user.Lastname, identifierSuffix) + } else { + peer.Identifier = fmt.Sprintf("%s (%s)", email, identifierSuffix) + } now := time.Now() if disabled { peer.DeactivatedAt = &now diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index 57e6dc2..de6bc3e 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -90,7 +90,7 @@ type Peer struct { // Misc. WireGuard Settings EndpointPublicKey string `form:"endpointpubkey" binding:"required,base64"` // the public key of the remote endpoint PrivateKey string `form:"privkey" binding:"omitempty,base64"` - IPsStr string `form:"ip" binding:"cidrlist,required_if=devicetype server"` // a comma separated list of IPs of the client + IPsStr string `form:"ip" binding:"cidrlist,required_if=DeviceType server"` // a comma separated list of IPs of the client DNSStr string `form:"dns" binding:"iplist"` // comma separated list of the DNS servers for the client // Global Device Settings (can be ignored, only make sense if device is in server mode) Mtu int `form:"mtu" binding:"gte=0,lte=1500"` @@ -230,7 +230,7 @@ type Device struct { // Core WireGuard Settings (Interface section) PrivateKey string `form:"privkey" binding:"required,base64"` - ListenPort int `form:"port" binding:"omitempty,gt=0,lt=65535,required_if=devicetype server"` + ListenPort int `form:"port" binding:"required_if=Type server,omitempty,gt=0,lt=65535"` FirewallMark int32 `form:"firewallmark" binding:"gte=0"` // Misc. WireGuard Settings PublicKey string `form:"pubkey" binding:"required,base64"` @@ -245,7 +245,7 @@ type Device struct { SaveConfig bool `form:"saveconfig"` // if set to `true', the configuration is saved from the current state of the interface upon shutdown, wg-quick addition // Settings that are applied to all peer by default - DefaultEndpoint string `form:"endpoint" binding:"omitempty,hostname_port,required_if=devicetype server"` + DefaultEndpoint string `form:"endpoint" binding:"required_if=Type server,omitempty,hostname_port"` DefaultAllowedIPsStr string `form:"allowedip" binding:"cidrlist"` // comma separated list of IPs that are used in the client config file DefaultPersistentKeepalive int `form:"keepalive" binding:"gte=0"` @@ -386,21 +386,24 @@ func (m *PeerManager) InitFromPhysicalInterface() error { } } - // Check if entries already exist in database, if not create them + // Check if device already exists in database, if not, create it + if err := m.validateOrCreateDevice(*device, ipAddresses, mtu); err != nil { + return errors.WithMessagef(err, "failed to validate device %s", device.Name) + } + + // Check if entries already exist in database, if not, create them for _, peer := range peers { if err := m.validateOrCreatePeer(deviceName, peer); err != nil { return errors.WithMessagef(err, "failed to validate peer %s for device %s", peer.PublicKey, deviceName) } } - if err := m.validateOrCreateDevice(*device, ipAddresses, mtu); err != nil { - return errors.WithMessagef(err, "failed to validate device %s", device.Name) - } } return nil } // validateOrCreatePeer checks if the given WireGuard peer already exists in the database, if not, the peer entry will be created +// 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) @@ -408,21 +411,22 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e if peer.PublicKey == "" { // peer not found, create peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(wgPeer.PublicKey.String()))) peer.PublicKey = wgPeer.PublicKey.String() - peer.PrivateKey = "" // UNKNOWN if wgPeer.PresharedKey != (wgtypes.Key{}) { peer.PresharedKey = wgPeer.PresharedKey.String() } peer.Email = "autodetected@example.com" - peer.Identifier = "Autodetected (" + peer.PublicKey[0:8] + ")" + peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")" peer.UpdatedAt = time.Now() peer.CreatedAt = time.Now() - IPs := make([]string, len(wgPeer.AllowedIPs)) + IPs := make([]string, len(wgPeer.AllowedIPs)) // use allowed IP's as the peer IP's for i, ip := range wgPeer.AllowedIPs { IPs[i] = ip.String() } - peer.AllowedIPsStr = "" // UNKNOWN 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 { @@ -439,11 +443,12 @@ func (m *PeerManager) validateOrCreateDevice(dev wgtypes.Device, ipAddresses []s m.db.Where("device_name = ?", dev.Name).FirstOrInit(&device) if device.PublicKey == "" { // device not found, create - device.Type = DeviceTypeCustom // imported device, we do not (easily) know if it is a client or server + device.Type = DeviceTypeServer // imported device, we assume that server mode is used device.PublicKey = dev.PublicKey.String() device.PrivateKey = dev.PrivateKey.String() device.DeviceName = dev.Name device.ListenPort = dev.ListenPort + device.FirewallMark = int32(dev.FirewallMark) device.Mtu = 0 device.DefaultPersistentKeepalive = 16 // Default device.IPsStr = strings.Join(ipAddresses, ", ") diff --git a/internal/wireguard/template.go b/internal/wireguard/template.go index 99cdb1c..d9c2e4a 100644 --- a/internal/wireguard/template.go +++ b/internal/wireguard/template.go @@ -2,8 +2,8 @@ package wireguard import ( "embed" - "html/template" "strings" + "text/template" ) //go:embed tpl/* diff --git a/internal/wireguard/tpl/interface.tpl b/internal/wireguard/tpl/interface.tpl index 8540c2a..e851b14 100644 --- a/internal/wireguard/tpl/interface.tpl +++ b/internal/wireguard/tpl/interface.tpl @@ -48,7 +48,7 @@ PublicKey = {{ .PublicKey }} PresharedKey = {{ .PresharedKey }} {{- end}} AllowedIPs = {{ .AllowedIPsStr }} -{{- if ne .Endpoint ""}} +{{- if and (ne .Endpoint "") (ne $.Interface.Type "server")}} Endpoint = {{ .Endpoint }} {{- end}} {{- if ne .PersistentKeepalive 0}} diff --git a/internal/wireguard/tpl/peer.tpl b/internal/wireguard/tpl/peer.tpl index ac55305..68e40c3 100644 --- a/internal/wireguard/tpl/peer.tpl +++ b/internal/wireguard/tpl/peer.tpl @@ -18,7 +18,7 @@ MTU = {{.Peer.Mtu}} [Peer] PublicKey = {{ .Peer.EndpointPublicKey }} -Endpoint = {{ .Server.Endpoint }} +Endpoint = {{ .Peer.Endpoint }} AllowedIPs = {{ .Peer.AllowedIPsStr }} {{- if .Peer.PresharedKey}} PresharedKey = {{ .Peer.PresharedKey }}