Files
netbird/client/uiwails/services/network.go
Zoltán Papp 04a982263d Wails UI
2026-03-02 15:59:09 +01:00

223 lines
5.8 KiB
Go

//go:build !(linux && 386)
package services
import (
"context"
"fmt"
"sort"
"strings"
"time"
log "github.com/sirupsen/logrus"
"github.com/netbirdio/netbird/client/proto"
)
// NetworkService exposes network/route management to the Wails frontend.
type NetworkService struct {
grpcClient GRPCClientIface
}
// NewNetworkService creates a new NetworkService.
func NewNetworkService(g GRPCClientIface) *NetworkService {
return &NetworkService{grpcClient: g}
}
// NetworkInfo is a serializable view of a single network/route.
type NetworkInfo struct {
ID string `json:"id"`
Range string `json:"range"`
Domains []string `json:"domains"`
Selected bool `json:"selected"`
ResolvedIPs map[string][]string `json:"resolvedIPs"`
}
// ListNetworks returns all networks from the daemon.
func (s *NetworkService) ListNetworks() ([]NetworkInfo, error) {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return nil, fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := conn.ListNetworks(ctx, &proto.ListNetworksRequest{})
if err != nil {
return nil, fmt.Errorf("list networks rpc: %w", err)
}
routes := make([]NetworkInfo, 0, len(resp.Routes))
for _, r := range resp.Routes {
info := NetworkInfo{
ID: r.GetID(),
Range: r.GetRange(),
Domains: r.GetDomains(),
Selected: r.GetSelected(),
}
if resolvedMap := r.GetResolvedIPs(); resolvedMap != nil {
info.ResolvedIPs = make(map[string][]string)
for domain, ipList := range resolvedMap {
info.ResolvedIPs[domain] = ipList.GetIps()
}
}
routes = append(routes, info)
}
sort.Slice(routes, func(i, j int) bool {
return strings.ToLower(routes[i].ID) < strings.ToLower(routes[j].ID)
})
return routes, nil
}
// ListOverlappingNetworks returns only networks with overlapping ranges.
func (s *NetworkService) ListOverlappingNetworks() ([]NetworkInfo, error) {
all, err := s.ListNetworks()
if err != nil {
return nil, err
}
existingRange := make(map[string][]NetworkInfo)
for _, r := range all {
if len(r.Domains) > 0 {
continue
}
existingRange[r.Range] = append(existingRange[r.Range], r)
}
var result []NetworkInfo
for _, group := range existingRange {
if len(group) > 1 {
result = append(result, group...)
}
}
return result, nil
}
// ListExitNodes returns networks with range 0.0.0.0/0 (exit nodes).
func (s *NetworkService) ListExitNodes() ([]NetworkInfo, error) {
all, err := s.ListNetworks()
if err != nil {
return nil, err
}
var result []NetworkInfo
for _, r := range all {
if r.Range == "0.0.0.0/0" {
result = append(result, r)
}
}
return result, nil
}
// SelectNetwork selects a single network by ID.
func (s *NetworkService) SelectNetwork(id string) error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{
NetworkIDs: []string{id},
Append: true,
}
if _, err := conn.SelectNetworks(ctx, req); err != nil {
log.Errorf("SelectNetworks rpc failed: %v", err)
return fmt.Errorf("select network: %w", err)
}
return nil
}
// DeselectNetwork deselects a single network by ID.
func (s *NetworkService) DeselectNetwork(id string) error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{
NetworkIDs: []string{id},
}
if _, err := conn.DeselectNetworks(ctx, req); err != nil {
log.Errorf("DeselectNetworks rpc failed: %v", err)
return fmt.Errorf("deselect network: %w", err)
}
return nil
}
// SelectAllNetworks selects all networks.
func (s *NetworkService) SelectAllNetworks() error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{All: true}
if _, err := conn.SelectNetworks(ctx, req); err != nil {
return fmt.Errorf("select all networks: %w", err)
}
return nil
}
// DeselectAllNetworks deselects all networks.
func (s *NetworkService) DeselectAllNetworks() error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{All: true}
if _, err := conn.DeselectNetworks(ctx, req); err != nil {
return fmt.Errorf("deselect all networks: %w", err)
}
return nil
}
// SelectNetworks selects a list of networks by ID.
func (s *NetworkService) SelectNetworks(ids []string) error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{NetworkIDs: ids, Append: true}
if _, err := conn.SelectNetworks(ctx, req); err != nil {
return fmt.Errorf("select networks: %w", err)
}
return nil
}
// DeselectNetworks deselects a list of networks by ID.
func (s *NetworkService) DeselectNetworks(ids []string) error {
conn, err := s.grpcClient.GetClient(3 * time.Second)
if err != nil {
return fmt.Errorf("get client: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req := &proto.SelectNetworksRequest{NetworkIDs: ids}
if _, err := conn.DeselectNetworks(ctx, req); err != nil {
return fmt.Errorf("deselect networks: %w", err)
}
return nil
}