From 116a86c5e7cc46ff11e6a46812d6c97b701e71f3 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Fri, 2 Apr 2021 23:48:30 +0200 Subject: [PATCH 01/11] WIP: support different interface types: server, client and custom. Show different UI for each type. --- assets/tpl/admin_edit_interface.html | 303 ++++++++++++++++++++++---- assets/tpl/admin_index.html | 6 +- internal/common/db.go | 2 +- internal/server/handlers_interface.go | 8 +- internal/server/server_helper.go | 4 +- internal/wireguard/peermanager.go | 109 +++++---- 6 files changed, 338 insertions(+), 94 deletions(-) diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index ca6add4..36abe2f 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -16,99 +16,314 @@

Edit interface {{.Device.DeviceName}}

{{template "prt_flashes.html" .}} -
+ + +
+ +
+ + + + +

Server's interface configuration

+ {{if .EditableKeys}} +
+
+ + +
+
+
+
+ + +
+
+ {{else}} + +
+
+ + +
+
+ {{end}} +
+
+ + +
+
+ + +
+
+

Client's global configuration

+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+

Interface configuration hooks

+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + + Cancel + Apply Global Settings to peers + +
+ + +
+
-

Server's interface configuration

+ +

Client's interface configuration

{{if .EditableKeys}}
- - + +
- - + +
{{else}}
- - + +
{{end}}
- - + +
-
- - -
-
-

Client's global configuration

-
-
- - +
+ +
-
- - +
+ +
-
- - +
+ +
-
-
-
- - -
-
- - +
+ +

Interface configuration hooks

- - + +
- - + +
- - + +
- - + +
Cancel - Apply Allowed IP's to clients + Apply Global Settings to peers +
+ + +
+
+ + + +

Custom interface configuration

+ {{if .EditableKeys}} +
+
+ + +
+
+
+
+ + +
+
+ {{else}} + +
+
+ + +
+
+ {{end}} +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+

Peer's global configuration

+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+

Interface configuration hooks

+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + + Cancel + Apply Global Settings to clients +
+
+
{{template "prt_footer.html" .}} diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 06a53d1..ce9d07c 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -35,7 +35,7 @@ Public Endpoint: - {{.Device.Endpoint}} + {{.Device.DefaultEndpoint}} Listening Port: @@ -61,7 +61,7 @@ Default allowed IP's: - {{.Device.AllowedIPsStr}} + {{.Device.DefaultAllowedIPsStr}} Default DNS servers: @@ -73,7 +73,7 @@ Default Keepalive Interval: - {{.Device.PersistentKeepalive}} + {{.Device.DefaultPersistentKeepalive}} diff --git a/internal/common/db.go b/internal/common/db.go index 9261c58..5cbc0ff 100644 --- a/internal/common/db.go +++ b/internal/common/db.go @@ -38,7 +38,7 @@ func GetDatabaseForConfig(cfg *DatabaseConfig) (db *gorm.DB, err error) { return } } - db, err = gorm.Open(sqlite.Open(cfg.Database), &gorm.Config{}) + db, err = gorm.Open(sqlite.Open(cfg.Database), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}) if err != nil { return } diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 3b960f6..509160c 100644 --- a/internal/server/handlers_interface.go +++ b/internal/server/handlers_interface.go @@ -45,10 +45,10 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) { } // Clean list input formDevice.IPs = common.ParseStringList(formDevice.IPsStr) - formDevice.AllowedIPs = common.ParseStringList(formDevice.AllowedIPsStr) + formDevice.DefaultAllowedIPs = common.ParseStringList(formDevice.DefaultAllowedIPsStr) formDevice.DNS = common.ParseStringList(formDevice.DNSStr) formDevice.IPsStr = common.ListToString(formDevice.IPs) - formDevice.AllowedIPsStr = common.ListToString(formDevice.AllowedIPs) + formDevice.DefaultAllowedIPsStr = common.ListToString(formDevice.DefaultAllowedIPs) formDevice.DNSStr = common.ListToString(formDevice.DNS) // Update WireGuard device @@ -122,8 +122,8 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) { peers := s.peers.GetAllPeers(device.DeviceName) for _, peer := range peers { - peer.AllowedIPs = device.AllowedIPs - peer.AllowedIPsStr = device.AllowedIPsStr + peer.AllowedIPs = device.DefaultAllowedIPs + peer.AllowedIPsStr = device.DefaultAllowedIPsStr if err := s.peers.UpdatePeer(peer); err != nil { SetFlashMessage(c, err.Error(), "danger") c.Redirect(http.StatusSeeOther, "/admin/device/edit") diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index cbe3e9c..ca35c33 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -23,7 +23,7 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { peer := wireguard.Peer{} peer.IsNew = true - peer.AllowedIPsStr = dev.AllowedIPsStr + peer.AllowedIPsStr = dev.DefaultAllowedIPsStr peer.IPs = make([]string, len(dev.IPs)) for i := range dev.IPs { freeIP, err := s.peers.GetAvailableIp(device, dev.IPs[i]) @@ -77,7 +77,7 @@ func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disab // This function also configures the new peer on the physical WireGuard interface if the peer is not deactivated. func (s *Server) CreatePeer(device string, peer wireguard.Peer) error { dev := s.peers.GetDevice(device) - peer.AllowedIPsStr = dev.AllowedIPsStr + peer.AllowedIPsStr = dev.DefaultAllowedIPsStr if peer.IPs == nil || len(peer.IPs) == 0 { peer.IPs = make([]string, len(dev.IPs)) for i := range dev.IPs { diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index 11217dc..ac923a3 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -1,5 +1,7 @@ package wireguard +// WireGuard documentation: https://manpages.debian.org/unstable/wireguard-tools/wg.8.en.html + import ( "bytes" "crypto/md5" @@ -63,26 +65,34 @@ func init() { // type Peer struct { - Peer *wgtypes.Peer `gorm:"-"` // WireGuard peer + Peer *wgtypes.Peer `gorm:"-"` // WireGuard peer + Device *Device `gorm:"foreignKey:DeviceName"` // linked WireGuard device Config string `gorm:"-"` - UID string `form:"uid" binding:"alphanum"` // uid for html identification - IsOnline bool `gorm:"-"` - IsNew bool `gorm:"-"` - Identifier string `form:"identifier" binding:"required,lt=64"` // Identifier AND Email make a WireGuard peer unique - Email string `gorm:"index" form:"mail" binding:"required,email"` - LastHandshake string `gorm:"-"` - LastHandshakeTime string `gorm:"-"` + UID string `form:"uid" binding:"alphanum"` // uid for html identification + IsOnline bool `gorm:"-"` + IsNew bool `gorm:"-"` + Identifier string `form:"identifier" binding:"required,lt=64"` // Identifier AND Email make a WireGuard peer unique + Email string `gorm:"index" form:"mail" binding:"required,email"` + LastHandshake string `gorm:"-"` + LastHandshakeTime string `gorm:"-"` + IgnoreGlobalSettings bool `form:"ignoreglobalsettings"` + DeviceName string `gorm:"index"` - IgnorePersistentKeepalive bool `form:"ignorekeepalive"` - PresharedKey string `form:"presharedkey" binding:"omitempty,base64"` - AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` - IPsStr string `form:"ip" binding:"cidrlist"` - AllowedIPs []string `gorm:"-"` // IPs that are used in the client config file - IPs []string `gorm:"-"` // The IPs of the client - PrivateKey string `form:"privkey" binding:"omitempty,base64"` - PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` - DeviceName string `gorm:"index"` + // Core WireGuard Settings + PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` + PresharedKey string `form:"presharedkey" binding:"omitempty,base64"` + AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` + AllowedIPs []string `gorm:"-"` // IPs that are used in the client config file + Endpoint string `form:"endpoint" binding:"hostname_port"` + PersistentKeepalive int `form:"keepalive" binding:"gte=0"` + + // Misc. WireGuard Settings + PrivateKey string `form:"privkey" binding:"omitempty,base64"` + IPsStr string `form:"ip" binding:"cidrlist"` + IPs []string `gorm:"-"` // The IPs of the client + DNSStr string `form:"dns" binding:"iplist"` // comma separated list of: + DNS []string `gorm:"-"` // the DNS servers for the client DeactivatedAt *time.Time CreatedBy string @@ -189,28 +199,46 @@ func (p Peer) GetConfigFileName() string { // DEVICE -------------------------------------------------------------------------------------- // +type DeviceType string + +const ( + DeviceTypeServer DeviceType = "server" + DeviceTypeClient DeviceType = "client" + DeviceTypeCustom DeviceType = "custom" +) + type Device struct { Interface *wgtypes.Device `gorm:"-"` - DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"` - PrivateKey string `form:"privkey" binding:"required,base64"` - PublicKey string `form:"pubkey" binding:"required,base64"` - PersistentKeepalive int `form:"keepalive" binding:"gte=0"` - ListenPort int `form:"port" binding:"required,gt=0"` - Mtu int `form:"mtu" binding:"gte=0,lte=1500"` - Endpoint string `form:"endpoint" binding:"required,hostname_port"` - AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` - IPsStr string `form:"ip" binding:"required,cidrlist"` - AllowedIPs []string `gorm:"-"` // IPs that are used in the client config file - IPs []string `gorm:"-"` // The IPs of the client - DNSStr string `form:"dns" binding:"iplist"` - DNS []string `gorm:"-"` // The DNS servers of the client - PreUp string `form:"preup"` - PostUp string `form:"postup"` - PreDown string `form:"predown"` - PostDown string `form:"postdown"` - CreatedAt time.Time - UpdatedAt time.Time + Type DeviceType `form:"devicetype"` + DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"` + + // Core WireGuard Settings (Interface section) + PrivateKey string `form:"privkey" binding:"required,base64"` + ListenPort int `form:"port" binding:"required,gt=0"` + FirewallMark int32 `form:"firewallmark"` + // Misc. WireGuard Settings + PublicKey string `form:"pubkey" binding:"required,base64"` + Mtu int `form:"mtu" binding:"gte=0,lte=1500"` // the interface MTU, wg-quick addition + IPsStr string `form:"ip" binding:"required,cidrlist"` // comma separated list of: + IPs []string `gorm:"-"` // the IPs of the client, wg-quick addition + DNSStr string `form:"dns" binding:"iplist"` // comma separated list of: + DNS []string `gorm:"-"` // the DNS servers of the client, wg-quick addition + RoutingTable string `form:"routingtable"` // the routing table, wg-quick addition + PreUp string `form:"preup"` // pre up script, wg-quick addition + PostUp string `form:"postup"` // post up script, wg-quick addition + PreDown string `form:"predown"` // pre down script, wg-quick addition + PostDown string `form:"postdown"` // post down script, wg-quick addition + 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:"required,hostname_port"` + DefaultAllowedIPsStr string `form:"allowedip" binding:"cidrlist"` + DefaultAllowedIPs []string `gorm:"-"` // IPs that are used in the client config file + DefaultPersistentKeepalive int `form:"keepalive" binding:"gte=0"` + + CreatedAt time.Time + UpdatedAt time.Time } func (d Device) IsValid() bool { @@ -220,7 +248,7 @@ func (d Device) IsValid() bool { if len(d.IPs) == 0 { return false } - if d.Endpoint == "" { + if d.DefaultEndpoint == "" { return false } @@ -370,12 +398,13 @@ 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.PublicKey = dev.PublicKey.String() device.PrivateKey = dev.PrivateKey.String() device.DeviceName = dev.Name device.ListenPort = dev.ListenPort device.Mtu = 0 - device.PersistentKeepalive = 16 // Default + device.DefaultPersistentKeepalive = 16 // Default device.IPsStr = strings.Join(ipAddresses, ", ") if mtu == DefaultMTU { mtu = 0 @@ -423,7 +452,7 @@ func (m *PeerManager) populatePeerData(peer *Peer) { // populateDeviceData enriches the device struct with WireGuard live data like interface information func (m *PeerManager) populateDeviceData(device *Device) { - device.AllowedIPs = strings.Split(device.AllowedIPsStr, ", ") + device.DefaultAllowedIPs = strings.Split(device.DefaultAllowedIPsStr, ", ") device.IPs = strings.Split(device.IPsStr, ", ") device.DNS = strings.Split(device.DNSStr, ", ") @@ -621,7 +650,7 @@ func (m *PeerManager) DeletePeer(peer Peer) error { func (m *PeerManager) UpdateDevice(device Device) error { device.UpdatedAt = time.Now() - device.AllowedIPsStr = strings.Join(device.AllowedIPs, ", ") + device.DefaultAllowedIPsStr = strings.Join(device.DefaultAllowedIPs, ", ") device.IPsStr = strings.Join(device.IPs, ", ") device.DNSStr = strings.Join(device.DNS, ", ") From aa17303cec4294d6e5c3d19ca9933640cc057884 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sat, 3 Apr 2021 19:11:05 +0200 Subject: [PATCH 02/11] WIP: support different interface types: server, client and custom. Show different UI for each type. --- assets/tpl/admin_edit_client.html | 252 +++++++++++++++++++++++--- assets/tpl/admin_edit_interface.html | 26 ++- assets/tpl/admin_index.html | 9 +- internal/server/configuration.go | 1 + internal/server/handlers_interface.go | 12 +- internal/server/handlers_peer.go | 16 +- internal/server/server_helper.go | 27 +-- internal/wireguard/peermanager.go | 177 +++++++++++------- 8 files changed, 396 insertions(+), 124 deletions(-) diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 4a429aa..bdd5bb8 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -13,34 +13,36 @@ {{template "prt_nav.html" .}}
+ {{template "prt_flashes.html" .}} + + + {{if eq .Device.Type "server"}} {{if .Peer.IsNew}}

Create a new client

{{else}} -

Edit client {{.Peer.Identifier}}

+

Edit client: {{.Peer.Identifier}}

{{end}} - {{template "prt_flashes.html" .}} -
{{if .EditableKeys}}
- - + +
- - + +
- - + +
{{else}} @@ -48,48 +50,60 @@
- - + +
{{end}}
- - + +
- - + +
- - + +
- - + + +
+
+
+
+ + +
+
+
+
+ +
- -
- -
@@ -99,6 +113,196 @@ Cancel + {{end}} + + + {{if eq .Device.Type "client"}} + {{if .Peer.IsNew}} +

Create a new remote endpoint

+ {{else}} +

Edit remote endpoint: {{.Peer.Identifier}}

+ {{end}} + +
+ + + + {{if .EditableKeys}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ {{else}} + + +
+
+ + +
+
+ {{end}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+
+ + +
+
+
+ + + + Cancel +
+ {{end}} + + + {{if eq .Device.Type "custom"}} + {{if .Peer.IsNew}} +

Create a new peer

+ {{else}} +

Edit peer: {{.Peer.Identifier}}

+ {{end}} + +
+ + + {{if .EditableKeys}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ {{else}} + + +
+
+ + +
+
+ {{end}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+
+ + +
+
+ + +
+
+
+ + + + Cancel +
+ {{end}}
{{template "prt_footer.html" .}} diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index 36abe2f..c1a8c6e 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -36,6 +36,12 @@

Server's interface configuration

+
+
+ + +
+
{{if .EditableKeys}}
@@ -134,6 +140,12 @@

Client's interface configuration

+
+
+ + +
+
{{if .EditableKeys}}
@@ -219,6 +231,12 @@

Custom interface configuration

+
+
+ + +
+
{{if .EditableKeys}}
@@ -257,8 +275,12 @@
- - +
+ + +
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index ce9d07c..2066777 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -84,11 +84,18 @@
+ {{with or (eq $.Device.Type "server") (eq $.Device.Type "custom")}}

Current VPN Peers

+ {{end}} + {{with eq $.Device.Type "client"}} +

Current VPN Endpoints

+ {{end}}
+ {{with eq $.Device.Type "server"}} - M + {{end}} + M
diff --git a/internal/server/configuration.go b/internal/server/configuration.go index bb985b0..2727967 100644 --- a/internal/server/configuration.go +++ b/internal/server/configuration.go @@ -85,6 +85,7 @@ func NewConfig() *Config { cfg.Core.AdminUser = "admin@wgportal.local" cfg.Core.AdminPassword = "wgportal" cfg.Core.LdapEnabled = false + cfg.Core.EditableKeys = true cfg.Core.SessionSecret = "secret" cfg.Database.Typ = "sqlite" diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 509160c..085477c 100644 --- a/internal/server/handlers_interface.go +++ b/internal/server/handlers_interface.go @@ -44,12 +44,9 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) { return } // Clean list input - formDevice.IPs = common.ParseStringList(formDevice.IPsStr) - formDevice.DefaultAllowedIPs = common.ParseStringList(formDevice.DefaultAllowedIPsStr) - formDevice.DNS = common.ParseStringList(formDevice.DNSStr) - formDevice.IPsStr = common.ListToString(formDevice.IPs) - formDevice.DefaultAllowedIPsStr = common.ListToString(formDevice.DefaultAllowedIPs) - formDevice.DNSStr = common.ListToString(formDevice.DNS) + formDevice.IPsStr = common.ListToString(common.ParseStringList(formDevice.IPsStr)) + formDevice.DefaultAllowedIPsStr = common.ListToString(common.ParseStringList(formDevice.DefaultAllowedIPsStr)) + formDevice.DNSStr = common.ListToString(common.ParseStringList(formDevice.DNSStr)) // Update WireGuard device err := s.wg.UpdateDevice(formDevice.DeviceName, formDevice.GetConfig()) @@ -80,7 +77,7 @@ func (s *Server) PostAdminEditInterface(c *gin.Context) { // Update interface IP address if s.config.WG.ManageIPAddresses { - if err := s.wg.SetIPAddress(currentSession.DeviceName, formDevice.IPs); err != nil { + if err := s.wg.SetIPAddress(currentSession.DeviceName, formDevice.GetIPAddresses()); err != nil { _ = s.updateFormInSession(c, formDevice) SetFlashMessage(c, "Failed to update ip address: "+err.Error(), "danger") c.Redirect(http.StatusSeeOther, "/admin/device/edit?formerr=update") @@ -122,7 +119,6 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) { peers := s.peers.GetAllPeers(device.DeviceName) for _, peer := range peers { - peer.AllowedIPs = device.DefaultAllowedIPs peer.AllowedIPsStr = device.DefaultAllowedIPsStr if err := s.peers.UpdatePeer(peer); err != nil { SetFlashMessage(c, err.Error(), "danger") diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go index 2b9211d..9dd99ec 100644 --- a/internal/server/handlers_peer.go +++ b/internal/server/handlers_peer.go @@ -40,6 +40,7 @@ func (s *Server) GetAdminEditPeer(c *gin.Context) { "EditableKeys": s.config.Core.EditableKeys, "Device": s.peers.GetDevice(currentSession.DeviceName), "DeviceNames": s.wg.Cfg.DeviceNames, + "AdminEmail": s.config.Core.AdminUser, "Csrf": csrf.GetToken(c), }) } @@ -61,10 +62,8 @@ func (s *Server) PostAdminEditPeer(c *gin.Context) { } // Clean list input - formPeer.IPs = common.ParseStringList(formPeer.IPsStr) - formPeer.AllowedIPs = common.ParseStringList(formPeer.AllowedIPsStr) - formPeer.IPsStr = common.ListToString(formPeer.IPs) - formPeer.AllowedIPsStr = common.ListToString(formPeer.AllowedIPs) + formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr)) + formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr)) disabled := c.PostForm("isdisabled") != "" now := time.Now() @@ -101,6 +100,7 @@ func (s *Server) GetAdminCreatePeer(c *gin.Context) { "EditableKeys": s.config.Core.EditableKeys, "Device": s.peers.GetDevice(currentSession.DeviceName), "DeviceNames": s.wg.Cfg.DeviceNames, + "AdminEmail": s.config.Core.AdminUser, "Csrf": csrf.GetToken(c), }) } @@ -119,10 +119,8 @@ func (s *Server) PostAdminCreatePeer(c *gin.Context) { } // Clean list input - formPeer.IPs = common.ParseStringList(formPeer.IPsStr) - formPeer.AllowedIPs = common.ParseStringList(formPeer.AllowedIPsStr) - formPeer.IPsStr = common.ListToString(formPeer.IPs) - formPeer.AllowedIPsStr = common.ListToString(formPeer.AllowedIPs) + formPeer.IPsStr = common.ListToString(common.ParseStringList(formPeer.IPsStr)) + formPeer.AllowedIPsStr = common.ListToString(common.ParseStringList(formPeer.AllowedIPsStr)) disabled := c.PostForm("isdisabled") != "" now := time.Now() @@ -328,7 +326,7 @@ func (s *Server) GetPeerStatus(c *gin.Context) { isOnline := false ping := make(chan bool) defer close(ping) - for _, cidr := range peer.IPs { + for _, cidr := range peer.GetIPAddresses() { ip, _, _ := net.ParseCIDR(cidr) var ra *net.IPAddr if common.IsIPv6(ip.String()) { diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index ca35c33..9304a65 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -8,7 +8,6 @@ import ( "syscall" "time" - "github.com/h44z/wg-portal/internal/common" "github.com/h44z/wg-portal/internal/users" "github.com/h44z/wg-portal/internal/wireguard" "github.com/pkg/errors" @@ -20,19 +19,20 @@ import ( // PrepareNewPeer initiates a new peer for the given WireGuard device. func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { dev := s.peers.GetDevice(device) + deviceIPs := dev.GetIPAddresses() peer := wireguard.Peer{} peer.IsNew = true peer.AllowedIPsStr = dev.DefaultAllowedIPsStr - peer.IPs = make([]string, len(dev.IPs)) - for i := range dev.IPs { - freeIP, err := s.peers.GetAvailableIp(device, dev.IPs[i]) + peerIPs := make([]string, len(deviceIPs)) + for i := range deviceIPs { + freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) if err != nil { return wireguard.Peer{}, errors.WithMessage(err, "failed to get available IP addresses") } - peer.IPs[i] = freeIP + peerIPs[i] = freeIP } - peer.IPsStr = common.ListToString(peer.IPs) + peer.SetIPAddresses(peerIPs...) psk, err := wgtypes.GenerateKey() if err != nil { return wireguard.Peer{}, errors.Wrap(err, "failed to generate key") @@ -77,17 +77,20 @@ func (s *Server) CreatePeerByEmail(device, email, identifierSuffix string, disab // This function also configures the new peer on the physical WireGuard interface if the peer is not deactivated. func (s *Server) CreatePeer(device string, peer wireguard.Peer) error { dev := s.peers.GetDevice(device) + deviceIPs := dev.GetIPAddresses() + peerIPs := peer.GetIPAddresses() + peer.AllowedIPsStr = dev.DefaultAllowedIPsStr - if peer.IPs == nil || len(peer.IPs) == 0 { - peer.IPs = make([]string, len(dev.IPs)) - for i := range dev.IPs { - freeIP, err := s.peers.GetAvailableIp(device, dev.IPs[i]) + if len(peerIPs) == 0 { + peerIPs = make([]string, len(deviceIPs)) + for i := range deviceIPs { + freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) if err != nil { return errors.WithMessage(err, "failed to get available IP addresses") } - peer.IPs[i] = freeIP + peerIPs[i] = freeIP } - peer.IPsStr = common.ListToString(peer.IPs) + peer.SetIPAddresses(peerIPs...) } if peer.PrivateKey == "" { // if private key is empty create a new one psk, err := wgtypes.GenerateKey() diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index ac923a3..33a454e 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -70,29 +70,27 @@ type Peer struct { Config string `gorm:"-"` UID string `form:"uid" binding:"alphanum"` // uid for html identification - IsOnline bool `gorm:"-"` - IsNew bool `gorm:"-"` - Identifier string `form:"identifier" binding:"required,lt=64"` // Identifier AND Email make a WireGuard peer unique - Email string `gorm:"index" form:"mail" binding:"required,email"` - LastHandshake string `gorm:"-"` - LastHandshakeTime string `gorm:"-"` - IgnoreGlobalSettings bool `form:"ignoreglobalsettings"` DeviceName string `gorm:"index"` + Identifier string `form:"identifier" binding:"required,max=64"` // Identifier AND Email make a WireGuard peer unique + Email string `gorm:"index" form:"mail" binding:"omitempty,email"` + IgnoreGlobalSettings bool `form:"ignoreglobalsettings"` + + IsOnline bool `gorm:"-"` + IsNew bool `gorm:"-"` + LastHandshake string `gorm:"-"` + LastHandshakeTime string `gorm:"-"` // Core WireGuard Settings - PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` - PresharedKey string `form:"presharedkey" binding:"omitempty,base64"` - AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` - AllowedIPs []string `gorm:"-"` // IPs that are used in the client config file - Endpoint string `form:"endpoint" binding:"hostname_port"` - PersistentKeepalive int `form:"keepalive" binding:"gte=0"` + PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` + PresharedKey string `form:"presharedkey" binding:"omitempty,base64"` + AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` // a comma separated list of IPs that are used in the client config file + Endpoint string `form:"endpoint" binding:"omitempty,hostname_port"` + PersistentKeepalive int `form:"keepalive" binding:"gte=0"` // Misc. WireGuard Settings - PrivateKey string `form:"privkey" binding:"omitempty,base64"` - IPsStr string `form:"ip" binding:"cidrlist"` - IPs []string `gorm:"-"` // The IPs of the client - DNSStr string `form:"dns" binding:"iplist"` // comma separated list of: - DNS []string `gorm:"-"` // the DNS servers for the client + PrivateKey string `form:"privkey" binding:"omitempty,base64"` + IPsStr string `form:"ip" binding:"cidrlist"` // 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 DeactivatedAt *time.Time CreatedBy string @@ -101,6 +99,30 @@ type Peer struct { UpdatedAt time.Time } +func (p *Peer) SetIPAddresses(addresses ...string) { + p.IPsStr = common.ListToString(addresses) +} + +func (p Peer) GetIPAddresses() []string { + return common.ParseStringList(p.IPsStr) +} + +func (p *Peer) SetDNSServers(addresses ...string) { + p.DNSStr = common.ListToString(addresses) +} + +func (p Peer) GetDNSServers() []string { + return common.ParseStringList(p.DNSStr) +} + +func (p *Peer) SetAllowedIPs(addresses ...string) { + p.AllowedIPsStr = common.ListToString(addresses) +} + +func (p Peer) GetAllowedIPs() []string { + return common.ParseStringList(p.AllowedIPsStr) +} + func (p Peer) GetConfig() wgtypes.PeerConfig { publicKey, _ := wgtypes.ParseKey(p.PublicKey) var presharedKey *wgtypes.Key @@ -117,9 +139,9 @@ func (p Peer) GetConfig() wgtypes.PeerConfig { Endpoint: nil, PersistentKeepaliveInterval: nil, ReplaceAllowedIPs: true, - AllowedIPs: make([]net.IPNet, len(p.IPs)), + AllowedIPs: make([]net.IPNet, len(p.GetIPAddresses())), } - for i, ip := range p.IPs { + for i, ip := range p.GetIPAddresses() { _, ipNet, err := net.ParseCIDR(ip) if err == nil { cfg.AllowedIPs[i] = *ipNet @@ -210,51 +232,84 @@ const ( type Device struct { Interface *wgtypes.Device `gorm:"-"` - Type DeviceType `form:"devicetype"` - DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"` + Type DeviceType `form:"devicetype" binding:"required,oneof=client server custom"` + DeviceName string `form:"device" gorm:"primaryKey" binding:"required,alphanum"` + DisplayName string `form:"displayname" binding:"omitempty,max=200"` // Core WireGuard Settings (Interface section) PrivateKey string `form:"privkey" binding:"required,base64"` - ListenPort int `form:"port" binding:"required,gt=0"` - FirewallMark int32 `form:"firewallmark"` + ListenPort int `form:"port" binding:"gt=0,lt=65535"` + FirewallMark int32 `form:"firewallmark" binding:"gte=0"` // Misc. WireGuard Settings - PublicKey string `form:"pubkey" binding:"required,base64"` - Mtu int `form:"mtu" binding:"gte=0,lte=1500"` // the interface MTU, wg-quick addition - IPsStr string `form:"ip" binding:"required,cidrlist"` // comma separated list of: - IPs []string `gorm:"-"` // the IPs of the client, wg-quick addition - DNSStr string `form:"dns" binding:"iplist"` // comma separated list of: - DNS []string `gorm:"-"` // the DNS servers of the client, wg-quick addition - RoutingTable string `form:"routingtable"` // the routing table, wg-quick addition - PreUp string `form:"preup"` // pre up script, wg-quick addition - PostUp string `form:"postup"` // post up script, wg-quick addition - PreDown string `form:"predown"` // pre down script, wg-quick addition - PostDown string `form:"postdown"` // post down script, wg-quick addition - SaveConfig bool `form:"saveconfig"` // if set to `true', the configuration is saved from the current state of the interface upon shutdown, wg-quick addition + PublicKey string `form:"pubkey" binding:"required,base64"` + Mtu int `form:"mtu" binding:"gte=0,lte=1500"` // the interface MTU, wg-quick addition + IPsStr string `form:"ip" binding:"required,cidrlist"` // comma separated list of the IPs of the client, wg-quick addition + DNSStr string `form:"dns" binding:"iplist"` // comma separated list of the DNS servers of the client, wg-quick addition + RoutingTable string `form:"routingtable"` // the routing table, wg-quick addition + PreUp string `form:"preup"` // pre up script, wg-quick addition + PostUp string `form:"postup"` // post up script, wg-quick addition + PreDown string `form:"predown"` // pre down script, wg-quick addition + PostDown string `form:"postdown"` // post down script, wg-quick addition + 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:"required,hostname_port"` - DefaultAllowedIPsStr string `form:"allowedip" binding:"cidrlist"` - DefaultAllowedIPs []string `gorm:"-"` // IPs that are used in the client config file - DefaultPersistentKeepalive int `form:"keepalive" binding:"gte=0"` + DefaultEndpoint string `form:"endpoint" binding:"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"` CreatedAt time.Time UpdatedAt time.Time } func (d Device) IsValid() bool { - if d.PublicKey == "" { - return false - } - if len(d.IPs) == 0 { - return false - } - if d.DefaultEndpoint == "" { - return false + switch d.Type { + case DeviceTypeServer: + if d.PublicKey == "" { + return false + } + if len(d.GetIPAddresses()) == 0 { + return false + } + if d.DefaultEndpoint == "" { + return false + } + case DeviceTypeClient: + if d.PublicKey == "" { + return false + } + if len(d.GetIPAddresses()) == 0 { + return false + } + case DeviceTypeCustom: } return true } +func (d *Device) SetIPAddresses(addresses ...string) { + d.IPsStr = common.ListToString(addresses) +} + +func (d Device) GetIPAddresses() []string { + return common.ParseStringList(d.IPsStr) +} + +func (d *Device) SetDNSServers(addresses ...string) { + d.DNSStr = common.ListToString(addresses) +} + +func (d Device) GetDNSServers() []string { + return common.ParseStringList(d.DNSStr) +} + +func (d *Device) SetDefaultAllowedIPs(addresses ...string) { + d.DefaultAllowedIPsStr = common.ListToString(addresses) +} + +func (d Device) GetDefaultAllowedIPs() []string { + return common.ParseStringList(d.DefaultAllowedIPsStr) +} + func (d Device) GetConfig() wgtypes.Config { var privateKey *wgtypes.Key if d.PrivateKey != "" { @@ -374,13 +429,12 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e peer.Identifier = "Autodetected (" + peer.PublicKey[0:8] + ")" peer.UpdatedAt = time.Now() peer.CreatedAt = time.Now() - peer.AllowedIPs = make([]string, 0) // UNKNOWN - peer.IPs = make([]string, len(wgPeer.AllowedIPs)) + IPs := make([]string, len(wgPeer.AllowedIPs)) for i, ip := range wgPeer.AllowedIPs { - peer.IPs[i] = ip.String() + IPs[i] = ip.String() } - peer.AllowedIPsStr = strings.Join(peer.AllowedIPs, ", ") - peer.IPsStr = strings.Join(peer.IPs, ", ") + peer.AllowedIPsStr = "" // UNKNOWN + peer.SetIPAddresses(IPs...) peer.DeviceName = device res := m.db.Create(&peer) @@ -422,8 +476,6 @@ func (m *PeerManager) validateOrCreateDevice(dev wgtypes.Device, ipAddresses []s // populatePeerData enriches the peer struct with WireGuard live data like last handshake, ... func (m *PeerManager) populatePeerData(peer *Peer) { - peer.AllowedIPs = strings.Split(peer.AllowedIPsStr, ", ") - peer.IPs = strings.Split(peer.IPsStr, ", ") // Set config file tmpCfg, _ := peer.GetConfigFile(m.GetDevice(peer.DeviceName)) peer.Config = string(tmpCfg) @@ -452,10 +504,6 @@ func (m *PeerManager) populatePeerData(peer *Peer) { // populateDeviceData enriches the device struct with WireGuard live data like interface information func (m *PeerManager) populateDeviceData(device *Device) { - device.DefaultAllowedIPs = strings.Split(device.DefaultAllowedIPsStr, ", ") - device.IPs = strings.Split(device.IPsStr, ", ") - device.DNS = strings.Split(device.DNSStr, ", ") - // set data from WireGuard interface device.Interface, _ = m.wg.GetDeviceInfo(device.DeviceName) } @@ -612,8 +660,6 @@ func (m *PeerManager) CreatePeer(peer Peer) error { peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey))) peer.UpdatedAt = time.Now() peer.CreatedAt = time.Now() - peer.AllowedIPsStr = strings.Join(peer.AllowedIPs, ", ") - peer.IPsStr = strings.Join(peer.IPs, ", ") res := m.db.Create(&peer) if res.Error != nil { @@ -626,8 +672,6 @@ func (m *PeerManager) CreatePeer(peer Peer) error { func (m *PeerManager) UpdatePeer(peer Peer) error { peer.UpdatedAt = time.Now() - peer.AllowedIPsStr = strings.Join(peer.AllowedIPs, ", ") - peer.IPsStr = strings.Join(peer.IPs, ", ") res := m.db.Save(&peer) if res.Error != nil { @@ -650,9 +694,6 @@ func (m *PeerManager) DeletePeer(peer Peer) error { func (m *PeerManager) UpdateDevice(device Device) error { device.UpdatedAt = time.Now() - device.DefaultAllowedIPsStr = strings.Join(device.DefaultAllowedIPs, ", ") - device.IPsStr = strings.Join(device.IPs, ", ") - device.DNSStr = strings.Join(device.DNS, ", ") res := m.db.Save(&device) if res.Error != nil { @@ -669,7 +710,7 @@ func (m *PeerManager) GetAllReservedIps(device string) ([]string, error) { reservedIps := make([]string, 0) peers := m.GetAllPeers(device) for _, user := range peers { - for _, cidr := range user.IPs { + for _, cidr := range user.GetIPAddresses() { if cidr == "" { continue } @@ -682,7 +723,7 @@ func (m *PeerManager) GetAllReservedIps(device string) ([]string, error) { } dev := m.GetDevice(device) - for _, cidr := range dev.IPs { + for _, cidr := range dev.GetIPAddresses() { if cidr == "" { continue } From 3bfcbe0209946d6603f0fc8f41aac24f4db8022f Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sat, 3 Apr 2021 22:38:22 +0200 Subject: [PATCH 03/11] WIP: support different interface types: update config templates --- assets/tpl/admin_edit_client.html | 45 ++++++++-- assets/tpl/admin_edit_interface.html | 2 +- go.mod | 4 +- internal/wireguard/peermanager.go | 125 ++++++++++++--------------- internal/wireguard/template.go | 67 ++++---------- internal/wireguard/tpl/interface.tpl | 58 +++++++++++++ internal/wireguard/tpl/peer.tpl | 28 ++++++ 7 files changed, 198 insertions(+), 131 deletions(-) create mode 100644 internal/wireguard/tpl/interface.tpl create mode 100644 internal/wireguard/tpl/peer.tpl diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index bdd5bb8..10fc99c 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -26,6 +26,9 @@
+ + + {{if .EditableKeys}}
@@ -74,22 +77,26 @@
-
+
-
+
-
+
+
+ + +
@@ -127,6 +134,8 @@ + + {{if .EditableKeys}}
@@ -136,7 +145,7 @@
- +
@@ -170,12 +179,18 @@
+ + +
+
+
+
-
+
@@ -209,6 +224,8 @@ + + {{if .EditableKeys}}
@@ -251,34 +268,44 @@
-
+
+ + +
+
+
+
-
+
-
+
-
+
+
+ + +
diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index c1a8c6e..dc1cf39 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -264,7 +264,7 @@
-
+
diff --git a/go.mod b/go.mod index 27c93e4..657a6aa 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/gin-contrib/sessions v0.0.3 github.com/gin-gonic/gin v1.6.3 github.com/go-ldap/ldap/v3 v3.2.4 - github.com/go-playground/validator/v10 v10.2.0 + github.com/go-playground/validator/v10 v10.4.1 github.com/gorilla/sessions v1.2.1 // indirect github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible github.com/kelseyhightower/envconfig v1.4.0 @@ -17,7 +17,7 @@ require ( github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e github.com/toorop/gin-logrus v0.0.0-20200831135515-d2ee50d38dae github.com/utrack/gin-csrf v0.0.0-20190424104817-40fb8d2c8fca - golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c gorm.io/driver/mysql v1.0.4 diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index 33a454e..57e6dc2 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -7,13 +7,13 @@ import ( "crypto/md5" "fmt" "net" - "reflect" "regexp" "sort" "strings" - "text/template" "time" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" "github.com/h44z/wg-portal/internal/common" @@ -42,7 +42,6 @@ var cidrList validator.Func = func(fl validator.FieldLevel) bool { var ipList validator.Func = func(fl validator.FieldLevel) bool { ipListStr := fl.Field().String() - ipList := common.ParseStringList(ipListStr) for i := range ipList { ip := net.ParseIP(ipList[i]) @@ -65,15 +64,16 @@ func init() { // type Peer struct { - Peer *wgtypes.Peer `gorm:"-"` // WireGuard peer - Device *Device `gorm:"foreignKey:DeviceName"` // linked WireGuard device + Peer *wgtypes.Peer `gorm:"-"` // WireGuard peer + Device *Device `gorm:"foreignKey:DeviceName" binding:"-"` // linked WireGuard device Config string `gorm:"-"` - UID string `form:"uid" binding:"alphanum"` // uid for html identification - DeviceName string `gorm:"index"` - Identifier string `form:"identifier" binding:"required,max=64"` // Identifier AND Email make a WireGuard peer unique - Email string `gorm:"index" form:"mail" binding:"omitempty,email"` - IgnoreGlobalSettings bool `form:"ignoreglobalsettings"` + UID string `form:"uid" binding:"required,alphanum"` // uid for html identification + DeviceName string `gorm:"index" form:"device" binding:"required"` + DeviceType DeviceType `gorm:"-" form:"devicetype" binding:"required,oneof=client server custom"` + Identifier string `form:"identifier" binding:"required,max=64"` // Identifier AND Email make a WireGuard peer unique + Email string `gorm:"index" form:"mail" binding:"required,email"` + IgnoreGlobalSettings bool `form:"ignoreglobalsettings"` IsOnline bool `gorm:"-"` IsNew bool `gorm:"-"` @@ -81,16 +81,19 @@ type Peer struct { LastHandshakeTime string `gorm:"-"` // Core WireGuard Settings - PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` + PublicKey string `gorm:"primaryKey" form:"pubkey" binding:"required,base64"` // the public key of the peer itself PresharedKey string `form:"presharedkey" binding:"omitempty,base64"` AllowedIPsStr string `form:"allowedip" binding:"cidrlist"` // a comma separated list of IPs that are used in the client config file Endpoint string `form:"endpoint" binding:"omitempty,hostname_port"` PersistentKeepalive int `form:"keepalive" binding:"gte=0"` // Misc. WireGuard Settings - PrivateKey string `form:"privkey" binding:"omitempty,base64"` - IPsStr string `form:"ip" binding:"cidrlist"` // 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 + 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 + 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"` DeactivatedAt *time.Time CreatedBy string @@ -131,40 +134,49 @@ func (p Peer) GetConfig() wgtypes.PeerConfig { presharedKey = &presharedKeyTmp } + var endpoint *net.UDPAddr + if p.Endpoint != "" { + addr, err := net.ResolveUDPAddr("udp", p.Endpoint) + if err == nil { + endpoint = addr + } + } + + var keepAlive *time.Duration + if p.PersistentKeepalive != 0 { + keepAliveDuration := time.Duration(p.PersistentKeepalive) * time.Second + keepAlive = &keepAliveDuration + } + + peerAllowedIPs := p.GetAllowedIPs() + allowedIPs := make([]net.IPNet, len(peerAllowedIPs)) + for i, ip := range peerAllowedIPs { + _, ipNet, err := net.ParseCIDR(ip) + if err == nil { + allowedIPs[i] = *ipNet + } + } + cfg := wgtypes.PeerConfig{ PublicKey: publicKey, Remove: false, UpdateOnly: false, PresharedKey: presharedKey, - Endpoint: nil, - PersistentKeepaliveInterval: nil, + Endpoint: endpoint, + PersistentKeepaliveInterval: keepAlive, ReplaceAllowedIPs: true, - AllowedIPs: make([]net.IPNet, len(p.GetIPAddresses())), - } - for i, ip := range p.GetIPAddresses() { - _, ipNet, err := net.ParseCIDR(ip) - if err == nil { - cfg.AllowedIPs[i] = *ipNet - } + AllowedIPs: allowedIPs, } return cfg } func (p Peer) GetConfigFile(device Device) ([]byte, error) { - tpl, err := template.New("client").Funcs(template.FuncMap{"StringsJoin": strings.Join}).Parse(ClientCfgTpl) - if err != nil { - return nil, errors.Wrap(err, "failed to parse client template") - } - var tplBuff bytes.Buffer - err = tpl.Execute(&tplBuff, struct { - Client Peer - Server Device - }{ - Client: p, - Server: device, + err := templateCache.ExecuteTemplate(&tplBuff, "peer.tpl", gin.H{ + "Peer": p, + "Interface": device, }) if err != nil { return nil, errors.Wrap(err, "failed to execute client template") @@ -192,26 +204,6 @@ func (p Peer) IsValid() bool { return true } -func (p Peer) ToMap() map[string]string { - out := make(map[string]string) - - v := reflect.ValueOf(p) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - - typ := v.Type() - for i := 0; i < v.NumField(); i++ { - // gets us a StructField - fi := typ.Field(i) - if tagv := fi.Tag.Get("form"); tagv != "" { - // set key of map to value in struct field - out[tagv] = v.Field(i).String() - } - } - return out -} - func (p Peer) GetConfigFileName() string { reg := regexp.MustCompile("[^a-zA-Z0-9_-]+") return reg.ReplaceAllString(strings.ReplaceAll(p.Identifier, " ", "-"), "") + ".conf" @@ -238,7 +230,7 @@ type Device struct { // Core WireGuard Settings (Interface section) PrivateKey string `form:"privkey" binding:"required,base64"` - ListenPort int `form:"port" binding:"gt=0,lt=65535"` + ListenPort int `form:"port" binding:"omitempty,gt=0,lt=65535,required_if=devicetype server"` FirewallMark int32 `form:"firewallmark" binding:"gte=0"` // Misc. WireGuard Settings PublicKey string `form:"pubkey" binding:"required,base64"` @@ -253,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"` + DefaultEndpoint string `form:"endpoint" binding:"omitempty,hostname_port,required_if=devicetype server"` 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"` @@ -317,28 +309,23 @@ func (d Device) GetConfig() wgtypes.Config { privateKey = &pKey } + fwMark := int(d.FirewallMark) + cfg := wgtypes.Config{ - PrivateKey: privateKey, - ListenPort: &d.ListenPort, + PrivateKey: privateKey, + ListenPort: &d.ListenPort, + FirewallMark: &fwMark, } return cfg } func (d Device) GetConfigFile(peers []Peer) ([]byte, error) { - tpl, err := template.New("server").Funcs(template.FuncMap{"StringsJoin": strings.Join}).Parse(DeviceCfgTpl) - if err != nil { - return nil, errors.Wrap(err, "failed to parse server template") - } - var tplBuff bytes.Buffer - err = tpl.Execute(&tplBuff, struct { - Clients []Peer - Server Device - }{ - Clients: peers, - Server: d, + err := templateCache.ExecuteTemplate(&tplBuff, "interface.tpl", gin.H{ + "Peers": peers, + "Interface": d, }) if err != nil { return nil, errors.Wrap(err, "failed to execute server template") diff --git a/internal/wireguard/template.go b/internal/wireguard/template.go index 3b65e57..99cdb1c 100644 --- a/internal/wireguard/template.go +++ b/internal/wireguard/template.go @@ -1,53 +1,20 @@ package wireguard -var ( - ClientCfgTpl = `#{{ .Client.Identifier }} -[Interface] -Address = {{ .Client.IPsStr }} -PrivateKey = {{ .Client.PrivateKey }} -{{- if .Server.DNSStr}} -DNS = {{ .Server.DNSStr }} -{{- end}} -{{- if ne .Server.Mtu 0}} -MTU = {{.Server.Mtu}} -{{- end}} - -[Peer] -PublicKey = {{ .Server.PublicKey }} -{{- if .Client.PresharedKey}} -PresharedKey = {{ .Client.PresharedKey }} -{{- end}} -AllowedIPs = {{ .Client.AllowedIPsStr }} -Endpoint = {{ .Server.Endpoint }} -{{- if and (ne .Server.PersistentKeepalive 0) (not .Client.IgnorePersistentKeepalive)}} -PersistentKeepalive = {{.Server.PersistentKeepalive}} -{{- end}} -` - DeviceCfgTpl = `# AUTOGENERATED FILE - DO NOT EDIT -# Updated: {{ .Server.UpdatedAt }} / Created: {{ .Server.CreatedAt }} -[Interface] -{{- range .Server.IPs}} -Address = {{ . }} -{{- end}} -ListenPort = {{ .Server.ListenPort }} -PrivateKey = {{ .Server.PrivateKey }} -{{- if ne .Server.Mtu 0}} -MTU = {{.Server.Mtu}} -{{- end}} -PreUp = {{ .Server.PreUp }} -PostUp = {{ .Server.PostUp }} -PreDown = {{ .Server.PreDown }} -PostDown = {{ .Server.PostDown }} - -{{range .Clients}} -{{if not .DeactivatedAt -}} -# {{.Identifier}} / {{.Email}} / Updated: {{.UpdatedAt}} / Created: {{.CreatedAt}} -[Peer] -PublicKey = {{ .PublicKey }} -{{- if .PresharedKey}} -PresharedKey = {{ .PresharedKey }} -{{- end}} -AllowedIPs = {{ StringsJoin .IPs ", " }} -{{- end}} -{{end}}` +import ( + "embed" + "html/template" + "strings" ) + +//go:embed tpl/* +var Templates embed.FS + +var templateCache *template.Template + +func init() { + var err error + templateCache, err = template.New("server").Funcs(template.FuncMap{"StringsJoin": strings.Join}).ParseFS(Templates, "tpl/*.tpl") + if err != nil { + panic(err) + } +} diff --git a/internal/wireguard/tpl/interface.tpl b/internal/wireguard/tpl/interface.tpl new file mode 100644 index 0000000..8540c2a --- /dev/null +++ b/internal/wireguard/tpl/interface.tpl @@ -0,0 +1,58 @@ +# AUTOGENERATED FILE - DO NOT EDIT +# -WGP- Interface: {{ .Interface.DeviceName }} / Updated: {{ .Interface.UpdatedAt }} / Created: {{ .Interface.CreatedAt }} +# -WGP- Interface display name: {{ .Interface.DisplayName }} +# -WGP- Interface mode: {{ .Interface.Type }} +# -WGP- PublicKey = {{ .Interface.PublicKey }} + +[Interface] + +# Core settings +PrivateKey = {{ .Interface.PrivateKey }} +Address = {{ .Interface.IPsStr }} + +# Misc. settings +{{- if ne .Interface.ListenPort 0}} +ListenPort = {{ .Interface.ListenPort }} +{{- end}} +{{- if ne .Interface.Mtu 0}} +MTU = {{.Interface.Mtu}} +{{- end}} +{{- if ne .Interface.FirewallMark 0}} +FwMark = {{.Interface.FirewallMark}} +{{- end}} +{{- if ne .Interface.RoutingTable ""}} +Table = {{.Interface.RoutingTable}} +{{- end}} +{{- if .Interface.SaveConfig}} +SaveConfig = true +{{- end}} + +# Interface hooks +PreUp = {{ .Interface.PreUp }} +PostUp = {{ .Interface.PostUp }} +PreDown = {{ .Interface.PreDown }} +PostDown = {{ .Interface.PostDown }} + +# +# Peers +# + +{{range .Peers}} +{{- if not .DeactivatedAt}} +# -WGP- Peer: {{.Identifier}} / Updated: {{.UpdatedAt}} / Created: {{.CreatedAt}} +# -WGP- Peer email: {{.Email}} +# -WGP- PrivateKey: {{.PrivateKey}} +[Peer] +PublicKey = {{ .PublicKey }} +{{- if .PresharedKey}} +PresharedKey = {{ .PresharedKey }} +{{- end}} +AllowedIPs = {{ .AllowedIPsStr }} +{{- if ne .Endpoint ""}} +Endpoint = {{ .Endpoint }} +{{- end}} +{{- if ne .PersistentKeepalive 0}} +PersistentKeepalive = {{ .PersistentKeepalive }} +{{- end}} +{{- end}} +{{end}} \ No newline at end of file diff --git a/internal/wireguard/tpl/peer.tpl b/internal/wireguard/tpl/peer.tpl new file mode 100644 index 0000000..ac55305 --- /dev/null +++ b/internal/wireguard/tpl/peer.tpl @@ -0,0 +1,28 @@ +# AUTOGENERATED FILE - PROVIDED BY WIREGUARD PORTAL +# WireGuard configuration: {{ .Peer.Identifier }} +# -WGP- PublicKey: {{ .Peer.PublicKey }} + +[Interface] + +# Core settings +PrivateKey = {{ .Peer.PrivateKey }} +Address = {{ .Peer.IPsStr }} + +# Misc. settings +{{- if .Peer.DNSStr}} +DNS = {{ .Peer.DNSStr }} +{{- end}} +{{- if ne .Peer.Mtu 0}} +MTU = {{.Peer.Mtu}} +{{- end}} + +[Peer] +PublicKey = {{ .Peer.EndpointPublicKey }} +Endpoint = {{ .Server.Endpoint }} +AllowedIPs = {{ .Peer.AllowedIPsStr }} +{{- if .Peer.PresharedKey}} +PresharedKey = {{ .Peer.PresharedKey }} +{{- end}} +{{- if ne .Peer.PersistentKeepalive 0}} +PersistentKeepalive = {{.Peer.PersistentKeepalive}} +{{- end}} \ No newline at end of file From 647fe92a0324462a41772282c0f0045de5b0a4bc Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sat, 3 Apr 2021 23:54:35 +0200 Subject: [PATCH 04/11] WIP: support different interface types: many fixes and improvements... --- assets/tpl/admin_create_clients.html | 4 +- assets/tpl/admin_edit_client.html | 35 +++++++-------- assets/tpl/admin_edit_interface.html | 61 ++++++++++++++------------- assets/tpl/admin_edit_user.html | 8 ++-- internal/server/handlers_interface.go | 40 +++++++++++++++++- internal/server/server_helper.go | 29 +++++++++---- internal/wireguard/peermanager.go | 29 +++++++------ internal/wireguard/template.go | 2 +- internal/wireguard/tpl/interface.tpl | 2 +- internal/wireguard/tpl/peer.tpl | 2 +- 10 files changed, 134 insertions(+), 78 deletions(-) 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 }} From 39903922dde07d235d4bbb185ae1cb96fc82662e Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sun, 4 Apr 2021 00:04:59 +0200 Subject: [PATCH 05/11] WIP: support different interface types: improve placeholder values, allow bulk user creation for external email addresses --- assets/tpl/admin_edit_client.html | 4 ++-- assets/tpl/admin_edit_interface.html | 24 +++++++++++++++++------- internal/server/handlers_interface.go | 2 -- internal/server/handlers_peer.go | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index c34b419..419c601 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -96,7 +96,7 @@
- +
@@ -305,7 +305,7 @@
- +
diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index 50c3e6b..1af2c9c 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -74,6 +74,16 @@
+
+
+ + +
+
+ + +
+

Client's global configuration

@@ -94,7 +104,7 @@
- +
@@ -181,15 +191,15 @@
- +
- +
- +

Interface configuration hooks

@@ -271,11 +281,11 @@
- +
- +
@@ -312,7 +322,7 @@
- +

Interface configuration hooks

diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 67a0cb6..cf20c15 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.FirewallMark = 0 - formDevice.RoutingTable = "" formDevice.SaveConfig = false case wireguard.DeviceTypeCustom: } diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go index 9dd99ec..7e12e35 100644 --- a/internal/server/handlers_peer.go +++ b/internal/server/handlers_peer.go @@ -175,7 +175,7 @@ func (s *Server) PostAdminCreateLdapPeers(c *gin.Context) { emails := common.ParseStringList(formData.Emails) for i := range emails { // TODO: also check email addr for validity? - if !strings.ContainsRune(emails[i], '@') || s.users.GetUser(emails[i]) == nil { + if !strings.ContainsRune(emails[i], '@') { _ = s.updateFormInSession(c, formData) SetFlashMessage(c, "invalid email address: "+emails[i], "danger") c.Redirect(http.StatusSeeOther, "/admin/peer/createldap?formerr=mail") From 94ca1778847d1f316270bf52ff175e873b335892 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 5 Apr 2021 18:38:38 +0200 Subject: [PATCH 06/11] support different interface types: client and server mode --- assets/css/custom.css | 8 + assets/tpl/admin_edit_client.html | 124 +------ assets/tpl/admin_edit_interface.html | 505 ++++++++++---------------- assets/tpl/admin_index.html | 58 ++- internal/server/handlers_common.go | 1 + internal/server/handlers_interface.go | 22 +- internal/server/routes.go | 1 + internal/server/server_helper.go | 12 +- internal/wireguard/peermanager.go | 73 +++- internal/wireguard/tpl/interface.tpl | 29 +- internal/wireguard/tpl/peer.tpl | 2 +- 11 files changed, 378 insertions(+), 457 deletions(-) diff --git a/assets/css/custom.css b/assets/css/custom.css index f450dbb..f1a7a2c 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -80,4 +80,12 @@ pre{background:#f7f7f9}iframe{overflow:hidden;border:none}@media (min-width: 768 .form-group.required label:after { content:"*"; color:red; +} + +a.advanced-settings:before { + content: "Hide"; +} + +a.advanced-settings.collapsed:before { + content: "Show"; } \ No newline at end of file diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 419c601..4cf61bd 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -91,11 +91,11 @@
- +
- +
@@ -192,7 +192,7 @@
- +
@@ -209,124 +209,6 @@
- - Cancel - - {{end}} - - - {{if eq .Device.Type "custom"}} - {{if .Peer.IsNew}} -

Create a new peer

- {{else}} -

Edit peer: {{.Peer.Identifier}}

- {{end}} - -
- - - - - {{if .EditableKeys}} -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- {{else}} - - -
-
- - -
-
- {{end}} -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - -
-
- -
-
-
- - -
-
- - -
-
-
- - Cancel
diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index 1af2c9c..4373f09 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -23,338 +23,231 @@ -
- - - -

Server's interface configuration

-
-
- - + + + +

Server's interface configuration

+
+
+ + +
-
- {{if .EditableKeys}} -
-
- - + {{if .EditableKeys}} +
+
+ + +
-
-
-
- - +
+
+ + +
-
- {{else}} - -
-
- - + {{else}} + +
+
+ + +
-
- {{end}} -
-
- - + {{end}} +
+
+ + +
+
+ + +
-
- - +

Client's global configuration

+
+
+ + +
-
-
-
- - +
+
+ + +
+
+ + +
-
- - +
+
+ + +
+
+ + +
-
-

Client's global configuration

-
-
- - +

Interface configuration hooks

+
+
+ + +
-
-
-
- - +
+
+ + +
-
- - +
+
+ + +
-
-
-
- - +
+
+ + +
-
- - -
-
-

Interface configuration hooks

-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - Cancel - Apply Global Settings to peers - + +
+
+
+ + +
+
+ + +
+
+
+
+
+ + +
+
+
+
+ + + Cancel + Apply Global Settings to clients +
- - - -

Client's interface configuration

-
-
- - -
-
- {{if .EditableKeys}} -
-
- - -
-
-
-
- - -
-
- {{else}} - -
-
- - -
-
- {{end}} -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
-

Interface configuration hooks

-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - - Cancel -
-
- - -
-
- - - -

Custom interface configuration

-
-
- - -
-
- {{if .EditableKeys}} -
-
- - -
-
-
-
- - -
-
- {{else}} - -
-
- - -
-
- {{end}} -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
-
- - + + + +

Client's interface configuration

+
+
+ + +
+
+ {{if .EditableKeys}} +
+
+ + +
+
+
+
+ + +
+
+ {{else}} + +
+
+ + +
+
+ {{end}} +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+

Interface configuration hooks

+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
-
-
-

Peer's global configuration

-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-

Interface configuration hooks

-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - Cancel - Apply Global Settings to clients - + + Cancel +
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 2066777..8077b7f 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -18,7 +18,9 @@
- Interface status for {{.Device.DeviceName}} + Interface status for {{.Device.DeviceName}} {{if eq $.Device.Type "server"}}(server mode){{end}}{{if eq $.Device.Type "client"}}(client mode){{end}} + +         @@ -26,6 +28,7 @@
+ {{if eq $.Device.Type "server"}}
@@ -78,21 +81,60 @@
+ {{end}} + {{if eq $.Device.Type "client"}} +
+ + + + + + + + + + + + + + + +
Public Key:{{.Device.PublicKey}}
Enabled Endpoints:{{len .Device.Interface.Peers}}
Total Endpoints:{{.TotalPeers}}
+
+
+ + + + + + + + + + + + + + + +
IP Address:{{.Device.IPsStr}}
DNS servers:{{.Device.DNSStr}}
Default MTU:{{.Device.Mtu}}
+
+ {{end}}
- {{with or (eq $.Device.Type "server") (eq $.Device.Type "custom")}} + {{if eq $.Device.Type "server"}}

Current VPN Peers

{{end}} - {{with eq $.Device.Type "client"}} + {{if eq $.Device.Type "client"}}

Current VPN Endpoints

{{end}}
- {{with eq $.Device.Type "server"}} + {{if eq $.Device.Type "server"}} {{end}} M @@ -140,9 +182,11 @@ + {{if eq $.Device.Type "server"}} + {{end}} @@ -168,22 +212,28 @@

{{if $p.DeactivatedAt}}-{{else}} {{formatBytes $p.Peer.ReceiveBytes}} / {{formatBytes $p.Peer.TransmitBytes}}{{end}}

{{end}}
+ {{if eq $.Device.Type "server"}}
{{$p.Config}}
+ {{end}}
+ {{if eq $.Device.Type "server"}} + {{end}}
+ {{if eq $.Device.Type "server"}} + {{end}}
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}} From 39166250ea0b3d7e078c1c2bd76aa1e30ad67931 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 5 Apr 2021 19:12:27 +0200 Subject: [PATCH 07/11] fix some bugs in client mode, improve login ui --- assets/css/signin.css | 3 +++ assets/tpl/admin_edit_client.html | 37 ++++++--------------------- assets/tpl/admin_index.html | 2 +- assets/tpl/login.html | 22 +++++++++++----- assets/tpl/prt_nav.html | 4 +-- internal/server/handlers_common.go | 8 +++--- internal/server/handlers_interface.go | 2 +- internal/server/handlers_peer.go | 6 ++--- internal/server/handlers_user.go | 6 ++--- internal/server/server_helper.go | 32 ++++++++++++++++++++--- internal/wireguard/tpl/peer.tpl | 2 ++ 11 files changed, 72 insertions(+), 52 deletions(-) diff --git a/assets/css/signin.css b/assets/css/signin.css index e69de29..8479bf2 100644 --- a/assets/css/signin.css +++ b/assets/css/signin.css @@ -0,0 +1,3 @@ +.navbar { + padding: 0.5rem 1rem; +} \ No newline at end of file diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 4cf61bd..1cb0bfd 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -137,36 +137,9 @@ - {{if .EditableKeys}} -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- {{else}} - -
-
- - -
-
- {{end}} -
+ +
@@ -184,6 +157,12 @@
+
+
+ + +
+
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 8077b7f..026665a 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -163,7 +163,7 @@ {{$p.Identifier}} - {{$p.PublicKey}} + {{if eq $.Device.Type "server"}}{{$p.PublicKey}}{{end}}{{if eq $.Device.Type "client"}}{{$p.EndpointPublicKey}}{{end}} {{$p.Email}} {{$p.IPsStr}} {{$p.LastHandshake}} diff --git a/assets/tpl/login.html b/assets/tpl/login.html index a6b6287..e3e89b4 100644 --- a/assets/tpl/login.html +++ b/assets/tpl/login.html @@ -13,8 +13,17 @@ - -
+ + +
Please sign in
@@ -28,15 +37,16 @@
- + {{ if eq .error true }} -
- {{.message}} + {{end}} -
+
diff --git a/assets/tpl/prt_nav.html b/assets/tpl/prt_nav.html index 994f540..e997a44 100644 --- a/assets/tpl/prt_nav.html +++ b/assets/tpl/prt_nav.html @@ -27,8 +27,8 @@
diff --git a/internal/server/handlers_common.go b/internal/server/handlers_common.go index 2fa1087..476474b 100644 --- a/internal/server/handlers_common.go +++ b/internal/server/handlers_common.go @@ -23,7 +23,7 @@ func (s *Server) GetHandleError(c *gin.Context, code int, message, details strin "Session": GetSessionData(c), "Static": s.getStaticData(), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), }) } @@ -36,7 +36,7 @@ func (s *Server) GetIndex(c *gin.Context) { "Session": currentSession, "Static": s.getStaticData(), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), }) } @@ -104,7 +104,7 @@ func (s *Server) GetAdminIndex(c *gin.Context) { "TotalPeers": len(s.peers.GetAllPeers(currentSession.DeviceName)), "Users": s.users.GetUsers(), "Device": device, - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), }) } @@ -143,7 +143,7 @@ func (s *Server) GetUserIndex(c *gin.Context) { "TotalPeers": len(peers), "Users": []users.User{*s.users.GetUser(currentSession.Email)}, "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), }) } diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 96f477e..457ac3f 100644 --- a/internal/server/handlers_interface.go +++ b/internal/server/handlers_interface.go @@ -27,7 +27,7 @@ func (s *Server) GetAdminEditInterface(c *gin.Context) { "Static": s.getStaticData(), "Device": currentSession.FormData.(wireguard.Device), "EditableKeys": s.config.Core.EditableKeys, - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "Csrf": csrf.GetToken(c), }) } diff --git a/internal/server/handlers_peer.go b/internal/server/handlers_peer.go index 7e12e35..3933519 100644 --- a/internal/server/handlers_peer.go +++ b/internal/server/handlers_peer.go @@ -39,7 +39,7 @@ func (s *Server) GetAdminEditPeer(c *gin.Context) { "Peer": currentSession.FormData.(wireguard.Peer), "EditableKeys": s.config.Core.EditableKeys, "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "AdminEmail": s.config.Core.AdminUser, "Csrf": csrf.GetToken(c), }) @@ -99,7 +99,7 @@ func (s *Server) GetAdminCreatePeer(c *gin.Context) { "Peer": currentSession.FormData.(wireguard.Peer), "EditableKeys": s.config.Core.EditableKeys, "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "AdminEmail": s.config.Core.AdminUser, "Csrf": csrf.GetToken(c), }) @@ -154,7 +154,7 @@ func (s *Server) GetAdminCreateLdapPeers(c *gin.Context) { "Users": s.users.GetFilteredAndSortedUsers("lastname", "asc", ""), "FormData": currentSession.FormData.(LdapCreateForm), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "Csrf": csrf.GetToken(c), }) } diff --git a/internal/server/handlers_user.go b/internal/server/handlers_user.go index 17e9ff4..643e56f 100644 --- a/internal/server/handlers_user.go +++ b/internal/server/handlers_user.go @@ -58,7 +58,7 @@ func (s *Server) GetAdminUsersIndex(c *gin.Context) { "Users": dbUsers, "TotalUsers": len(s.users.GetUsers()), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), }) } @@ -78,7 +78,7 @@ func (s *Server) GetAdminUsersEdit(c *gin.Context) { "Static": s.getStaticData(), "User": currentSession.FormData.(users.User), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "Epoch": time.Time{}, "Csrf": csrf.GetToken(c), }) @@ -156,7 +156,7 @@ func (s *Server) GetAdminUsersCreate(c *gin.Context) { "Static": s.getStaticData(), "User": currentSession.FormData.(users.User), "Device": s.peers.GetDevice(currentSession.DeviceName), - "DeviceNames": s.wg.Cfg.DeviceNames, + "DeviceNames": s.GetDeviceNames(), "Epoch": time.Time{}, "Csrf": csrf.GetToken(c), }) diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index 5eec6b3..b0d8863 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -140,8 +140,13 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error { // Update WireGuard device var err error switch { - case peer.DeactivatedAt == &updateTime: - err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey) + case peer.DeactivatedAt != nil && *peer.DeactivatedAt == updateTime: + switch dev.Type { + case wireguard.DeviceTypeServer: + err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey) + case wireguard.DeviceTypeClient: + err = s.wg.RemovePeer(peer.DeviceName, peer.EndpointPublicKey) + } case peer.DeactivatedAt == nil && currentPeer.Peer != nil: err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev)) case peer.DeactivatedAt == nil && currentPeer.Peer == nil: @@ -161,8 +166,18 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error { // DeletePeer removes the peer from the physical WireGuard interface and the database. func (s *Server) DeletePeer(peer wireguard.Peer) error { + dev := s.peers.GetDevice(peer.DeviceName) + + var publicKey string + switch dev.Type { + case wireguard.DeviceTypeServer: + publicKey = peer.PublicKey + case wireguard.DeviceTypeClient: + publicKey = peer.EndpointPublicKey + } + // Delete WireGuard peer - if err := s.wg.RemovePeer(peer.DeviceName, peer.PublicKey); err != nil { + if err := s.wg.RemovePeer(peer.DeviceName, publicKey); err != nil { return errors.WithMessage(err, "failed to remove WireGuard peer") } @@ -308,3 +323,14 @@ func (s *Server) CreateUserDefaultPeer(email, device string) error { return nil } + +func (s *Server) GetDeviceNames() map[string]string { + devNames := make(map[string]string, len(s.wg.Cfg.DeviceNames)) + + for _, devName := range s.wg.Cfg.DeviceNames { + dev := s.peers.GetDevice(devName) + devNames[devName] = dev.DisplayName + } + + return devNames +} diff --git a/internal/wireguard/tpl/peer.tpl b/internal/wireguard/tpl/peer.tpl index 5899308..78c7fca 100644 --- a/internal/wireguard/tpl/peer.tpl +++ b/internal/wireguard/tpl/peer.tpl @@ -19,7 +19,9 @@ MTU = {{.Peer.Mtu}} [Peer] PublicKey = {{ .Peer.EndpointPublicKey }} Endpoint = {{ .Peer.Endpoint }} +{{- if .Peer.AllowedIPsStr}} AllowedIPs = {{ .Peer.AllowedIPsStr }} +{{- end}} {{- if .Peer.PresharedKey}} PresharedKey = {{ .Peer.PresharedKey }} {{- end}} From ba768dd2c3fce4c0edc3d0a056aa6ef7d7421bf8 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 5 Apr 2021 20:00:11 +0200 Subject: [PATCH 08/11] improve client mode, todo: migrate peers (new db schema) --- assets/tpl/admin_edit_client.html | 6 +-- assets/tpl/admin_index.html | 2 +- internal/server/configuration.go | 2 +- internal/server/handlers_interface.go | 1 - internal/server/server_helper.go | 69 +++++++++++---------------- internal/wireguard/peermanager.go | 33 ++++--------- internal/wireguard/tpl/interface.tpl | 7 +-- internal/wireguard/tpl/peer.tpl | 2 +- 8 files changed, 43 insertions(+), 79 deletions(-) diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index 1cb0bfd..a33a36b 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -28,7 +28,6 @@ - {{if .EditableKeys}}
@@ -138,7 +137,6 @@ -
@@ -153,8 +151,8 @@
- - + +
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 026665a..8077b7f 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -163,7 +163,7 @@ {{$p.Identifier}} - {{if eq $.Device.Type "server"}}{{$p.PublicKey}}{{end}}{{if eq $.Device.Type "client"}}{{$p.EndpointPublicKey}}{{end}} + {{$p.PublicKey}} {{$p.Email}} {{$p.IPsStr}} {{$p.LastHandshake}} diff --git a/internal/server/configuration.go b/internal/server/configuration.go index 2727967..5f2f3a7 100644 --- a/internal/server/configuration.go +++ b/internal/server/configuration.go @@ -106,7 +106,7 @@ func NewConfig() *Config { cfg.LDAP.DisabledAttribute = "userAccountControl" cfg.LDAP.AdminLdapGroup = "CN=WireGuardAdmins,OU=_O_IT,DC=COMPANY,DC=LOCAL" - cfg.WG.DeviceNames = []string{"wg0"} + cfg.WG.DeviceNames = []string{"wg0", "wg1"} cfg.WG.DefaultDeviceName = "wg0" cfg.WG.ConfigDirectoryPath = "/etc/wireguard" cfg.WG.ManageIPAddresses = true diff --git a/internal/server/handlers_interface.go b/internal/server/handlers_interface.go index 457ac3f..f22dec5 100644 --- a/internal/server/handlers_interface.go +++ b/internal/server/handlers_interface.go @@ -162,7 +162,6 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) { peer.PersistentKeepalive = device.DefaultPersistentKeepalive peer.DNSStr = device.DNSStr peer.Mtu = device.Mtu - peer.EndpointPublicKey = device.PublicKey if err := s.peers.UpdatePeer(peer); err != nil { SetFlashMessage(c, err.Error(), "danger") diff --git a/internal/server/server_helper.go b/internal/server/server_helper.go index b0d8863..5eca32d 100644 --- a/internal/server/server_helper.go +++ b/internal/server/server_helper.go @@ -23,37 +23,37 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) { peer := wireguard.Peer{} peer.IsNew = true - peerIPs := make([]string, len(deviceIPs)) - for i := range deviceIPs { - freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) - if err != nil { - return wireguard.Peer{}, errors.WithMessage(err, "failed to get available IP addresses") - } - peerIPs[i] = freeIP - } - peer.SetIPAddresses(peerIPs...) - psk, err := wgtypes.GenerateKey() - if err != nil { - return wireguard.Peer{}, errors.Wrap(err, "failed to generate key") - } - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - return wireguard.Peer{}, errors.Wrap(err, "failed to generate private key") - } - peer.PresharedKey = psk.String() - peer.PrivateKey = key.String() - peer.PublicKey = key.PublicKey().String() - peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey))) switch dev.Type { case wireguard.DeviceTypeServer: - peer.EndpointPublicKey = dev.PublicKey + peerIPs := make([]string, len(deviceIPs)) + for i := range deviceIPs { + freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) + if err != nil { + return wireguard.Peer{}, errors.WithMessage(err, "failed to get available IP addresses") + } + peerIPs[i] = freeIP + } + peer.SetIPAddresses(peerIPs...) + psk, err := wgtypes.GenerateKey() + if err != nil { + return wireguard.Peer{}, errors.Wrap(err, "failed to generate key") + } + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return wireguard.Peer{}, errors.Wrap(err, "failed to generate private key") + } + peer.PresharedKey = psk.String() + peer.PrivateKey = key.String() + peer.PublicKey = key.PublicKey().String() + peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey))) peer.Endpoint = dev.DefaultEndpoint peer.DNSStr = dev.DNSStr peer.PersistentKeepalive = dev.DefaultPersistentKeepalive peer.AllowedIPsStr = dev.DefaultAllowedIPsStr peer.Mtu = dev.Mtu case wireguard.DeviceTypeClient: + peer.UID = "newendpoint" } return peer, nil @@ -90,7 +90,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error { peerIPs := peer.GetIPAddresses() peer.AllowedIPsStr = dev.DefaultAllowedIPsStr - if len(peerIPs) == 0 { + if len(peerIPs) == 0 && dev.Type == wireguard.DeviceTypeServer { peerIPs = make([]string, len(deviceIPs)) for i := range deviceIPs { freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) @@ -101,7 +101,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error { } peer.SetIPAddresses(peerIPs...) } - if peer.PrivateKey == "" { // if private key is empty create a new one + if peer.PrivateKey == "" && dev.Type == wireguard.DeviceTypeServer { // if private key is empty create a new one psk, err := wgtypes.GenerateKey() if err != nil { return errors.Wrap(err, "failed to generate key") @@ -141,12 +141,7 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error { var err error switch { case peer.DeactivatedAt != nil && *peer.DeactivatedAt == updateTime: - switch dev.Type { - case wireguard.DeviceTypeServer: - err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey) - case wireguard.DeviceTypeClient: - err = s.wg.RemovePeer(peer.DeviceName, peer.EndpointPublicKey) - } + err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey) case peer.DeactivatedAt == nil && currentPeer.Peer != nil: err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev)) case peer.DeactivatedAt == nil && currentPeer.Peer == nil: @@ -156,6 +151,8 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error { return errors.WithMessage(err, "failed to update WireGuard peer") } + peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey))) + // Update in database if err := s.peers.UpdatePeer(peer); err != nil { return errors.WithMessage(err, "failed to update peer") @@ -166,18 +163,8 @@ func (s *Server) UpdatePeer(peer wireguard.Peer, updateTime time.Time) error { // DeletePeer removes the peer from the physical WireGuard interface and the database. func (s *Server) DeletePeer(peer wireguard.Peer) error { - dev := s.peers.GetDevice(peer.DeviceName) - - var publicKey string - switch dev.Type { - case wireguard.DeviceTypeServer: - publicKey = peer.PublicKey - case wireguard.DeviceTypeClient: - publicKey = peer.EndpointPublicKey - } - // Delete WireGuard peer - if err := s.wg.RemovePeer(peer.DeviceName, publicKey); err != nil { + if err := s.wg.RemovePeer(peer.DeviceName, peer.PublicKey); err != nil { return errors.WithMessage(err, "failed to remove WireGuard peer") } diff --git a/internal/wireguard/peermanager.go b/internal/wireguard/peermanager.go index 56a8dfd..cf1abb0 100644 --- a/internal/wireguard/peermanager.go +++ b/internal/wireguard/peermanager.go @@ -88,10 +88,9 @@ type Peer struct { PersistentKeepalive int `form:"keepalive" binding:"gte=0"` // 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 - DNSStr string `form:"dns" binding:"iplist"` // comma separated list of the DNS servers for the client + 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 + 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"` @@ -126,14 +125,8 @@ func (p Peer) GetAllowedIPs() []string { return common.ParseStringList(p.AllowedIPsStr) } -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) - } +func (p Peer) GetConfig(_ *Device) wgtypes.PeerConfig { + publicKey, _ := wgtypes.ParseKey(p.PublicKey) var presharedKey *wgtypes.Key if p.PresharedKey != "" { @@ -432,18 +425,11 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e 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() + peer.PublicKey = wgPeer.PublicKey.String() if wgPeer.Endpoint != nil { peer.Endpoint = wgPeer.Endpoint.String() } - peer.Identifier = "Autodetected Endpoint (" + peer.EndpointPublicKey[0:8] + ")" + peer.Identifier = "Autodetected Endpoint (" + peer.PublicKey[0:8] + ")" } if wgPeer.PresharedKey != (wgtypes.Key{}) { peer.PresharedKey = wgPeer.PresharedKey.String() @@ -525,6 +511,7 @@ func (m *PeerManager) populatePeerData(peer *Peer) { } // fixPeerDefaultData tries to fill all required fields for the given peer +// also tries to migrate data if the database schema changed func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error { updatePeer := false @@ -534,10 +521,6 @@ func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error { peer.Endpoint = device.DefaultEndpoint updatePeer = true } - if peer.EndpointPublicKey == "" { - peer.EndpointPublicKey = device.PublicKey - updatePeer = true - } case DeviceTypeClient: } diff --git a/internal/wireguard/tpl/interface.tpl b/internal/wireguard/tpl/interface.tpl index f8aa3d2..318e2b7 100644 --- a/internal/wireguard/tpl/interface.tpl +++ b/internal/wireguard/tpl/interface.tpl @@ -52,14 +52,11 @@ PostDown = {{ .Interface.PostDown }} {{- if not .DeactivatedAt}} # -WGP- Peer: {{.Identifier}} / Updated: {{.UpdatedAt}} / Created: {{.CreatedAt}} # -WGP- Peer email: {{.Email}} +{{- if .PrivateKey}} # -WGP- PrivateKey: {{.PrivateKey}} +{{- end}} [Peer] -{{- if eq $.Interface.Type "server"}} PublicKey = {{ .PublicKey }} -{{- end}} -{{- if eq $.Interface.Type "client"}} -PublicKey = {{ .EndpointPublicKey }} -{{- end}} {{- if .PresharedKey}} PresharedKey = {{ .PresharedKey }} {{- end}} diff --git a/internal/wireguard/tpl/peer.tpl b/internal/wireguard/tpl/peer.tpl index 78c7fca..7f94732 100644 --- a/internal/wireguard/tpl/peer.tpl +++ b/internal/wireguard/tpl/peer.tpl @@ -17,7 +17,7 @@ MTU = {{.Peer.Mtu}} {{- end}} [Peer] -PublicKey = {{ .Peer.EndpointPublicKey }} +PublicKey = {{ .Peer.PublicKey }} Endpoint = {{ .Peer.Endpoint }} {{- if .Peer.AllowedIPsStr}} AllowedIPs = {{ .Peer.AllowedIPsStr }} From b4f3228bec815f7c6089b3149678e39e6624b1c0 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 5 Apr 2021 23:18:02 +0200 Subject: [PATCH 09/11] more ui improvements, fix peer template for clients --- assets/css/custom.css | 12 ++++++++ assets/tpl/admin_edit_client.html | 18 +++++++---- assets/tpl/admin_edit_interface.html | 4 +-- assets/tpl/admin_index.html | 14 +++++++++ assets/tpl/login.html | 2 +- internal/server/configuration.go | 2 +- internal/wireguard/peermanager.go | 45 +++++++--------------------- internal/wireguard/tpl/peer.tpl | 2 +- 8 files changed, 53 insertions(+), 46 deletions(-) diff --git a/assets/css/custom.css b/assets/css/custom.css index f1a7a2c..5a7d603 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -88,4 +88,16 @@ a.advanced-settings:before { a.advanced-settings.collapsed:before { content: "Show"; +} + +.form-group.global-config label:after, .custom-control.global-config label:after { + content: "g"; + color: #0057bb; + font-size: xx-small; + top: -5px; + position: absolute; +} + +.text-blue { + color: #0057bb; } \ No newline at end of file diff --git a/assets/tpl/admin_edit_client.html b/assets/tpl/admin_edit_client.html index a33a36b..7590957 100644 --- a/assets/tpl/admin_edit_client.html +++ b/assets/tpl/admin_edit_client.html @@ -77,23 +77,23 @@
-
+
-
+
-
+
-
+
@@ -110,7 +110,7 @@
@@ -168,10 +168,16 @@
-
+
+
+
+ + +
+
diff --git a/assets/tpl/admin_edit_interface.html b/assets/tpl/admin_edit_interface.html index 4373f09..dfcce2c 100644 --- a/assets/tpl/admin_edit_interface.html +++ b/assets/tpl/admin_edit_interface.html @@ -71,7 +71,7 @@
-

Client's global configuration

+

Client's global configuration (g)

@@ -156,7 +156,7 @@ Cancel - Apply Global Settings to clients + Apply Global Settings (g) to clients
diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 8077b7f..089e6ad 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -147,8 +147,15 @@ Identifier Public Key + {{if eq $.Device.Type "server"}} E-Mail + {{end}} + {{if eq $.Device.Type "server"}} IP's + {{end}} + {{if eq $.Device.Type "client"}} + Endpoint + {{end}} Handshake @@ -164,8 +171,15 @@ {{$p.Identifier}} {{$p.PublicKey}} + {{if eq $.Device.Type "server"}} {{$p.Email}} + {{end}} + {{if eq $.Device.Type "server"}} {{$p.IPsStr}} + {{end}} + {{if eq $.Device.Type "client"}} + {{$p.Endpoint}} + {{end}} {{$p.LastHandshake}} {{if eq $.Session.IsAdmin true}} diff --git a/assets/tpl/login.html b/assets/tpl/login.html index e3e89b4..74e2bb0 100644 --- a/assets/tpl/login.html +++ b/assets/tpl/login.html @@ -40,7 +40,7 @@ {{ if eq .error true }} -