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 }