github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/connection_gater_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/kevinms/leakybucket-go"
     9  	"github.com/libp2p/go-libp2p"
    10  	"github.com/libp2p/go-libp2p-core/peer"
    11  	ma "github.com/multiformats/go-multiaddr"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers/peerdata"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers/scorers"
    15  	mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    16  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1"
    17  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    18  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    19  )
    20  
    21  func TestPeer_AtMaxLimit(t *testing.T) {
    22  	// create host and remote peer
    23  	ipAddr, pkey := createAddrAndPrivKey(t)
    24  	ipAddr2, pkey2 := createAddrAndPrivKey(t)
    25  
    26  	listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, 2000))
    27  	require.NoError(t, err, "Failed to p2p listen")
    28  	s := &Service{
    29  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
    30  	}
    31  	s.peers = peers.NewStatus(context.Background(), &peers.StatusConfig{
    32  		PeerLimit: 0,
    33  		ScorerParams: &scorers.Config{
    34  			BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
    35  				Threshold: 3,
    36  			},
    37  		},
    38  	})
    39  	s.cfg = &Config{MaxPeers: 0}
    40  	s.addrFilter, err = configureFilter(&Config{})
    41  	require.NoError(t, err)
    42  	h1, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey), libp2p.ListenAddrs(listen), libp2p.ConnectionGater(s)}...)
    43  	require.NoError(t, err)
    44  	s.host = h1
    45  	defer func() {
    46  		err := h1.Close()
    47  		require.NoError(t, err)
    48  	}()
    49  
    50  	for i := 0; i < highWatermarkBuffer; i++ {
    51  		addPeer(t, s.peers, peers.PeerConnected)
    52  	}
    53  
    54  	// create alternate host
    55  	listen, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr2, 3000))
    56  	require.NoError(t, err, "Failed to p2p listen")
    57  	h2, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey2), libp2p.ListenAddrs(listen)}...)
    58  	require.NoError(t, err)
    59  	defer func() {
    60  		err := h2.Close()
    61  		require.NoError(t, err)
    62  	}()
    63  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr, 2000, h1.ID()))
    64  	require.NoError(t, err)
    65  	addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddress)
    66  	require.NoError(t, err)
    67  	err = h2.Connect(context.Background(), *addrInfo)
    68  	require.NotNil(t, err, "Wanted connection to fail with max peer")
    69  }
    70  
    71  func TestService_InterceptBannedIP(t *testing.T) {
    72  	s := &Service{
    73  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
    74  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
    75  			PeerLimit:    20,
    76  			ScorerParams: &scorers.Config{},
    77  		}),
    78  	}
    79  	var err error
    80  	s.addrFilter, err = configureFilter(&Config{})
    81  	require.NoError(t, err)
    82  	ip := "212.67.10.122"
    83  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
    84  	require.NoError(t, err)
    85  
    86  	for i := 0; i < ipBurst; i++ {
    87  		valid := s.validateDial(multiAddress)
    88  		if !valid {
    89  			t.Errorf("Expected multiaddress with ip %s to not be rejected", ip)
    90  		}
    91  	}
    92  	valid := s.validateDial(multiAddress)
    93  	if valid {
    94  		t.Errorf("Expected multiaddress with ip %s to be rejected as it exceeds the burst limit", ip)
    95  	}
    96  }
    97  
    98  func TestService_RejectInboundPeersBeyondLimit(t *testing.T) {
    99  	limit := 20
   100  	s := &Service{
   101  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   102  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   103  			PeerLimit:    limit,
   104  			ScorerParams: &scorers.Config{},
   105  		}),
   106  		host: mockp2p.NewTestP2P(t).BHost,
   107  		cfg:  &Config{MaxPeers: uint(limit)},
   108  	}
   109  	var err error
   110  	s.addrFilter, err = configureFilter(&Config{})
   111  	require.NoError(t, err)
   112  	ip := "212.67.10.122"
   113  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   114  	require.NoError(t, err)
   115  
   116  	valid := s.InterceptAccept(&maEndpoints{raddr: multiAddress})
   117  	if !valid {
   118  		t.Errorf("Expected multiaddress with ip %s to be accepted as it is below the inbound limit", ip)
   119  	}
   120  
   121  	inboundLimit := float64(limit) * peers.InboundRatio
   122  	inboundLimit += highWatermarkBuffer
   123  	// top off by 1 to trigger it above the limit.
   124  	inboundLimit += 1
   125  	// Add in up to inbound peer limit.
   126  	for i := 0; i < int(inboundLimit); i++ {
   127  		addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED))
   128  	}
   129  	valid = s.InterceptAccept(&maEndpoints{raddr: multiAddress})
   130  	if valid {
   131  		t.Errorf("Expected multiaddress with ip %s to be rejected as it exceeds the inbound limit", ip)
   132  	}
   133  }
   134  
   135  func TestPeer_BelowMaxLimit(t *testing.T) {
   136  	// create host and remote peer
   137  	ipAddr, pkey := createAddrAndPrivKey(t)
   138  	ipAddr2, pkey2 := createAddrAndPrivKey(t)
   139  
   140  	listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, 2000))
   141  	require.NoError(t, err, "Failed to p2p listen")
   142  	s := &Service{
   143  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   144  	}
   145  	s.peers = peers.NewStatus(context.Background(), &peers.StatusConfig{
   146  		PeerLimit: 1,
   147  		ScorerParams: &scorers.Config{
   148  			BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
   149  				Threshold: 3,
   150  			},
   151  		},
   152  	})
   153  	s.cfg = &Config{MaxPeers: 1}
   154  	s.addrFilter, err = configureFilter(&Config{})
   155  	require.NoError(t, err)
   156  	h1, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey), libp2p.ListenAddrs(listen), libp2p.ConnectionGater(s)}...)
   157  	require.NoError(t, err)
   158  	s.host = h1
   159  	defer func() {
   160  		err := h1.Close()
   161  		require.NoError(t, err)
   162  	}()
   163  
   164  	// create alternate host
   165  	listen, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr2, 3000))
   166  	require.NoError(t, err, "Failed to p2p listen")
   167  	h2, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey2), libp2p.ListenAddrs(listen)}...)
   168  	require.NoError(t, err)
   169  	defer func() {
   170  		err := h2.Close()
   171  		require.NoError(t, err)
   172  	}()
   173  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr, 2000, h1.ID()))
   174  	require.NoError(t, err)
   175  	addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddress)
   176  	require.NoError(t, err)
   177  	err = h2.Connect(context.Background(), *addrInfo)
   178  	assert.NoError(t, err, "Wanted connection to succeed")
   179  }
   180  
   181  func TestPeerAllowList(t *testing.T) {
   182  	// create host with allow list
   183  	ipAddr, pkey := createAddrAndPrivKey(t)
   184  	ipAddr2, pkey2 := createAddrAndPrivKey(t)
   185  
   186  	// use unattainable subnet, which will lead to
   187  	// peer rejecting all peers, except for those
   188  	// from that subnet.
   189  	cidr := "202.35.89.12/16"
   190  
   191  	listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, 2000))
   192  	require.NoError(t, err, "Failed to p2p listen")
   193  	s := &Service{
   194  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   195  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   196  			ScorerParams: &scorers.Config{},
   197  		}),
   198  	}
   199  	s.addrFilter, err = configureFilter(&Config{AllowListCIDR: cidr})
   200  	require.NoError(t, err)
   201  	h1, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey), libp2p.ListenAddrs(listen), libp2p.ConnectionGater(s)}...)
   202  	require.NoError(t, err)
   203  	s.host = h1
   204  	defer func() {
   205  		err := h1.Close()
   206  		require.NoError(t, err)
   207  	}()
   208  
   209  	// create alternate host
   210  	listen, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr2, 3000))
   211  	require.NoError(t, err, "Failed to p2p listen")
   212  	h2, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey2), libp2p.ListenAddrs(listen)}...)
   213  	require.NoError(t, err)
   214  	defer func() {
   215  		err := h2.Close()
   216  		require.NoError(t, err)
   217  	}()
   218  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr2, 3000, h2.ID()))
   219  	require.NoError(t, err)
   220  	addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddress)
   221  	require.NoError(t, err)
   222  	err = h1.Connect(context.Background(), *addrInfo)
   223  	assert.NotNil(t, err, "Wanted connection to fail with allow list")
   224  	assert.ErrorContains(t, "no good addresses", err)
   225  }
   226  
   227  func TestPeerDenyList(t *testing.T) {
   228  	// create host with deny list
   229  	ipAddr, pkey := createAddrAndPrivKey(t)
   230  	ipAddr2, pkey2 := createAddrAndPrivKey(t)
   231  
   232  	mask := ipAddr2.DefaultMask()
   233  	ones, _ := mask.Size()
   234  	maskedIP := ipAddr2.Mask(mask)
   235  	cidr := maskedIP.String() + fmt.Sprintf("/%d", ones)
   236  
   237  	listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, 2000))
   238  	require.NoError(t, err, "Failed to p2p listen")
   239  	s := &Service{
   240  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   241  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   242  			ScorerParams: &scorers.Config{},
   243  		}),
   244  	}
   245  	s.addrFilter, err = configureFilter(&Config{DenyListCIDR: []string{cidr}})
   246  	require.NoError(t, err)
   247  	h1, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey), libp2p.ListenAddrs(listen), libp2p.ConnectionGater(s)}...)
   248  	require.NoError(t, err)
   249  	s.host = h1
   250  	defer func() {
   251  		err := h1.Close()
   252  		require.NoError(t, err)
   253  	}()
   254  
   255  	// create alternate host
   256  	listen, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr2, 3000))
   257  	require.NoError(t, err, "Failed to p2p listen")
   258  	h2, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey2), libp2p.ListenAddrs(listen)}...)
   259  	require.NoError(t, err)
   260  	defer func() {
   261  		err := h2.Close()
   262  		require.NoError(t, err)
   263  	}()
   264  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr2, 3000, h2.ID()))
   265  	require.NoError(t, err)
   266  	addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddress)
   267  	require.NoError(t, err)
   268  	err = h1.Connect(context.Background(), *addrInfo)
   269  	assert.NotNil(t, err, "Wanted connection to fail with deny list")
   270  	assert.ErrorContains(t, "no good addresses", err)
   271  }
   272  
   273  func TestService_InterceptAddrDial_Allow(t *testing.T) {
   274  	s := &Service{
   275  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   276  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   277  			ScorerParams: &scorers.Config{},
   278  		}),
   279  	}
   280  	var err error
   281  	cidr := "212.67.89.112/16"
   282  	s.addrFilter, err = configureFilter(&Config{AllowListCIDR: cidr})
   283  	require.NoError(t, err)
   284  	ip := "212.67.10.122"
   285  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   286  	require.NoError(t, err)
   287  	valid := s.InterceptAddrDial("", multiAddress)
   288  	if !valid {
   289  		t.Errorf("Expected multiaddress with ip %s to not be rejected with an allow cidr mask of %s", ip, cidr)
   290  	}
   291  }
   292  
   293  func TestService_InterceptAddrDial_Public(t *testing.T) {
   294  	s := &Service{
   295  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   296  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   297  			ScorerParams: &scorers.Config{},
   298  		}),
   299  	}
   300  	var err error
   301  	//test with public filter
   302  	cidr := "public"
   303  	ip := "212.67.10.122"
   304  	s.addrFilter, err = configureFilter(&Config{AllowListCIDR: cidr})
   305  	require.NoError(t, err)
   306  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   307  	require.NoError(t, err)
   308  	valid := s.InterceptAddrDial("", multiAddress)
   309  	if !valid {
   310  		t.Errorf("Expected multiaddress with ip %s to not be rejected since we allow public addresses", ip)
   311  	}
   312  
   313  	ip = "192.168.1.0" //this is private and should fail
   314  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   315  	require.NoError(t, err)
   316  	valid = s.InterceptAddrDial("", multiAddress)
   317  	if valid {
   318  		t.Errorf("Expected multiaddress with ip %s to be rejected since we are only allowing public addresses", ip)
   319  	}
   320  
   321  	//test with public allow filter, with a public address added to the deny list
   322  	invalidPublicIp := "212.67.10.122"
   323  	validPublicIp := "91.65.69.69"
   324  	s.addrFilter, err = configureFilter(&Config{AllowListCIDR: "public", DenyListCIDR: []string{"212.67.89.112/16"}})
   325  	require.NoError(t, err)
   326  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", validPublicIp, 3000))
   327  	require.NoError(t, err)
   328  	valid = s.InterceptAddrDial("", multiAddress)
   329  	if !valid {
   330  		t.Errorf("Expected multiaddress with ip %s to not be rejected since it is a public address that is not in the deny list", ip)
   331  	}
   332  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", invalidPublicIp, 3000))
   333  	require.NoError(t, err)
   334  	valid = s.InterceptAddrDial("", multiAddress)
   335  	if valid {
   336  		t.Errorf("Expected multiaddress with ip %s to be rejected since it is on the deny list", ip)
   337  	}
   338  
   339  }
   340  
   341  func TestService_InterceptAddrDial_Private(t *testing.T) {
   342  	s := &Service{
   343  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   344  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   345  			ScorerParams: &scorers.Config{},
   346  		}),
   347  	}
   348  	var err error
   349  	//test with private filter
   350  	cidr := "private"
   351  	s.addrFilter, err = configureFilter(&Config{DenyListCIDR: []string{cidr}})
   352  	require.NoError(t, err)
   353  	ip := "212.67.10.122"
   354  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   355  	require.NoError(t, err)
   356  	valid := s.InterceptAddrDial("", multiAddress)
   357  	if !valid {
   358  		t.Errorf("Expected multiaddress with ip %s to be allowed since we are only denying private addresses", ip)
   359  	}
   360  
   361  	ip = "192.168.1.0"
   362  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   363  	require.NoError(t, err)
   364  	valid = s.InterceptAddrDial("", multiAddress)
   365  	if valid {
   366  		t.Errorf("Expected multiaddress with ip %s to be rejected since we are denying private addresses", ip)
   367  	}
   368  }
   369  
   370  func TestService_InterceptAddrDial_AllowPrivate(t *testing.T) {
   371  	s := &Service{
   372  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   373  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   374  			ScorerParams: &scorers.Config{},
   375  		}),
   376  	}
   377  	var err error
   378  	//test with private filter
   379  	cidr := "private"
   380  	s.addrFilter, err = configureFilter(&Config{AllowListCIDR: cidr})
   381  	require.NoError(t, err)
   382  	ip := "212.67.10.122"
   383  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   384  	require.NoError(t, err)
   385  	valid := s.InterceptAddrDial("", multiAddress)
   386  	if valid {
   387  		t.Errorf("Expected multiaddress with ip %s to be denied since we are only allowing private addresses", ip)
   388  	}
   389  
   390  	ip = "192.168.1.0"
   391  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   392  	require.NoError(t, err)
   393  	valid = s.InterceptAddrDial("", multiAddress)
   394  	if !valid {
   395  		t.Errorf("Expected multiaddress with ip %s to be allowed since we are allowing private addresses", ip)
   396  	}
   397  }
   398  
   399  func TestService_InterceptAddrDial_DenyPublic(t *testing.T) {
   400  	s := &Service{
   401  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   402  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   403  			ScorerParams: &scorers.Config{},
   404  		}),
   405  	}
   406  	var err error
   407  	//test with private filter
   408  	cidr := "public"
   409  	s.addrFilter, err = configureFilter(&Config{DenyListCIDR: []string{cidr}})
   410  	require.NoError(t, err)
   411  	ip := "212.67.10.122"
   412  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   413  	require.NoError(t, err)
   414  	valid := s.InterceptAddrDial("", multiAddress)
   415  	if valid {
   416  		t.Errorf("Expected multiaddress with ip %s to be denied since we are denying public addresses", ip)
   417  	}
   418  
   419  	ip = "192.168.1.0"
   420  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   421  	require.NoError(t, err)
   422  	valid = s.InterceptAddrDial("", multiAddress)
   423  	if !valid {
   424  		t.Errorf("Expected multiaddress with ip %s to be allowed since we are only denying public addresses", ip)
   425  	}
   426  }
   427  
   428  func TestService_InterceptAddrDial_AllowConflict(t *testing.T) {
   429  	s := &Service{
   430  		ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, false),
   431  		peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
   432  			ScorerParams: &scorers.Config{},
   433  		}),
   434  	}
   435  	var err error
   436  	//test with private filter
   437  	cidr := "public"
   438  	s.addrFilter, err = configureFilter(&Config{DenyListCIDR: []string{cidr, "192.168.0.0/16"}})
   439  	require.NoError(t, err)
   440  	ip := "212.67.10.122"
   441  	multiAddress, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   442  	require.NoError(t, err)
   443  	valid := s.InterceptAddrDial("", multiAddress)
   444  	if valid {
   445  		t.Errorf("Expected multiaddress with ip %s to be denied since we are denying public addresses", ip)
   446  	}
   447  
   448  	ip = "192.168.1.0"
   449  	multiAddress, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, 3000))
   450  	require.NoError(t, err)
   451  	valid = s.InterceptAddrDial("", multiAddress)
   452  	if valid {
   453  		t.Errorf("Expected multiaddress with ip %s will be denied since after denying public addresses, we then also deny this private address", ip)
   454  	}
   455  }
   456  
   457  // Mock type for testing.
   458  type maEndpoints struct {
   459  	laddr ma.Multiaddr
   460  	raddr ma.Multiaddr
   461  }
   462  
   463  // LocalMultiaddr returns the local address associated with
   464  // this connection
   465  func (c *maEndpoints) LocalMultiaddr() ma.Multiaddr {
   466  	return c.laddr
   467  }
   468  
   469  // RemoteMultiaddr returns the remote address associated with
   470  // this connection
   471  func (c *maEndpoints) RemoteMultiaddr() ma.Multiaddr {
   472  	return c.raddr
   473  }