support different interface types: client and server mode

This commit is contained in:
Christoph Haas
2021-04-05 18:38:38 +02:00
parent 39903922dd
commit 94ca177884
11 changed files with 378 additions and 457 deletions

View File

@@ -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") == "" {

View File

@@ -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")

View File

@@ -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)

View File

@@ -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")
}
}

View File

@@ -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

View File

@@ -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}}

View File

@@ -8,7 +8,7 @@
PrivateKey = {{ .Peer.PrivateKey }}
Address = {{ .Peer.IPsStr }}
# Misc. settings
# Misc. settings (optional)
{{- if .Peer.DNSStr}}
DNS = {{ .Peer.DNSStr }}
{{- end}}