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 }