github.com/Finschia/ostracon@v1.1.5/p2p/transport.go (about) 1 package p2p 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "time" 8 9 "golang.org/x/net/netutil" 10 11 "github.com/gogo/protobuf/proto" 12 tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p" 13 14 "github.com/Finschia/ostracon/crypto" 15 "github.com/Finschia/ostracon/libs/protoio" 16 "github.com/Finschia/ostracon/p2p/conn" 17 ) 18 19 const ( 20 defaultDialTimeout = time.Second 21 defaultFilterTimeout = 5 * time.Second 22 defaultHandshakeTimeout = 3 * time.Second 23 ) 24 25 // IPResolver is a behaviour subset of net.Resolver. 26 type IPResolver interface { 27 LookupIPAddr(context.Context, string) ([]net.IPAddr, error) 28 } 29 30 // accept is the container to carry the upgraded connection and NodeInfo from an 31 // asynchronously running routine to the Accept method. 32 type accept struct { 33 netAddr *NetAddress 34 conn net.Conn 35 nodeInfo NodeInfo 36 err error 37 } 38 39 // peerConfig is used to bundle data we need to fully setup a Peer with an 40 // MConn, provided by the caller of Accept and Dial (currently the Switch). This 41 // a temporary measure until reactor setup is less dynamic and we introduce the 42 // concept of PeerBehaviour to communicate about significant Peer lifecycle 43 // events. 44 // TODO(xla): Refactor out with more static Reactor setup and PeerBehaviour. 45 type peerConfig struct { 46 chDescs []*conn.ChannelDescriptor 47 onPeerError func(Peer, interface{}) 48 outbound bool 49 // isPersistent allows you to set a function, which, given socket address 50 // (for outbound peers) OR self-reported address (for inbound peers), tells 51 // if the peer is persistent or not. 52 isPersistent func(*NetAddress) bool 53 reactorsByCh map[byte]Reactor 54 msgTypeByChID map[byte]proto.Message 55 metrics *Metrics 56 mlc *metricsLabelCache 57 } 58 59 // Transport emits and connects to Peers. The implementation of Peer is left to 60 // the transport. Each transport is also responsible to filter establishing 61 // peers specific to its domain. 62 type Transport interface { 63 // Listening address. 64 NetAddress() NetAddress 65 66 // Accept returns a newly connected Peer. 67 Accept(peerConfig) (Peer, error) 68 69 // Dial connects to the Peer for the address. 70 Dial(NetAddress, peerConfig) (Peer, error) 71 72 // Cleanup any resources associated with Peer. 73 Cleanup(Peer) 74 } 75 76 // transportLifecycle bundles the methods for callers to control start and stop 77 // behaviour. 78 type transportLifecycle interface { 79 Close() error 80 Listen(NetAddress) error 81 } 82 83 // ConnFilterFunc to be implemented by filter hooks after a new connection has 84 // been established. The set of exisiting connections is passed along together 85 // with all resolved IPs for the new connection. 86 type ConnFilterFunc func(ConnSet, net.Conn, []net.IP) error 87 88 // ConnDuplicateIPFilter resolves and keeps all ips for an incoming connection 89 // and refuses new ones if they come from a known ip. 90 func ConnDuplicateIPFilter() ConnFilterFunc { 91 return func(cs ConnSet, c net.Conn, ips []net.IP) error { 92 for _, ip := range ips { 93 if cs.HasIP(ip) { 94 return ErrRejected{ 95 conn: c, 96 err: fmt.Errorf("ip<%v> already connected", ip), 97 isDuplicate: true, 98 } 99 } 100 } 101 102 return nil 103 } 104 } 105 106 // MultiplexTransportOption sets an optional parameter on the 107 // MultiplexTransport. 108 type MultiplexTransportOption func(*MultiplexTransport) 109 110 // MultiplexTransportConnFilters sets the filters for rejection new connections. 111 func MultiplexTransportConnFilters( 112 filters ...ConnFilterFunc, 113 ) MultiplexTransportOption { 114 return func(mt *MultiplexTransport) { mt.connFilters = filters } 115 } 116 117 // MultiplexTransportFilterTimeout sets the timeout waited for filter calls to 118 // return. 119 func MultiplexTransportFilterTimeout( 120 timeout time.Duration, 121 ) MultiplexTransportOption { 122 return func(mt *MultiplexTransport) { mt.filterTimeout = timeout } 123 } 124 125 // MultiplexTransportResolver sets the Resolver used for ip lokkups, defaults to 126 // net.DefaultResolver. 127 func MultiplexTransportResolver(resolver IPResolver) MultiplexTransportOption { 128 return func(mt *MultiplexTransport) { mt.resolver = resolver } 129 } 130 131 // MultiplexTransportMaxIncomingConnections sets the maximum number of 132 // simultaneous connections (incoming). Default: 0 (unlimited) 133 func MultiplexTransportMaxIncomingConnections(n int) MultiplexTransportOption { 134 return func(mt *MultiplexTransport) { mt.maxIncomingConnections = n } 135 } 136 137 // MultiplexTransport accepts and dials tcp connections and upgrades them to 138 // multiplexed peers. 139 type MultiplexTransport struct { 140 netAddr NetAddress 141 listener net.Listener 142 maxIncomingConnections int // see MaxIncomingConnections 143 144 acceptc chan accept 145 closec chan struct{} 146 147 // Lookup table for duplicate ip and id checks. 148 conns ConnSet 149 connFilters []ConnFilterFunc 150 151 dialTimeout time.Duration 152 filterTimeout time.Duration 153 handshakeTimeout time.Duration 154 nodeInfo NodeInfo 155 nodeKey NodeKey 156 resolver IPResolver 157 158 // TODO(xla): This config is still needed as we parameterise peerConn and 159 // peer currently. All relevant configuration should be refactored into options 160 // with sane defaults. 161 mConfig conn.MConnConfig 162 } 163 164 // Test multiplexTransport for interface completeness. 165 var _ Transport = (*MultiplexTransport)(nil) 166 var _ transportLifecycle = (*MultiplexTransport)(nil) 167 168 // NewMultiplexTransport returns a tcp connected multiplexed peer. 169 func NewMultiplexTransport( 170 nodeInfo NodeInfo, 171 nodeKey NodeKey, 172 mConfig conn.MConnConfig, 173 ) *MultiplexTransport { 174 return &MultiplexTransport{ 175 acceptc: make(chan accept), 176 closec: make(chan struct{}), 177 dialTimeout: defaultDialTimeout, 178 filterTimeout: defaultFilterTimeout, 179 handshakeTimeout: defaultHandshakeTimeout, 180 mConfig: mConfig, 181 nodeInfo: nodeInfo, 182 nodeKey: nodeKey, 183 conns: NewConnSet(), 184 resolver: net.DefaultResolver, 185 } 186 } 187 188 // NetAddress implements Transport. 189 func (mt *MultiplexTransport) NetAddress() NetAddress { 190 return mt.netAddr 191 } 192 193 // Accept implements Transport. 194 func (mt *MultiplexTransport) Accept(cfg peerConfig) (Peer, error) { 195 select { 196 // This case should never have any side-effectful/blocking operations to 197 // ensure that quality peers are ready to be used. 198 case a := <-mt.acceptc: 199 if a.err != nil { 200 return nil, a.err 201 } 202 203 cfg.outbound = false 204 205 return mt.wrapPeer(a.conn, a.nodeInfo, cfg, a.netAddr), nil 206 case <-mt.closec: 207 return nil, ErrTransportClosed{} 208 } 209 } 210 211 // Dial implements Transport. 212 func (mt *MultiplexTransport) Dial( 213 addr NetAddress, 214 cfg peerConfig, 215 ) (Peer, error) { 216 c, err := addr.DialTimeout(mt.dialTimeout) 217 if err != nil { 218 return nil, err 219 } 220 221 // TODO(xla): Evaluate if we should apply filters if we explicitly dial. 222 if err := mt.filterConn(c); err != nil { 223 return nil, err 224 } 225 226 secretConn, nodeInfo, err := mt.upgrade(c, &addr) 227 if err != nil { 228 return nil, err 229 } 230 231 cfg.outbound = true 232 233 p := mt.wrapPeer(secretConn, nodeInfo, cfg, &addr) 234 235 return p, nil 236 } 237 238 // Close implements transportLifecycle. 239 func (mt *MultiplexTransport) Close() error { 240 close(mt.closec) 241 242 if mt.listener != nil { 243 return mt.listener.Close() 244 } 245 246 return nil 247 } 248 249 // Listen implements transportLifecycle. 250 func (mt *MultiplexTransport) Listen(addr NetAddress) error { 251 ln, err := net.Listen("tcp", addr.DialString()) 252 if err != nil { 253 return err 254 } 255 256 if mt.maxIncomingConnections > 0 { 257 ln = netutil.LimitListener(ln, mt.maxIncomingConnections) 258 } 259 260 mt.netAddr = addr 261 mt.listener = ln 262 263 go mt.acceptPeers() 264 265 return nil 266 } 267 268 // AddChannel registers a channel to nodeInfo. 269 // NOTE: NodeInfo must be of type DefaultNodeInfo else channels won't be updated 270 // This is a bit messy at the moment but is cleaned up in the following version 271 // when NodeInfo changes from an interface to a concrete type 272 func (mt *MultiplexTransport) AddChannel(chID byte) error { 273 ni, ok := mt.nodeInfo.(DefaultNodeInfo) 274 if !ok { 275 return fmt.Errorf("nodeInfo type: %T is not supported", mt.nodeInfo) 276 } 277 if !ni.HasChannel(chID) { 278 ni.Channels = append(ni.Channels, chID) 279 } 280 mt.nodeInfo = ni 281 return nil 282 } 283 284 func (mt *MultiplexTransport) acceptPeers() { 285 for { 286 c, err := mt.listener.Accept() 287 if err != nil { 288 // If Close() has been called, silently exit. 289 select { 290 case _, ok := <-mt.closec: 291 if !ok { 292 return 293 } 294 default: 295 // Transport is not closed 296 } 297 298 mt.acceptc <- accept{err: err} 299 return 300 } 301 302 // Connection upgrade and filtering should be asynchronous to avoid 303 // Head-of-line blocking[0]. 304 // Reference: https://github.com/tendermint/tendermint/issues/2047 305 // 306 // [0] https://en.wikipedia.org/wiki/Head-of-line_blocking 307 go func(c net.Conn) { 308 defer func() { 309 if r := recover(); r != nil { 310 err := ErrRejected{ 311 conn: c, 312 err: fmt.Errorf("recovered from panic: %v", r), 313 isAuthFailure: true, 314 } 315 select { 316 case mt.acceptc <- accept{err: err}: 317 case <-mt.closec: 318 // Give up if the transport was closed. 319 _ = c.Close() 320 return 321 } 322 } 323 }() 324 325 var ( 326 nodeInfo NodeInfo 327 secretConn *conn.SecretConnection 328 netAddr *NetAddress 329 ) 330 331 err := mt.filterConn(c) 332 if err == nil { 333 secretConn, nodeInfo, err = mt.upgrade(c, nil) 334 if err == nil { 335 addr := c.RemoteAddr() 336 id := PubKeyToID(secretConn.RemotePubKey()) 337 netAddr = NewNetAddress(id, addr) 338 } 339 } 340 341 select { 342 case mt.acceptc <- accept{netAddr, secretConn, nodeInfo, err}: 343 // Make the upgraded peer available. 344 case <-mt.closec: 345 // Give up if the transport was closed. 346 _ = c.Close() 347 return 348 } 349 }(c) 350 } 351 } 352 353 // Cleanup removes the given address from the connections set and 354 // closes the connection. 355 func (mt *MultiplexTransport) Cleanup(p Peer) { 356 mt.conns.RemoveAddr(p.RemoteAddr()) 357 _ = p.CloseConn() 358 } 359 360 func (mt *MultiplexTransport) cleanup(c net.Conn) error { 361 mt.conns.Remove(c) 362 363 return c.Close() 364 } 365 366 func (mt *MultiplexTransport) filterConn(c net.Conn) (err error) { 367 defer func() { 368 if err != nil { 369 _ = c.Close() 370 } 371 }() 372 373 // Reject if connection is already present. 374 if mt.conns.Has(c) { 375 return ErrRejected{conn: c, isDuplicate: true} 376 } 377 378 // Resolve ips for incoming conn. 379 ips, err := resolveIPs(mt.resolver, c) 380 if err != nil { 381 return err 382 } 383 384 errc := make(chan error, len(mt.connFilters)) 385 386 for _, f := range mt.connFilters { 387 go func(f ConnFilterFunc, c net.Conn, ips []net.IP, errc chan<- error) { 388 errc <- f(mt.conns, c, ips) 389 }(f, c, ips, errc) 390 } 391 392 for i := 0; i < cap(errc); i++ { 393 select { 394 case err := <-errc: 395 if err != nil { 396 return ErrRejected{conn: c, err: err, isFiltered: true} 397 } 398 case <-time.After(mt.filterTimeout): 399 return ErrFilterTimeout{} 400 } 401 402 } 403 404 mt.conns.Set(c, ips) 405 406 return nil 407 } 408 409 func (mt *MultiplexTransport) upgrade( 410 c net.Conn, 411 dialedAddr *NetAddress, 412 ) (secretConn *conn.SecretConnection, nodeInfo NodeInfo, err error) { 413 defer func() { 414 if err != nil { 415 _ = mt.cleanup(c) 416 } 417 }() 418 419 secretConn, err = upgradeSecretConn(c, mt.handshakeTimeout, mt.nodeKey.PrivKey) 420 if err != nil { 421 return nil, nil, ErrRejected{ 422 conn: c, 423 err: fmt.Errorf("secret conn failed: %v", err), 424 isAuthFailure: true, 425 } 426 } 427 428 // For outgoing conns, ensure connection key matches dialed key. 429 connID := PubKeyToID(secretConn.RemotePubKey()) 430 if dialedAddr != nil { 431 if dialedID := dialedAddr.ID; connID != dialedID { 432 return nil, nil, ErrRejected{ 433 conn: c, 434 id: connID, 435 err: fmt.Errorf( 436 "conn.ID (%v) dialed ID (%v) mismatch", 437 connID, 438 dialedID, 439 ), 440 isAuthFailure: true, 441 } 442 } 443 } 444 445 nodeInfo, err = handshake(secretConn, mt.handshakeTimeout, mt.nodeInfo) 446 if err != nil { 447 return nil, nil, ErrRejected{ 448 conn: c, 449 err: fmt.Errorf("handshake failed: %v", err), 450 isAuthFailure: true, 451 } 452 } 453 454 if err := nodeInfo.Validate(); err != nil { 455 return nil, nil, ErrRejected{ 456 conn: c, 457 err: err, 458 isNodeInfoInvalid: true, 459 } 460 } 461 462 // Ensure connection key matches self reported key. 463 if connID != nodeInfo.ID() { 464 return nil, nil, ErrRejected{ 465 conn: c, 466 id: connID, 467 err: fmt.Errorf( 468 "conn.ID (%v) NodeInfo.ID (%v) mismatch", 469 connID, 470 nodeInfo.ID(), 471 ), 472 isAuthFailure: true, 473 } 474 } 475 476 // Reject self. 477 if mt.nodeInfo.ID() == nodeInfo.ID() { 478 return nil, nil, ErrRejected{ 479 addr: *NewNetAddress(nodeInfo.ID(), c.RemoteAddr()), 480 conn: c, 481 id: nodeInfo.ID(), 482 isSelf: true, 483 } 484 } 485 486 if err := mt.nodeInfo.CompatibleWith(nodeInfo); err != nil { 487 return nil, nil, ErrRejected{ 488 conn: c, 489 err: err, 490 id: nodeInfo.ID(), 491 isIncompatible: true, 492 } 493 } 494 495 return secretConn, nodeInfo, nil 496 } 497 498 func (mt *MultiplexTransport) wrapPeer( 499 c net.Conn, 500 ni NodeInfo, 501 cfg peerConfig, 502 socketAddr *NetAddress, 503 ) Peer { 504 505 persistent := false 506 if cfg.isPersistent != nil { 507 if cfg.outbound { 508 persistent = cfg.isPersistent(socketAddr) 509 } else { 510 selfReportedAddr, err := ni.NetAddress() 511 if err == nil { 512 persistent = cfg.isPersistent(selfReportedAddr) 513 } 514 } 515 } 516 517 peerConn := newPeerConn( 518 cfg.outbound, 519 persistent, 520 c, 521 socketAddr, 522 ) 523 524 p := newPeer( 525 peerConn, 526 mt.mConfig, 527 ni, 528 cfg.reactorsByCh, 529 cfg.msgTypeByChID, 530 cfg.chDescs, 531 cfg.onPeerError, 532 cfg.mlc, 533 PeerMetrics(cfg.metrics), 534 ) 535 536 return p 537 } 538 539 func handshake( 540 c net.Conn, 541 timeout time.Duration, 542 nodeInfo NodeInfo, 543 ) (NodeInfo, error) { 544 if err := c.SetDeadline(time.Now().Add(timeout)); err != nil { 545 return nil, err 546 } 547 548 var ( 549 errc = make(chan error, 2) 550 551 pbpeerNodeInfo tmp2p.DefaultNodeInfo 552 peerNodeInfo DefaultNodeInfo 553 ourNodeInfo = nodeInfo.(DefaultNodeInfo) 554 ) 555 556 go func(errc chan<- error, c net.Conn) { 557 _, err := protoio.NewDelimitedWriter(c).WriteMsg(ourNodeInfo.ToProto()) 558 errc <- err 559 }(errc, c) 560 go func(errc chan<- error, c net.Conn) { 561 protoReader := protoio.NewDelimitedReader(c, MaxNodeInfoSize()) 562 _, err := protoReader.ReadMsg(&pbpeerNodeInfo) 563 errc <- err 564 }(errc, c) 565 566 for i := 0; i < cap(errc); i++ { 567 err := <-errc 568 if err != nil { 569 return nil, err 570 } 571 } 572 573 peerNodeInfo, err := DefaultNodeInfoFromToProto(&pbpeerNodeInfo) 574 if err != nil { 575 return nil, err 576 } 577 578 return peerNodeInfo, c.SetDeadline(time.Time{}) 579 } 580 581 func upgradeSecretConn( 582 c net.Conn, 583 timeout time.Duration, 584 privKey crypto.PrivKey, 585 ) (*conn.SecretConnection, error) { 586 if err := c.SetDeadline(time.Now().Add(timeout)); err != nil { 587 return nil, err 588 } 589 590 sc, err := conn.MakeSecretConnection(c, privKey) 591 if err != nil { 592 return nil, err 593 } 594 595 return sc, sc.SetDeadline(time.Time{}) 596 } 597 598 func resolveIPs(resolver IPResolver, c net.Conn) ([]net.IP, error) { 599 host, _, err := net.SplitHostPort(c.RemoteAddr().String()) 600 if err != nil { 601 return nil, err 602 } 603 604 // implement with reference to https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/dns-client-resolution-timeouts#what-is-the-default-behavior-of-a-dns-client-when-a-single-dns-server-is-configured-on-the-nic 605 timeouts := []time.Duration{1, 1, 2, 4, 2} 606 addrs := []net.IPAddr{} 607 for _, to := range timeouts { 608 timeoutCtx, cancelFunc := context.WithTimeout(context.Background(), to*time.Second) 609 defer cancelFunc() 610 addrs, err = resolver.LookupIPAddr(timeoutCtx, host) 611 if err == nil { 612 break 613 } 614 } 615 if err != nil { 616 return nil, err 617 } 618 619 ips := []net.IP{} 620 621 for _, addr := range addrs { 622 ips = append(ips, addr.IP) 623 } 624 625 return ips, nil 626 }