github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/p2p/dialer.go (about)

     1  /*
     2   * Copyright (C) 2020 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 p2p
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"net"
    25  	"sync"
    26  	"time"
    27  
    28  	nats_lib "github.com/nats-io/nats.go"
    29  	"github.com/rs/zerolog/log"
    30  	"google.golang.org/protobuf/proto"
    31  
    32  	"github.com/mysteriumnetwork/node/communication/nats"
    33  	"github.com/mysteriumnetwork/node/core/ip"
    34  	"github.com/mysteriumnetwork/node/core/port"
    35  	"github.com/mysteriumnetwork/node/eventbus"
    36  	"github.com/mysteriumnetwork/node/firewall"
    37  	"github.com/mysteriumnetwork/node/identity"
    38  	"github.com/mysteriumnetwork/node/nat/traversal"
    39  	"github.com/mysteriumnetwork/node/p2p/compat"
    40  	"github.com/mysteriumnetwork/node/pb"
    41  	"github.com/mysteriumnetwork/node/router"
    42  	"github.com/mysteriumnetwork/node/trace"
    43  )
    44  
    45  const maxBrokerConnectAttempts = 25
    46  
    47  // Dialer knows how to exchange p2p keys and encrypted configuration and creates ready to use p2p channels.
    48  type Dialer interface {
    49  	// Dial exchanges p2p configuration via broker, performs NAT pinging if needed
    50  	// and create p2p channel which is ready for communication.
    51  	Dial(ctx context.Context, consumerID, providerID identity.Identity, serviceType string, contactDef ContactDefinition, tracer *trace.Tracer) (Channel, error)
    52  }
    53  
    54  // NewDialer creates new p2p communication dialer which is used on consumer side.
    55  func NewDialer(broker brokerConnector, signer identity.SignerFactory, verifierFactory identity.VerifierFactory, ipResolver ip.Resolver, portPool port.ServicePortSupplier, eventBus eventbus.EventBus) Dialer {
    56  	return &dialer{
    57  		broker:          broker,
    58  		ipResolver:      ipResolver,
    59  		signer:          signer,
    60  		verifierFactory: verifierFactory,
    61  		portPool:        portPool,
    62  		consumerPinger:  traversal.NewPinger(traversal.DefaultPingConfig(), eventbus.New()),
    63  		eventBus:        eventBus,
    64  	}
    65  }
    66  
    67  // dialer implements Dialer interface.
    68  type dialer struct {
    69  	portPool        port.ServicePortSupplier
    70  	broker          brokerConnector
    71  	consumerPinger  natConsumerPinger
    72  	signer          identity.SignerFactory
    73  	verifierFactory identity.VerifierFactory
    74  	ipResolver      ip.Resolver
    75  	eventBus        eventbus.EventBus
    76  }
    77  
    78  // Dial exchanges p2p configuration via broker, performs NAT pinging if needed
    79  // and create p2p channel which is ready for communication.
    80  func (m *dialer) Dial(ctx context.Context, consumerID, providerID identity.Identity, serviceType string, contactDef ContactDefinition, tracer *trace.Tracer) (Channel, error) {
    81  	config := &p2pConnectConfig{tracer: tracer}
    82  
    83  	// Send initial exchange with signed consumer public key.
    84  	brokerConn, err := m.connect(contactDef, tracer)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("could not open broker conn: %w", err)
    87  	}
    88  	defer brokerConn.Close()
    89  
    90  	peerReady := make(chan struct{})
    91  	var once sync.Once
    92  	_, err = brokerConn.Subscribe(channelHandlersReadySubject(providerID, serviceType), func(msg *nats_lib.Msg) {
    93  		defer once.Do(func() { close(peerReady) })
    94  		if err := m.channelHandlersReady(msg); err != nil {
    95  			log.Err(err).Msg("Channel handlers ready handler setup failed")
    96  			return
    97  		}
    98  	})
    99  	if err != nil {
   100  		return nil, fmt.Errorf("could not subscribe to ready subject: %w", err)
   101  	}
   102  
   103  	config, err = m.startConfigExchange(config, ctx, brokerConn, providerID, serviceType, consumerID)
   104  	if err != nil {
   105  		return nil, fmt.Errorf("could not exchange config: %w", err)
   106  	}
   107  
   108  	if config.compatibility < 2 {
   109  		return nil, fmt.Errorf("peer using compatibility version lower than 2: %d", config.compatibility)
   110  	}
   111  
   112  	if serviceType != "openvpn" { // OpenVPN does this automatically, we don't need to perform it manually.
   113  		if err := router.ExcludeIP(net.ParseIP(config.peerIP())); err != nil {
   114  			return nil, fmt.Errorf("failed to exclude peer IP from default routes: %w", err)
   115  		}
   116  	}
   117  
   118  	if _, err := firewall.AllowIPAccess(config.peerPublicIP); err != nil {
   119  		return nil, fmt.Errorf("could not add peer IP firewall rule: %w", err)
   120  	}
   121  
   122  	config.publicIP, config.localPorts, err = m.prepareLocalPorts(config)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("could not prepare ports: %w", err)
   125  	}
   126  
   127  	config.publicPorts = stunPorts(consumerID, m.eventBus, config.localPorts...)
   128  
   129  	// Finally send consumer encrypted and signed connect config in ack message.
   130  	err = m.ackConfigExchange(config, ctx, brokerConn, providerID, serviceType, consumerID)
   131  	if err != nil {
   132  		return nil, fmt.Errorf("could not ack config: %w", err)
   133  	}
   134  
   135  	dial := m.dialPinger
   136  	if len(config.peerPorts) == requiredConnCount {
   137  		dial = m.dialDirect
   138  	}
   139  	conn1, conn2, err := dial(ctx, providerID, config)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("could not dial p2p channel: %w", err)
   142  	}
   143  
   144  	// Wait until provider confirms that channel handlers are ready.
   145  	traceAck := config.tracer.StartStage("Consumer P2P dial ack")
   146  	select {
   147  	case <-peerReady:
   148  		log.Debug().Msg("Received handlers ready message from provider")
   149  	case <-ctx.Done():
   150  		return nil, errors.New("timeout while performing configuration exchange")
   151  	}
   152  
   153  	channel, err := newChannel(conn1, config.privateKey, config.peerPubKey, config.compatibility)
   154  	if err != nil {
   155  		return nil, fmt.Errorf("could not create p2p channel during dial: %w", err)
   156  	}
   157  	channel.setTracer(tracer)
   158  	channel.setServiceConn(conn2)
   159  	channel.setPeerID(providerID)
   160  	channel.launchReadSendLoops()
   161  	config.tracer.EndStage(traceAck)
   162  
   163  	return channel, nil
   164  }
   165  
   166  func (m *dialer) connect(contactDef ContactDefinition, tracer *trace.Tracer) (conn nats.Connection, err error) {
   167  	trace := tracer.StartStage("Consumer P2P connect")
   168  	defer tracer.EndStage(trace)
   169  
   170  	// broker connect might fail due to reconfiguration of network routes in progress
   171  	for i := 0; i < maxBrokerConnectAttempts; i++ {
   172  		serverURLs, err := nats.ParseServerURIs(contactDef.BrokerAddresses)
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  
   177  		conn, err = m.broker.Connect(serverURLs...)
   178  		if err != nil {
   179  			log.Warn().Msgf("broker connect failed - attempting again in 1sec: %s", err)
   180  			time.Sleep(time.Second)
   181  			continue
   182  		}
   183  		break
   184  	}
   185  	return conn, err
   186  }
   187  
   188  func (m *dialer) startConfigExchange(config *p2pConnectConfig, ctx context.Context, brokerConn nats.Connection, providerID identity.Identity, serviceType string, consumerID identity.Identity) (*p2pConnectConfig, error) {
   189  	trace := config.tracer.StartStage("Consumer P2P exchange")
   190  	defer config.tracer.EndStage(trace)
   191  
   192  	pubKey, privateKey, err := GenerateKey()
   193  	if err != nil {
   194  		return nil, fmt.Errorf("could not generate consumer p2p keys: %w", err)
   195  	}
   196  
   197  	beginExchangeMsg := &pb.P2PConfigExchangeMsg{
   198  		PublicKey: pubKey.Hex(),
   199  	}
   200  	log.Debug().Msgf("Consumer %s sending public key %s to provider %s", consumerID.Address, beginExchangeMsg.PublicKey, providerID.Address)
   201  	packedMsg, err := packSignedMsg(m.signer, consumerID, beginExchangeMsg)
   202  	if err != nil {
   203  		return nil, fmt.Errorf("could not pack signed message: %v", err)
   204  	}
   205  	exchangeMsgBrokerReply, err := m.sendSignedMsg(ctx, configExchangeSubject(providerID, serviceType), packedMsg, brokerConn)
   206  	if err != nil {
   207  		return nil, fmt.Errorf("could not send signed message: %w", err)
   208  	}
   209  
   210  	// Parse provider response with public key and encrypted and signed connection config.
   211  	exchangeMsgReplySignedMsg, _, err := unpackSignedMsg(m.verifierFactory(providerID), exchangeMsgBrokerReply)
   212  	if err != nil {
   213  		return nil, fmt.Errorf("could not unpack peer signed message: %w", err)
   214  	}
   215  	var exchangeMsgReply pb.P2PConfigExchangeMsg
   216  	if err := proto.Unmarshal(exchangeMsgReplySignedMsg.Data, &exchangeMsgReply); err != nil {
   217  		return nil, fmt.Errorf("could not unmarshal peer signed message payload: %w", err)
   218  	}
   219  	peerPubKey, err := DecodePublicKey(exchangeMsgReply.PublicKey)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	peerConnConfig, err := decryptConnConfigMsg(exchangeMsgReply.ConfigCiphertext, privateKey, peerPubKey)
   224  	if err != nil {
   225  		return nil, fmt.Errorf("could not decrypt peer conn config: %w", err)
   226  	}
   227  
   228  	config.publicKey = pubKey
   229  	config.compatibility = int(peerConnConfig.Compatibility)
   230  	config.privateKey = privateKey
   231  	config.peerPubKey = peerPubKey
   232  	config.peerPublicIP = peerConnConfig.PublicIP
   233  	config.peerPorts = int32ToIntSlice(peerConnConfig.Ports)
   234  	return config, nil
   235  }
   236  
   237  func (m *dialer) ackConfigExchange(config *p2pConnectConfig, ctx context.Context, brokerConn nats.Connection, providerID identity.Identity, serviceType string, consumerID identity.Identity) error {
   238  	trace := config.tracer.StartStage("Consumer P2P exchange ack")
   239  	defer config.tracer.EndStage(trace)
   240  
   241  	connConfig := &pb.P2PConnectConfig{
   242  		PublicIP:      config.publicIP,
   243  		Ports:         intToInt32Slice(config.publicPorts),
   244  		Compatibility: compat.Compatibility,
   245  	}
   246  	connConfigCiphertext, err := encryptConnConfigMsg(connConfig, config.privateKey, config.peerPubKey)
   247  	if err != nil {
   248  		return fmt.Errorf("could not encrypt config msg: %v", err)
   249  	}
   250  	endExchangeMsg := &pb.P2PConfigExchangeMsg{
   251  		PublicKey:        config.publicKey.Hex(),
   252  		ConfigCiphertext: connConfigCiphertext,
   253  	}
   254  	log.Debug().Msgf("Consumer %s sending ack with encrypted config to provider %s", consumerID.Address, providerID.Address)
   255  	packedMsg, err := packSignedMsg(m.signer, consumerID, endExchangeMsg)
   256  	if err != nil {
   257  		return fmt.Errorf("could not pack signed message: %v", err)
   258  	}
   259  
   260  	// simple broker Publish will not work here since we have to delay Consumer from pinging Provider
   261  	//  until provider receives consumer config ( IP, ports ) and starts pinging Consumer first.
   262  	// This is why we use broker Request method to be sure that Provider processed our given configuration.
   263  	// To improve speed here investigate options to reduce broker communication round trip.
   264  	_, err = m.sendSignedMsg(ctx, configExchangeACKSubject(providerID, serviceType), packedMsg, brokerConn)
   265  
   266  	if err != nil {
   267  		return fmt.Errorf("could not send signed msg: %v", err)
   268  	}
   269  
   270  	return nil
   271  }
   272  
   273  func (m *dialer) prepareLocalPorts(config *p2pConnectConfig) (string, []int, error) {
   274  	trace := config.tracer.StartStage("Consumer P2P exchange (ports)")
   275  	defer config.tracer.EndStage(trace)
   276  
   277  	// Finally send consumer encrypted and signed connect config in ack message.
   278  	publicIP, err := m.ipResolver.GetPublicIP()
   279  	if err != nil {
   280  		return "", nil, fmt.Errorf("could not get public IP: %v", err)
   281  	}
   282  
   283  	localPorts, err := acquireLocalPorts(m.portPool, len(config.peerPorts))
   284  	if err != nil {
   285  		return publicIP, nil, fmt.Errorf("could not acquire local ports: %v", err)
   286  	}
   287  
   288  	return publicIP, localPorts, nil
   289  }
   290  
   291  func (m *dialer) dialDirect(ctx context.Context, providerID identity.Identity, config *p2pConnectConfig) (*net.UDPConn, *net.UDPConn, error) {
   292  	trace := config.tracer.StartStage("Consumer P2P dial (upnp)")
   293  	defer config.tracer.EndStage(trace)
   294  
   295  	log.Debug().Msg("Skipping provider ping")
   296  
   297  	ip := defaultInterfaceAddress()
   298  	conn1, err := net.DialUDP("udp4", &net.UDPAddr{IP: net.ParseIP(ip), Port: config.localPorts[0]}, &net.UDPAddr{IP: net.ParseIP(config.peerIP()), Port: config.peerPorts[0]})
   299  	if err != nil {
   300  		return nil, nil, fmt.Errorf("could not create UDP conn for p2p channel: %w", err)
   301  	}
   302  	conn2, err := net.DialUDP("udp4", &net.UDPAddr{IP: net.ParseIP(ip), Port: config.localPorts[1]}, &net.UDPAddr{IP: net.ParseIP(config.peerIP()), Port: config.peerPorts[1]})
   303  	if err != nil {
   304  		return nil, nil, fmt.Errorf("could not create UDP conn for service: %w", err)
   305  	}
   306  
   307  	if err := router.ProtectUDPConn(conn1); err != nil {
   308  		return nil, nil, fmt.Errorf("failed to protect udp connection: %w", err)
   309  	}
   310  
   311  	if err := router.ProtectUDPConn(conn2); err != nil {
   312  		return nil, nil, fmt.Errorf("failed to protect udp connection: %w", err)
   313  	}
   314  
   315  	return conn1, conn2, err
   316  }
   317  
   318  func (m *dialer) dialPinger(ctx context.Context, providerID identity.Identity, config *p2pConnectConfig) (*net.UDPConn, *net.UDPConn, error) {
   319  	trace := config.tracer.StartStage("Consumer P2P dial (pinger)")
   320  	defer config.tracer.EndStage(trace)
   321  
   322  	if _, err := firewall.AllowIPAccess(config.peerPublicIP); err != nil {
   323  		return nil, nil, fmt.Errorf("could not add peer IP firewall rule: %w", err)
   324  	}
   325  
   326  	ip := defaultInterfaceAddress()
   327  	log.Debug().Msgf("Pinging provider %s  using ports %v:%v", providerID.Address, config.localPorts, config.peerPorts)
   328  	conns, err := m.consumerPinger.PingProviderPeer(ctx, ip, config.peerIP(), config.localPorts, config.peerPorts, consumerInitialTTL, requiredConnCount)
   329  	if err != nil {
   330  		return nil, nil, fmt.Errorf("could not ping peer: %w", err)
   331  	}
   332  	return conns[0], conns[1], nil
   333  }
   334  
   335  func (m *dialer) sendSignedMsg(ctx context.Context, subject string, msg []byte, brokerConn nats.Connection) ([]byte, error) {
   336  	reply, err := brokerConn.RequestWithContext(ctx, subject, msg)
   337  	if err != nil {
   338  		return nil, fmt.Errorf("could not send broker request to subject %s: %v", subject, err)
   339  	}
   340  	return reply.Data, nil
   341  }
   342  
   343  func (m *dialer) channelHandlersReady(msg *nats_lib.Msg) error {
   344  	var handlersReady pb.P2PChannelHandlersReady
   345  	if err := proto.Unmarshal(msg.Data, &handlersReady); err != nil {
   346  		return fmt.Errorf("failed to unmarshal handlers ready message: %w", err)
   347  	}
   348  	if handlersReady.Value != "HANDLERS READY" {
   349  		return errors.New("incorrect handlers ready message value")
   350  	}
   351  
   352  	return nil
   353  }