github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/endpoint.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 endpoint
    19  
    20  import (
    21  	"fmt"
    22  	"net"
    23  
    24  	"github.com/pkg/errors"
    25  	"github.com/rs/zerolog/log"
    26  
    27  	"github.com/mysteriumnetwork/node/config"
    28  	wg "github.com/mysteriumnetwork/node/services/wireguard"
    29  	"github.com/mysteriumnetwork/node/services/wireguard/key"
    30  	"github.com/mysteriumnetwork/node/services/wireguard/resources"
    31  	"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
    32  	"github.com/mysteriumnetwork/node/utils/netutil"
    33  )
    34  
    35  // NewConnectionEndpoint returns new connection endpoint instance.
    36  func NewConnectionEndpoint(resourceAllocator *resources.Allocator, wgClientFactory *WgClientFactory) (wg.ConnectionEndpoint, error) {
    37  	wgClient, err := wgClientFactory.NewWGClient()
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	return &connectionEndpoint{
    43  		wgClient:          wgClient,
    44  		resourceAllocator: resourceAllocator,
    45  	}, nil
    46  }
    47  
    48  type connectionEndpoint struct {
    49  	cfg               wgcfg.DeviceConfig
    50  	endpoint          net.UDPAddr
    51  	resourceAllocator *resources.Allocator
    52  	wgClient          WgClient
    53  }
    54  
    55  // StartConsumerMode starts and configure wireguard network interface running in consumer mode.
    56  func (ce *connectionEndpoint) StartConsumerMode(cfg wgcfg.DeviceConfig) error {
    57  	if err := ce.cleanAbandonedInterfaces(); err != nil {
    58  		return err
    59  	}
    60  
    61  	var iface string
    62  	var err error
    63  	if cfg.ProxyPort > 0 {
    64  		iface = fmt.Sprintf("myst%d", cfg.ProxyPort)
    65  	} else {
    66  		iface, err = ce.resourceAllocator.AllocateInterface()
    67  		if err != nil {
    68  			return errors.Wrap(err, "could not allocate interface")
    69  		}
    70  	}
    71  
    72  	log.Debug().Msgf("Allocated interface: %s", iface)
    73  
    74  	cfg.IfaceName = iface
    75  	ce.cfg = cfg
    76  
    77  	if err := ce.wgClient.ConfigureDevice(cfg); err != nil {
    78  		if err1 := ce.resourceAllocator.ReleaseInterface(iface); err1 != nil {
    79  			log.Error().Err(err1).Msg("Can't release allocated interface " + iface)
    80  		}
    81  		return errors.Wrap(err, "could not configure device")
    82  	}
    83  	return nil
    84  }
    85  
    86  func (ce *connectionEndpoint) ReconfigureConsumerMode(cfg wgcfg.DeviceConfig) error {
    87  	cfg.IfaceName = ce.cfg.IfaceName
    88  	ce.cfg = cfg
    89  
    90  	if err := ce.wgClient.ReConfigureDevice(cfg); err != nil {
    91  		return fmt.Errorf("could not reconfigure device: %w", err)
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (ce *connectionEndpoint) StartProviderMode(publicIP string, config wgcfg.DeviceConfig) (err error) {
    98  	if publicIP == "" {
    99  		return errors.New("public IP is required")
   100  	}
   101  	if config.ListenPort == 0 {
   102  		return errors.New("listen port is required")
   103  	}
   104  
   105  	if err := ce.cleanAbandonedInterfaces(); err != nil {
   106  		return err
   107  	}
   108  
   109  	iface, err := ce.resourceAllocator.AllocateInterface()
   110  	if err != nil {
   111  		return errors.Wrap(err, "could not allocate interface")
   112  	}
   113  
   114  	config.IfaceName = iface
   115  	config.Subnet.IP = netutil.FirstIP(config.Subnet)
   116  	ce.cfg = config
   117  	ce.endpoint = net.UDPAddr{IP: net.ParseIP(publicIP), Port: config.ListenPort}
   118  
   119  	if err := ce.wgClient.ConfigureDevice(config); err != nil {
   120  		if err1 := ce.resourceAllocator.ReleaseInterface(iface); err1 != nil {
   121  			log.Error().Err(err1).Msg("Can't release allocated interface " + iface)
   122  		}
   123  		return errors.Wrap(err, "could not configure device")
   124  	}
   125  	return nil
   126  }
   127  
   128  // InterfaceName returns a connection endpoint interface name.
   129  func (ce *connectionEndpoint) InterfaceName() string {
   130  	return ce.cfg.IfaceName
   131  }
   132  
   133  // PeerStats returns stats information about connected peer.
   134  func (ce *connectionEndpoint) PeerStats() (wgcfg.Stats, error) {
   135  	return ce.wgClient.PeerStats(ce.cfg.IfaceName)
   136  }
   137  
   138  // Config provides wireguard service configuration for the current connection endpoint.
   139  func (ce *connectionEndpoint) Config() (wg.ServiceConfig, error) {
   140  	publicKey, err := key.PrivateKeyToPublicKey(ce.cfg.PrivateKey)
   141  	if err != nil {
   142  		return wg.ServiceConfig{}, err
   143  	}
   144  
   145  	var config wg.ServiceConfig
   146  	config.Provider.PublicKey = publicKey
   147  	config.Provider.Endpoint = ce.endpoint
   148  	config.Consumer.IPAddress = ce.cfg.Subnet
   149  	config.Consumer.IPAddress.IP = ce.consumerIP(ce.cfg.Subnet)
   150  	return config, nil
   151  }
   152  
   153  // Stop closes wireguard client and destroys wireguard network interface.
   154  func (ce *connectionEndpoint) Stop() error {
   155  	if err := ce.wgClient.Close(); err != nil {
   156  		return err
   157  	}
   158  
   159  	return ce.resourceAllocator.ReleaseInterface(ce.cfg.IfaceName)
   160  }
   161  
   162  func (ce *connectionEndpoint) cleanAbandonedInterfaces() error {
   163  	if config.GetBool(config.FlagDVPNMode) {
   164  		// Do not clean up unknown interfaces in dVPN mode.
   165  		// There could be several connections at the same time and we should not kill them.
   166  		return nil
   167  	}
   168  
   169  	ifaces, err := ce.resourceAllocator.AbandonedInterfaces()
   170  	if err != nil {
   171  		return err
   172  	}
   173  
   174  	for _, iface := range ifaces {
   175  		if err := ce.wgClient.DestroyDevice(iface.Name); err != nil {
   176  			log.Warn().Err(err).Msg("Failed to destroy abandoned interface: " + iface.Name)
   177  		}
   178  		log.Info().Msg("Abandoned interface destroyed: " + iface.Name)
   179  	}
   180  
   181  	return nil
   182  }