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

     1  /*
     2   * Copyright (C) 2018 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 userspace
    19  
    20  import (
    21  	"bufio"
    22  	"fmt"
    23  	"strings"
    24  
    25  	"github.com/pkg/errors"
    26  	"golang.zx2c4.com/wireguard/conn"
    27  	"golang.zx2c4.com/wireguard/device"
    28  	"golang.zx2c4.com/wireguard/tun"
    29  
    30  	"github.com/mysteriumnetwork/node/services/wireguard/connection/dns"
    31  	"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
    32  	"github.com/mysteriumnetwork/node/utils/actionstack"
    33  	"github.com/mysteriumnetwork/node/utils/netutil"
    34  )
    35  
    36  type client struct {
    37  	tun        tun.Device
    38  	devAPI     *device.Device
    39  	dnsManager dns.Manager
    40  }
    41  
    42  // NewWireguardClient creates new wireguard user space client.
    43  func NewWireguardClient() (*client, error) {
    44  	return &client{
    45  		dnsManager: dns.NewManager(),
    46  	}, nil
    47  }
    48  
    49  func (c *client) ConfigureDevice(config wgcfg.DeviceConfig) (err error) {
    50  	rollback := actionstack.NewActionStack()
    51  	if c.tun, err = CreateTUN(config.IfaceName, config.Subnet); err != nil {
    52  		return errors.Wrap(err, "failed to create TUN device")
    53  	}
    54  
    55  	devAPI := device.NewDevice(c.tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "[userspace-wg]"))
    56  	c.devAPI = devAPI
    57  	rollback.Push(func() {
    58  		devAPI.Close()
    59  		c.devAPI = nil
    60  	})
    61  
    62  	if err := c.configureDevice(config); err != nil {
    63  		rollback.Run()
    64  		return err
    65  	}
    66  
    67  	if config.Peer.Endpoint != nil {
    68  		if err := netutil.AddDefaultRoute(config.IfaceName); err != nil {
    69  			rollback.Run()
    70  			return fmt.Errorf("could not add default route for %s: %w", config.IfaceName, err)
    71  		}
    72  	}
    73  
    74  	return nil
    75  }
    76  
    77  func (c *client) ReConfigureDevice(config wgcfg.DeviceConfig) (err error) {
    78  	if err = netutil.AssignIP(config.IfaceName, config.Subnet); err != nil {
    79  		return fmt.Errorf("failed to assign IP address: %w", err)
    80  	}
    81  
    82  	return c.configureDevice(config)
    83  }
    84  
    85  func (c *client) configureDevice(config wgcfg.DeviceConfig) (err error) {
    86  	if err := c.setDeviceConfig(config.Encode()); err != nil {
    87  		return errors.Wrap(err, "failed to configure initial device")
    88  	}
    89  
    90  	c.devAPI.Up()
    91  
    92  	if err := c.dnsManager.Set(dns.Config{
    93  		ScriptDir: config.DNSScriptDir,
    94  		IfaceName: config.IfaceName,
    95  		DNS:       config.DNS,
    96  	}); err != nil {
    97  		return fmt.Errorf("could not set DNS: %w", err)
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  func (c *client) Close() error {
   104  	c.devAPI.Close() // c.devAPI.Close() closes c.tun too
   105  	if err := c.dnsManager.Clean(); err != nil {
   106  		return fmt.Errorf("could not clean DNS: %w", err)
   107  	}
   108  	return nil
   109  }
   110  
   111  func (c *client) PeerStats(string) (wgcfg.Stats, error) {
   112  	deviceState, err := ParseUserspaceDevice(c.devAPI.IpcGetOperation)
   113  	if err != nil {
   114  		return wgcfg.Stats{}, err
   115  	}
   116  	stats, err := ParseDevicePeerStats(deviceState)
   117  	if err != nil {
   118  		return wgcfg.Stats{}, err
   119  	}
   120  	return stats, nil
   121  }
   122  
   123  func (c *client) DestroyDevice(name string) error {
   124  	return destroyDevice(name)
   125  }
   126  
   127  func (c *client) setDeviceConfig(config string) error {
   128  	if err := c.devAPI.IpcSetOperation(bufio.NewReader(strings.NewReader(config))); err != nil {
   129  		return errors.Wrap(err, "failed to set device config")
   130  	}
   131  	return nil
   132  }