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

     1  /*
     2   * Copyright (C) 2019 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 service
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"net"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/jinzhu/copier"
    28  	"github.com/pkg/errors"
    29  	"github.com/rs/zerolog/log"
    30  
    31  	"github.com/mysteriumnetwork/node/config"
    32  	"github.com/mysteriumnetwork/node/core/ip"
    33  	"github.com/mysteriumnetwork/node/core/service"
    34  	"github.com/mysteriumnetwork/node/core/shaper"
    35  	"github.com/mysteriumnetwork/node/dns"
    36  	"github.com/mysteriumnetwork/node/eventbus"
    37  	"github.com/mysteriumnetwork/node/firewall"
    38  	"github.com/mysteriumnetwork/node/nat"
    39  	wg "github.com/mysteriumnetwork/node/services/wireguard"
    40  	"github.com/mysteriumnetwork/node/services/wireguard/endpoint"
    41  	"github.com/mysteriumnetwork/node/services/wireguard/key"
    42  	"github.com/mysteriumnetwork/node/services/wireguard/resources"
    43  	"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
    44  	"github.com/mysteriumnetwork/node/utils/netutil"
    45  )
    46  
    47  // NewManager creates new instance of Wireguard service
    48  func NewManager(
    49  	ipResolver ip.Resolver,
    50  	country string,
    51  	natService nat.NATService,
    52  	eventBus eventbus.EventBus,
    53  	trafficFirewall firewall.IncomingTrafficFirewall,
    54  	resourcesAllocator *resources.Allocator,
    55  	wgClientFactory *endpoint.WgClientFactory,
    56  	dnsProxy *dns.Proxy,
    57  ) *Manager {
    58  	return &Manager{
    59  		done:               make(chan struct{}),
    60  		resourcesAllocator: resourcesAllocator,
    61  		ipResolver:         ipResolver,
    62  		natService:         natService,
    63  		eventBus:           eventBus,
    64  		trafficFirewall:    trafficFirewall,
    65  		dnsProxy:           dnsProxy,
    66  
    67  		connEndpointFactory: func() (wg.ConnectionEndpoint, error) {
    68  			return endpoint.NewConnectionEndpoint(resourcesAllocator, wgClientFactory)
    69  		},
    70  		country:        country,
    71  		sessionCleanup: map[string]func(){},
    72  	}
    73  }
    74  
    75  // Manager represents an instance of Wireguard service
    76  type Manager struct {
    77  	done        chan struct{}
    78  	startStopMu sync.Mutex
    79  
    80  	resourcesAllocator *resources.Allocator
    81  
    82  	natService      nat.NATService
    83  	eventBus        eventbus.EventBus
    84  	trafficFirewall firewall.IncomingTrafficFirewall
    85  
    86  	dnsProxy *dns.Proxy
    87  
    88  	connEndpointFactory func() (wg.ConnectionEndpoint, error)
    89  
    90  	ipResolver ip.Resolver
    91  
    92  	serviceInstance  *service.Instance
    93  	sessionCleanup   map[string]func()
    94  	sessionCleanupMu sync.Mutex
    95  
    96  	country    string
    97  	outboundIP string
    98  }
    99  
   100  // ProvideConfig provides the config for consumer and handles new WireGuard connection.
   101  func (m *Manager) ProvideConfig(sessionID string, sessionConfig json.RawMessage, remoteConn *net.UDPConn) (*service.ConfigParams, error) {
   102  	log.Info().Msg("Accepting new WireGuard connection")
   103  	consumerConfig := wg.ConsumerConfig{}
   104  	err := json.Unmarshal(sessionConfig, &consumerConfig)
   105  	if err != nil {
   106  		return nil, errors.Wrap(err, "could not unmarshal wg consumer config")
   107  	}
   108  
   109  	remoteConn.Close()
   110  	listenPort := remoteConn.LocalAddr().(*net.UDPAddr).Port
   111  	providerConfig, err := m.createProviderConfig(listenPort, consumerConfig.PublicKey)
   112  	if err != nil {
   113  		return nil, fmt.Errorf("could not create provider mode wg config: %w", err)
   114  	}
   115  
   116  	publicIP, err := m.ipResolver.GetPublicIP()
   117  	if err != nil {
   118  		return nil, errors.Wrap(err, "could not get public IP")
   119  	}
   120  
   121  	conn, err := m.startNewConnection(publicIP, providerConfig)
   122  	if err != nil {
   123  		return nil, errors.Wrap(err, "could not start new connection")
   124  	}
   125  
   126  	config, err := conn.Config()
   127  	if err != nil {
   128  		return nil, errors.Wrap(err, "could not get peer config")
   129  	}
   130  
   131  	var dnsIP net.IP
   132  	var releaseTrafficFirewall firewall.IncomingRuleRemove
   133  	if m.serviceInstance.PolicyProvider().HasDNSRules() {
   134  		releaseTrafficFirewall, err = m.trafficFirewall.BlockIncomingTraffic(providerConfig.Subnet)
   135  		if err != nil {
   136  			return nil, errors.Wrap(err, "failed to enable traffic blocking")
   137  		}
   138  	}
   139  
   140  	dnsIP = netutil.FirstIP(config.Consumer.IPAddress)
   141  	config.Consumer.DNSIPs = dnsIP.String()
   142  
   143  	natRules, err := m.natService.Setup(nat.Options{
   144  		VPNNetwork:    config.Consumer.IPAddress,
   145  		DNSIP:         dnsIP,
   146  		ProviderExtIP: net.ParseIP(m.outboundIP),
   147  	})
   148  	if err != nil {
   149  		return nil, errors.Wrap(err, "failed to setup NAT/firewall rules")
   150  	}
   151  
   152  	statsPublisher := newStatsPublisher(m.eventBus, time.Second)
   153  	go statsPublisher.start(sessionID, conn)
   154  
   155  	ifaceName := conn.InterfaceName()
   156  	s := shaper.New(m.eventBus)
   157  	err = s.Start(ifaceName)
   158  	if err != nil {
   159  		log.Error().Err(err).Msg("Could not start traffic shaper")
   160  	}
   161  
   162  	destroy := func() {
   163  		log.Info().Msgf("Cleaning up session %s", sessionID)
   164  		m.sessionCleanupMu.Lock()
   165  		defer m.sessionCleanupMu.Unlock()
   166  		_, ok := m.sessionCleanup[sessionID]
   167  		if !ok {
   168  			log.Info().Msgf("Session '%s' was already cleaned up, returning without changes", sessionID)
   169  			return
   170  		}
   171  		delete(m.sessionCleanup, sessionID)
   172  
   173  		statsPublisher.stop()
   174  
   175  		s.Clear(ifaceName)
   176  
   177  		if releaseTrafficFirewall != nil {
   178  			if err := releaseTrafficFirewall(); err != nil {
   179  				log.Warn().Err(err).Msg("failed to disable traffic blocking")
   180  			}
   181  		}
   182  
   183  		log.Trace().Msg("Deleting nat rules")
   184  		if err := m.natService.Del(natRules); err != nil {
   185  			log.Error().Err(err).Msg("Failed to delete NAT rules")
   186  		}
   187  
   188  		log.Trace().Msg("Stopping connection endpoint")
   189  		if err := conn.Stop(); err != nil {
   190  			log.Error().Err(err).Msg("Failed to stop connection endpoint")
   191  		}
   192  
   193  		if err := m.resourcesAllocator.ReleaseIPNet(providerConfig.Subnet); err != nil {
   194  			log.Error().Err(err).Msg("Failed to release IP network")
   195  		}
   196  	}
   197  
   198  	m.sessionCleanupMu.Lock()
   199  	m.sessionCleanup[sessionID] = destroy
   200  	m.sessionCleanupMu.Unlock()
   201  
   202  	return &service.ConfigParams{SessionServiceConfig: config, SessionDestroyCallback: destroy}, nil
   203  }
   204  
   205  func (m *Manager) createProviderConfig(listenPort int, peerPublicKey string) (wgcfg.DeviceConfig, error) {
   206  	network, err := m.resourcesAllocator.AllocateIPNet()
   207  	if err != nil {
   208  		return wgcfg.DeviceConfig{}, errors.Wrap(err, "could not allocate provider IP NET")
   209  	}
   210  
   211  	privateKey, err := key.GeneratePrivateKey()
   212  	if err != nil {
   213  		return wgcfg.DeviceConfig{}, fmt.Errorf("could not generate private key: %w", err)
   214  	}
   215  
   216  	return wgcfg.DeviceConfig{
   217  		IfaceName:  "", // Interface name will be generated by connection endpoint.
   218  		MTU:        config.GetInt(config.FlagWireguardMTU),
   219  		Subnet:     network,
   220  		PrivateKey: privateKey,
   221  		ListenPort: listenPort,
   222  		DNSPort:    config.GetInt(config.FlagDNSListenPort),
   223  		DNS:        nil,
   224  		Peer: wgcfg.Peer{
   225  			PublicKey: peerPublicKey,
   226  			// Peer endpoint is set automatically by wg once client does handshake.
   227  			Endpoint:               nil,
   228  			AllowedIPs:             []string{"0.0.0.0/0", "::/0"},
   229  			KeepAlivePeriodSeconds: 0,
   230  		},
   231  		ReplacePeers: true,
   232  	}, nil
   233  }
   234  
   235  func (m *Manager) startNewConnection(publicIP string, config wgcfg.DeviceConfig) (wg.ConnectionEndpoint, error) {
   236  	connEndpoint, err := m.connEndpointFactory()
   237  	if err != nil {
   238  		return nil, errors.Wrap(err, "could not run conn endpoint factory")
   239  	}
   240  
   241  	if err := connEndpoint.StartProviderMode(publicIP, config); err != nil {
   242  		return nil, errors.Wrap(err, "could not start provider wg connection endpoint")
   243  	}
   244  	return connEndpoint, nil
   245  }
   246  
   247  // Serve starts service - does block
   248  func (m *Manager) Serve(instance *service.Instance) error {
   249  	log.Info().Msg("Wireguard: starting")
   250  	m.startStopMu.Lock()
   251  	m.serviceInstance = instance
   252  
   253  	var err error
   254  	m.outboundIP, err = m.ipResolver.GetOutboundIP()
   255  	if err != nil {
   256  		return errors.Wrap(err, "could not get outbound IP")
   257  	}
   258  
   259  	if err := m.dnsProxy.Run(); err != nil {
   260  		log.Error().Err(err).Msg("Provider DNS will not be available")
   261  
   262  		return err
   263  	}
   264  
   265  	m.startStopMu.Unlock()
   266  	log.Info().Msg("Wireguard: started")
   267  	<-m.done
   268  	return nil
   269  }
   270  
   271  // Stop stops service.
   272  func (m *Manager) Stop() error {
   273  	log.Info().Msg("Wireguard: stopping")
   274  	m.startStopMu.Lock()
   275  	defer m.startStopMu.Unlock()
   276  
   277  	cleanupWg := sync.WaitGroup{}
   278  
   279  	// prevent concurrent iteration and write
   280  	sessionCleanupCopy := make(map[string]func())
   281  	if err := copier.Copy(&sessionCleanupCopy, m.sessionCleanup); err != nil {
   282  		panic(err)
   283  	}
   284  	for k, v := range sessionCleanupCopy {
   285  		cleanupWg.Add(1)
   286  		go func(sessionID string, cleanup func()) {
   287  			defer cleanupWg.Done()
   288  			cleanup()
   289  		}(k, v)
   290  	}
   291  	cleanupWg.Wait()
   292  
   293  	// Stop DNS proxy.
   294  	if m.dnsProxy != nil {
   295  		if err := m.dnsProxy.Stop(); err != nil {
   296  			log.Error().Err(err).Msg("Failed to stop DNS server")
   297  		}
   298  	}
   299  
   300  	close(m.done)
   301  	log.Info().Msg("Wireguard: stopped")
   302  	return nil
   303  }