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