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