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

     1  /*
     2   * Copyright (C) 2017 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  	"errors"
    23  	"fmt"
    24  	"net"
    25  
    26  	"github.com/rs/zerolog/log"
    27  
    28  	"github.com/mysteriumnetwork/go-openvpn/openvpn"
    29  	"github.com/mysteriumnetwork/go-openvpn/openvpn/middlewares/server/filter"
    30  	"github.com/mysteriumnetwork/go-openvpn/openvpn/middlewares/state"
    31  	"github.com/mysteriumnetwork/go-openvpn/openvpn/tls"
    32  	"github.com/mysteriumnetwork/node/config"
    33  	"github.com/mysteriumnetwork/node/core/ip"
    34  	"github.com/mysteriumnetwork/node/core/node"
    35  	"github.com/mysteriumnetwork/node/core/port"
    36  	"github.com/mysteriumnetwork/node/core/service"
    37  	"github.com/mysteriumnetwork/node/core/shaper"
    38  	"github.com/mysteriumnetwork/node/dns"
    39  	"github.com/mysteriumnetwork/node/eventbus"
    40  	"github.com/mysteriumnetwork/node/firewall"
    41  	"github.com/mysteriumnetwork/node/identity"
    42  	"github.com/mysteriumnetwork/node/market"
    43  	"github.com/mysteriumnetwork/node/nat"
    44  	openvpn_service "github.com/mysteriumnetwork/node/services/openvpn"
    45  	"github.com/mysteriumnetwork/node/session"
    46  	"github.com/mysteriumnetwork/node/utils/netutil"
    47  	"github.com/mysteriumnetwork/node/utils/stringutil"
    48  )
    49  
    50  // ProposalFactory prepares service proposal during runtime
    51  type ProposalFactory func(currentLocation market.Location) market.ServiceProposal
    52  
    53  // Manager represents entrypoint for Openvpn service with top level components
    54  type Manager struct {
    55  	natService      nat.NATService
    56  	ports           port.ServicePortSupplier
    57  	dnsProxy        *dns.Proxy
    58  	bus             eventbus.EventBus
    59  	trafficFirewall firewall.IncomingTrafficFirewall
    60  	vpnNetwork      net.IPNet
    61  	vpnServerPort   int
    62  	openvpnProcess  openvpn.Process
    63  	openvpnClients  *clientMap
    64  	openvpnAuth     *authHandler
    65  	ipResolver      ip.Resolver
    66  	serviceOptions  Options
    67  	nodeOptions     node.Options
    68  
    69  	outboundIP    string
    70  	country       string
    71  	dnsIP         net.IP
    72  	dnsOK         bool
    73  	tlsPrimitives *tls.Primitives
    74  }
    75  
    76  // Serve starts service - does block
    77  func (m *Manager) Serve(instance *service.Instance) (err error) {
    78  	m.vpnNetwork = net.IPNet{
    79  		IP:   net.ParseIP(m.serviceOptions.Subnet),
    80  		Mask: net.IPMask(net.ParseIP(m.serviceOptions.Netmask).To4()),
    81  	}
    82  
    83  	dnsPort := 11153
    84  	dnsHandler, err := dns.ResolveViaSystem()
    85  	if err == nil {
    86  		if instance.PolicyProvider().HasDNSRules() {
    87  			dnsHandler = dns.WhitelistAnswers(dnsHandler, m.trafficFirewall, instance.PolicyProvider())
    88  			removeRule, err := m.trafficFirewall.BlockIncomingTraffic(m.vpnNetwork)
    89  			if err != nil {
    90  				return fmt.Errorf("failed to enable traffic blocking: %w", err)
    91  			}
    92  			defer func() {
    93  				if err := removeRule(); err != nil {
    94  					log.Warn().Err(err).Msg("failed to disable traffic blocking")
    95  				}
    96  			}()
    97  		}
    98  
    99  		m.dnsProxy = dns.NewProxy("", dnsPort, dnsHandler)
   100  		if err := m.dnsProxy.Run(); err != nil {
   101  			log.Warn().Err(err).Msg("Provider DNS will not be available")
   102  		} else {
   103  			m.dnsOK = true
   104  			m.dnsIP = netutil.FirstIP(m.vpnNetwork)
   105  		}
   106  	} else {
   107  		log.Warn().Err(err).Msg("Provider DNS will not be available")
   108  	}
   109  
   110  	servicePort, err := m.ports.Acquire()
   111  	if err != nil {
   112  		return fmt.Errorf("failed to acquire an unused port: %w", err)
   113  	}
   114  	m.vpnServerPort = servicePort.Num()
   115  
   116  	m.outboundIP, err = m.ipResolver.GetOutboundIP()
   117  	if err != nil {
   118  		return fmt.Errorf("could not get outbound IP: %w", err)
   119  	}
   120  
   121  	m.tlsPrimitives, err = primitiveFactory(m.country, instance.ProviderID.Address)
   122  	if err != nil {
   123  		return
   124  	}
   125  
   126  	if err := firewall.AddInboundRule(m.serviceOptions.Protocol, m.vpnServerPort); err != nil {
   127  		return fmt.Errorf("failed to add firewall rule: %w", err)
   128  	}
   129  	defer func() {
   130  		if err := firewall.RemoveInboundRule(m.serviceOptions.Protocol, m.vpnServerPort); err != nil {
   131  			log.Error().Err(err).Msg("Failed to delete firewall rule for OpenVPN")
   132  		}
   133  	}()
   134  
   135  	log.Info().Msgf("Starting OpenVPN server on port: %d", m.vpnServerPort)
   136  	if err := m.startServer(); err != nil {
   137  		return fmt.Errorf("failed to start Openvpn server: %w", err)
   138  	}
   139  
   140  	if _, err := m.natService.Setup(nat.Options{
   141  		VPNNetwork:    m.vpnNetwork,
   142  		ProviderExtIP: net.ParseIP(m.outboundIP),
   143  		DNSIP:         m.dnsIP,
   144  	}); err != nil {
   145  		return fmt.Errorf("failed to setup NAT/firewall rules: %w", err)
   146  	}
   147  
   148  	s := shaper.New(m.bus)
   149  	err = s.Start(m.openvpnProcess.DeviceName())
   150  	if err != nil {
   151  		log.Error().Err(err).Msg("Could not start traffic shaper")
   152  	}
   153  	defer s.Clear(m.openvpnProcess.DeviceName())
   154  
   155  	log.Info().Msg("OpenVPN server waiting")
   156  	return m.openvpnProcess.Wait()
   157  }
   158  
   159  // Stop stops service
   160  func (m *Manager) Stop() error {
   161  	if m.openvpnProcess != nil {
   162  		m.openvpnProcess.Stop()
   163  	}
   164  
   165  	if m.dnsProxy != nil {
   166  		if err := m.dnsProxy.Stop(); err != nil {
   167  			return fmt.Errorf("could not stop DNS proxy: %w", err)
   168  		}
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  // ProvideConfig takes session creation config from end consumer and provides the service configuration to the end consumer
   175  func (m *Manager) ProvideConfig(sessionID string, sessionConfig json.RawMessage, conn *net.UDPConn) (*service.ConfigParams, error) {
   176  	if m.vpnServerPort == 0 {
   177  		return nil, errors.New("service port not initialized")
   178  	}
   179  
   180  	publicIP, err := m.ipResolver.GetPublicIP()
   181  	if err != nil {
   182  		return nil, fmt.Errorf("could not get public IP: %w", err)
   183  	}
   184  
   185  	serverIP := vpnServerIP(m.outboundIP, publicIP, m.nodeOptions.OptionsNetwork.Network.IsLocalnet())
   186  	vpnConfig := &openvpn_service.VPNConfig{
   187  		RemoteIP:        serverIP,
   188  		RemotePort:      m.vpnServerPort,
   189  		RemoteProtocol:  m.serviceOptions.Protocol,
   190  		TLSPresharedKey: m.tlsPrimitives.PresharedKey.ToPEMFormat(),
   191  		CACertificate:   m.tlsPrimitives.CertificateAuthority.ToPEMFormat(),
   192  	}
   193  	if m.dnsOK {
   194  		vpnConfig.DNSIPs = m.dnsIP.String()
   195  	}
   196  
   197  	if err := proxyOpenVPN(conn, m.vpnServerPort); err != nil {
   198  		return nil, fmt.Errorf("could not proxy connection to OpenVPN server: %w", err)
   199  	}
   200  
   201  	destroy := func() {
   202  		log.Info().Msgf("Cleaning up session %s", sessionID)
   203  
   204  		sessionClients := m.openvpnClients.GetSessionClients(session.ID(sessionID))
   205  		for clientID := range sessionClients {
   206  			if err := m.openvpnAuth.ClientKill(clientID); err != nil {
   207  				log.Error().Err(err).Msgf("Cleaning up session %s failed. Error disconnecting Openvpn client %d", sessionID, clientID)
   208  			}
   209  		}
   210  	}
   211  
   212  	return &service.ConfigParams{SessionServiceConfig: vpnConfig, SessionDestroyCallback: destroy}, nil
   213  }
   214  
   215  func (m *Manager) startServer() error {
   216  	vpnServerConfig := NewServerConfig(
   217  		m.nodeOptions.Directories.Runtime,
   218  		m.nodeOptions.Directories.Script,
   219  		m.serviceOptions.Subnet,
   220  		m.serviceOptions.Netmask,
   221  		m.tlsPrimitives,
   222  		m.nodeOptions.BindAddress,
   223  		m.vpnServerPort,
   224  		m.serviceOptions.Protocol,
   225  	)
   226  
   227  	openvpnFilterDeny := stringutil.Split(config.GetString(config.FlagFirewallProtectedNetworks), ',')
   228  	var openvpnFilterAllow []string
   229  	if m.dnsOK {
   230  		openvpnFilterAllow = []string{m.dnsIP.String()}
   231  	}
   232  
   233  	stateChannel := make(chan openvpn.State, 10)
   234  	m.openvpnAuth = newAuthHandler(m.openvpnClients, identity.NewExtractor())
   235  	m.openvpnProcess = openvpn.CreateNewProcess(
   236  		m.nodeOptions.Openvpn.BinaryPath(),
   237  		vpnServerConfig.GenericConfig,
   238  		filter.NewMiddleware(openvpnFilterAllow, openvpnFilterDeny),
   239  		m.openvpnAuth,
   240  		state.NewMiddleware(func(state openvpn.State) {
   241  			stateChannel <- state
   242  			// this is the last state - close channel (according to best practices of go - channel writer controls channel)
   243  			if state == openvpn.ProcessExited {
   244  				close(stateChannel)
   245  			}
   246  		}),
   247  		newStatsPublisher(m.openvpnClients, m.bus, 1),
   248  	)
   249  	if err := m.openvpnProcess.Start(); err != nil {
   250  		return err
   251  	}
   252  
   253  	// Wait for started state
   254  	for {
   255  		state, more := <-stateChannel
   256  		if !more {
   257  			return errors.New("process failed to start")
   258  		}
   259  		if state == openvpn.ConnectedState {
   260  			break
   261  		}
   262  	}
   263  
   264  	// Consume server states
   265  	go func() {
   266  		for state := range stateChannel {
   267  			switch state {
   268  			case openvpn.ProcessStarted:
   269  				log.Info().Msg("OpenVPN service booting up")
   270  			case openvpn.ProcessExited:
   271  				log.Info().Msg("OpenVPN service exited")
   272  			}
   273  		}
   274  	}()
   275  
   276  	log.Info().Msg("OpenVPN service started successfully")
   277  	return nil
   278  }