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  }