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 }