improve client mode, todo: migrate peers (new db schema)

This commit is contained in:
Christoph Haas 2021-04-05 20:00:11 +02:00
parent 39166250ea
commit ba768dd2c3
8 changed files with 43 additions and 79 deletions

View File

@ -28,7 +28,6 @@
<input type="hidden" name="uid" value="{{.Peer.UID}}"> <input type="hidden" name="uid" value="{{.Peer.UID}}">
<input type="hidden" name="devicetype" value="{{.Device.Type}}"> <input type="hidden" name="devicetype" value="{{.Device.Type}}">
<input type="hidden" name="device" value="{{.Device.DeviceName}}"> <input type="hidden" name="device" value="{{.Device.DeviceName}}">
<input type="hidden" name="endpointpubkey" value="{{.Peer.EndpointPublicKey}}">
<input type="hidden" name="endpoint" value="{{.Peer.Endpoint}}"> <input type="hidden" name="endpoint" value="{{.Peer.Endpoint}}">
{{if .EditableKeys}} {{if .EditableKeys}}
<div class="form-row"> <div class="form-row">
@ -138,7 +137,6 @@
<input type="hidden" name="devicetype" value="{{.Device.Type}}"> <input type="hidden" name="devicetype" value="{{.Device.Type}}">
<input type="hidden" name="device" value="{{.Device.DeviceName}}"> <input type="hidden" name="device" value="{{.Device.DeviceName}}">
<input type="hidden" name="privkey" value="{{.Peer.PrivateKey}}"> <input type="hidden" name="privkey" value="{{.Peer.PrivateKey}}">
<input type="hidden" name="pubkey" value="{{.Peer.PublicKey}}">
<div class="form-row"> <div class="form-row">
<div class="form-group required col-md-12"> <div class="form-group required col-md-12">
<label for="client_Identifier">Endpoint Friendly Name</label> <label for="client_Identifier">Endpoint Friendly Name</label>
@ -153,8 +151,8 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="form-group required col-md-12"> <div class="form-group required col-md-12">
<label for="client_EndpointPublicKey">Endpoint Public Key</label> <label for="client_PublicKey">Endpoint Public Key</label>
<input type="text" name="endpointpubkey" class="form-control" id="client_EndpointPublicKey" value="{{.Peer.EndpointPublicKey}}" required> <input type="text" name="pubkey" class="form-control" id="client_PublicKey" value="{{.Peer.PublicKey}}" required>
</div> </div>
</div> </div>
<div class="form-row"> <div class="form-row">

View File

@ -163,7 +163,7 @@
<span title="Online status" class="online-status" id="online-{{$p.UID}}" data-pkey="{{$p.PublicKey}}"><i class="fas fa-unlink"></i></span> <span title="Online status" class="online-status" id="online-{{$p.UID}}" data-pkey="{{$p.PublicKey}}"><i class="fas fa-unlink"></i></span>
</th> </th>
<td>{{$p.Identifier}}</td> <td>{{$p.Identifier}}</td>
<td>{{if eq $.Device.Type "server"}}{{$p.PublicKey}}{{end}}{{if eq $.Device.Type "client"}}{{$p.EndpointPublicKey}}{{end}}</td> <td>{{$p.PublicKey}}</td>
<td>{{$p.Email}}</td> <td>{{$p.Email}}</td>
<td>{{$p.IPsStr}}</td> <td>{{$p.IPsStr}}</td>
<td><span data-toggle="tooltip" data-placement="left" title="" data-original-title="{{$p.LastHandshakeTime}}">{{$p.LastHandshake}}</span></td> <td><span data-toggle="tooltip" data-placement="left" title="" data-original-title="{{$p.LastHandshakeTime}}">{{$p.LastHandshake}}</span></td>

View File

@ -106,7 +106,7 @@ func NewConfig() *Config {
cfg.LDAP.DisabledAttribute = "userAccountControl" cfg.LDAP.DisabledAttribute = "userAccountControl"
cfg.LDAP.AdminLdapGroup = "CN=WireGuardAdmins,OU=_O_IT,DC=COMPANY,DC=LOCAL" 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.DefaultDeviceName = "wg0"
cfg.WG.ConfigDirectoryPath = "/etc/wireguard" cfg.WG.ConfigDirectoryPath = "/etc/wireguard"
cfg.WG.ManageIPAddresses = true cfg.WG.ManageIPAddresses = true

View File

@ -162,7 +162,6 @@ func (s *Server) GetApplyGlobalConfig(c *gin.Context) {
peer.PersistentKeepalive = device.DefaultPersistentKeepalive peer.PersistentKeepalive = device.DefaultPersistentKeepalive
peer.DNSStr = device.DNSStr peer.DNSStr = device.DNSStr
peer.Mtu = device.Mtu peer.Mtu = device.Mtu
peer.EndpointPublicKey = device.PublicKey
if err := s.peers.UpdatePeer(peer); err != nil { if err := s.peers.UpdatePeer(peer); err != nil {
SetFlashMessage(c, err.Error(), "danger") SetFlashMessage(c, err.Error(), "danger")

View File

@ -23,37 +23,37 @@ func (s *Server) PrepareNewPeer(device string) (wireguard.Peer, error) {
peer := wireguard.Peer{} peer := wireguard.Peer{}
peer.IsNew = true 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 { switch dev.Type {
case wireguard.DeviceTypeServer: 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.Endpoint = dev.DefaultEndpoint
peer.DNSStr = dev.DNSStr peer.DNSStr = dev.DNSStr
peer.PersistentKeepalive = dev.DefaultPersistentKeepalive peer.PersistentKeepalive = dev.DefaultPersistentKeepalive
peer.AllowedIPsStr = dev.DefaultAllowedIPsStr peer.AllowedIPsStr = dev.DefaultAllowedIPsStr
peer.Mtu = dev.Mtu peer.Mtu = dev.Mtu
case wireguard.DeviceTypeClient: case wireguard.DeviceTypeClient:
peer.UID = "newendpoint"
} }
return peer, nil return peer, nil
@ -90,7 +90,7 @@ func (s *Server) CreatePeer(device string, peer wireguard.Peer) error {
peerIPs := peer.GetIPAddresses() peerIPs := peer.GetIPAddresses()
peer.AllowedIPsStr = dev.DefaultAllowedIPsStr peer.AllowedIPsStr = dev.DefaultAllowedIPsStr
if len(peerIPs) == 0 { if len(peerIPs) == 0 && dev.Type == wireguard.DeviceTypeServer {
peerIPs = make([]string, len(deviceIPs)) peerIPs = make([]string, len(deviceIPs))
for i := range deviceIPs { for i := range deviceIPs {
freeIP, err := s.peers.GetAvailableIp(device, deviceIPs[i]) 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...) 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() psk, err := wgtypes.GenerateKey()
if err != nil { if err != nil {
return errors.Wrap(err, "failed to generate key") 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 var err error
switch { switch {
case peer.DeactivatedAt != nil && *peer.DeactivatedAt == updateTime: case peer.DeactivatedAt != nil && *peer.DeactivatedAt == updateTime:
switch dev.Type { err = s.wg.RemovePeer(peer.DeviceName, peer.PublicKey)
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: case peer.DeactivatedAt == nil && currentPeer.Peer != nil:
err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev)) err = s.wg.UpdatePeer(peer.DeviceName, peer.GetConfig(&dev))
case peer.DeactivatedAt == nil && currentPeer.Peer == nil: 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") return errors.WithMessage(err, "failed to update WireGuard peer")
} }
peer.UID = fmt.Sprintf("u%x", md5.Sum([]byte(peer.PublicKey)))
// Update in database // Update in database
if err := s.peers.UpdatePeer(peer); err != nil { if err := s.peers.UpdatePeer(peer); err != nil {
return errors.WithMessage(err, "failed to update peer") 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. // DeletePeer removes the peer from the physical WireGuard interface and the database.
func (s *Server) DeletePeer(peer wireguard.Peer) error { 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 // 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") return errors.WithMessage(err, "failed to remove WireGuard peer")
} }

View File

@ -88,10 +88,9 @@ type Peer struct {
PersistentKeepalive int `form:"keepalive" binding:"gte=0"` PersistentKeepalive int `form:"keepalive" binding:"gte=0"`
// Misc. WireGuard Settings // Misc. WireGuard Settings
EndpointPublicKey string `form:"endpointpubkey" binding:"required,base64"` // the public key of the remote endpoint PrivateKey string `form:"privkey" binding:"omitempty,base64"`
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
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) // Global Device Settings (can be ignored, only make sense if device is in server mode)
Mtu int `form:"mtu" binding:"gte=0,lte=1500"` Mtu int `form:"mtu" binding:"gte=0,lte=1500"`
@ -126,14 +125,8 @@ func (p Peer) GetAllowedIPs() []string {
return common.ParseStringList(p.AllowedIPsStr) return common.ParseStringList(p.AllowedIPsStr)
} }
func (p Peer) GetConfig(dev *Device) wgtypes.PeerConfig { func (p Peer) GetConfig(_ *Device) wgtypes.PeerConfig {
var publicKey wgtypes.Key publicKey, _ := wgtypes.ParseKey(p.PublicKey)
switch dev.Type {
case DeviceTypeServer:
publicKey, _ = wgtypes.ParseKey(p.PublicKey)
case DeviceTypeClient:
publicKey, _ = wgtypes.ParseKey(p.EndpointPublicKey)
}
var presharedKey *wgtypes.Key var presharedKey *wgtypes.Key
if p.PresharedKey != "" { if p.PresharedKey != "" {
@ -432,18 +425,11 @@ func (m *PeerManager) validateOrCreatePeer(device string, wgPeer wgtypes.Peer) e
peer.PublicKey = wgPeer.PublicKey.String() peer.PublicKey = wgPeer.PublicKey.String()
peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")" peer.Identifier = "Autodetected Client (" + peer.PublicKey[0:8] + ")"
} else if dev.Type == DeviceTypeClient { } else if dev.Type == DeviceTypeClient {
// create a new key pair, not really needed but otherwise our "client exists" detection does not work... peer.PublicKey = wgPeer.PublicKey.String()
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 { if wgPeer.Endpoint != nil {
peer.Endpoint = wgPeer.Endpoint.String() 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{}) { if wgPeer.PresharedKey != (wgtypes.Key{}) {
peer.PresharedKey = wgPeer.PresharedKey.String() 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 // 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 { func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error {
updatePeer := false updatePeer := false
@ -534,10 +521,6 @@ func (m *PeerManager) fixPeerDefaultData(peer *Peer, device *Device) error {
peer.Endpoint = device.DefaultEndpoint peer.Endpoint = device.DefaultEndpoint
updatePeer = true updatePeer = true
} }
if peer.EndpointPublicKey == "" {
peer.EndpointPublicKey = device.PublicKey
updatePeer = true
}
case DeviceTypeClient: case DeviceTypeClient:
} }

View File

@ -52,14 +52,11 @@ PostDown = {{ .Interface.PostDown }}
{{- if not .DeactivatedAt}} {{- if not .DeactivatedAt}}
# -WGP- Peer: {{.Identifier}} / Updated: {{.UpdatedAt}} / Created: {{.CreatedAt}} # -WGP- Peer: {{.Identifier}} / Updated: {{.UpdatedAt}} / Created: {{.CreatedAt}}
# -WGP- Peer email: {{.Email}} # -WGP- Peer email: {{.Email}}
{{- if .PrivateKey}}
# -WGP- PrivateKey: {{.PrivateKey}} # -WGP- PrivateKey: {{.PrivateKey}}
{{- end}}
[Peer] [Peer]
{{- if eq $.Interface.Type "server"}}
PublicKey = {{ .PublicKey }} PublicKey = {{ .PublicKey }}
{{- end}}
{{- if eq $.Interface.Type "client"}}
PublicKey = {{ .EndpointPublicKey }}
{{- end}}
{{- if .PresharedKey}} {{- if .PresharedKey}}
PresharedKey = {{ .PresharedKey }} PresharedKey = {{ .PresharedKey }}
{{- end}} {{- end}}

View File

@ -17,7 +17,7 @@ MTU = {{.Peer.Mtu}}
{{- end}} {{- end}}
[Peer] [Peer]
PublicKey = {{ .Peer.EndpointPublicKey }} PublicKey = {{ .Peer.PublicKey }}
Endpoint = {{ .Peer.Endpoint }} Endpoint = {{ .Peer.Endpoint }}
{{- if .Peer.AllowedIPsStr}} {{- if .Peer.AllowedIPsStr}}
AllowedIPs = {{ .Peer.AllowedIPsStr }} AllowedIPs = {{ .Peer.AllowedIPsStr }}