github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/netstack-provider/client.go (about)

     1  /*
     2   * Copyright (C) 2022 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package netstack_provider
    19  
    20  import (
    21  	"bufio"
    22  	"fmt"
    23  	"net/netip"
    24  	"strings"
    25  	"sync"
    26  
    27  	"github.com/rs/zerolog/log"
    28  	"golang.zx2c4.com/wireguard/conn"
    29  	"golang.zx2c4.com/wireguard/device"
    30  
    31  	"github.com/mysteriumnetwork/node/services/wireguard/endpoint/userspace"
    32  	"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
    33  )
    34  
    35  type client struct {
    36  	mu     sync.Mutex
    37  	Device *device.Device
    38  }
    39  
    40  // New create new WireGuard client in full userspace environment using netstack.
    41  func New() (*client, error) {
    42  	log.Debug().Msg("Creating userspace wg client")
    43  	return &client{}, nil
    44  }
    45  
    46  func (c *client) ReConfigureDevice(config wgcfg.DeviceConfig) error {
    47  	return c.ConfigureDevice(config)
    48  }
    49  
    50  func (c *client) ConfigureDevice(cfg wgcfg.DeviceConfig) error {
    51  	tunnel, _, _, err := CreateNetTUNWithStack([]netip.Addr{netip.MustParseAddr(cfg.Subnet.IP.String())}, cfg.DNSPort, device.DefaultMTU)
    52  	if err != nil {
    53  		return fmt.Errorf("failed to create netstack device %s: %w", cfg.IfaceName, err)
    54  	}
    55  
    56  	logger := device.NewLogger(device.LogLevelVerbose, fmt.Sprintf("(%s) ", cfg.IfaceName))
    57  	wgDevice := device.NewDevice(tunnel, conn.NewDefaultBind(), logger)
    58  
    59  	log.Info().Msg("Applying interface configuration")
    60  	if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil {
    61  		wgDevice.Close()
    62  		return fmt.Errorf("could not set device uapi config: %w", err)
    63  	}
    64  
    65  	log.Info().Msg("Bringing device up")
    66  	wgDevice.Up()
    67  
    68  	c.mu.Lock()
    69  	c.Device = wgDevice
    70  	c.mu.Unlock()
    71  
    72  	return nil
    73  }
    74  
    75  func (c *client) DestroyDevice(iface string) error {
    76  	return c.Close()
    77  }
    78  
    79  func (c *client) PeerStats(iface string) (wgcfg.Stats, error) {
    80  	deviceState, err := userspace.ParseUserspaceDevice(c.Device.IpcGetOperation)
    81  	if err != nil {
    82  		return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err)
    83  	}
    84  
    85  	stats, statErr := userspace.ParseDevicePeerStats(deviceState)
    86  	if err != nil {
    87  		err = statErr
    88  		log.Warn().Err(err).Msg("Failed to parse device stats, will try again")
    89  	} else {
    90  		return stats, nil
    91  	}
    92  
    93  	return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err)
    94  }
    95  
    96  func (c *client) Close() (err error) {
    97  	c.mu.Lock()
    98  	defer c.mu.Unlock()
    99  
   100  	if c.Device != nil {
   101  		c.Device.Close()
   102  	}
   103  
   104  	return nil
   105  }