From aeb6dc13ace4238415988e63460074a54d1c58d9 Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Sun, 10 May 2020 06:18:21 +0800 Subject: [PATCH] Add Ability to Restrict Outbound Dials (#5794) * blacklist cidr * add test * Merge refs/heads/master into p2pBlacklist --- beacon-chain/main.go | 1 + beacon-chain/node/node.go | 1 + beacon-chain/p2p/config.go | 1 + beacon-chain/p2p/options.go | 26 +++++++++++++++ beacon-chain/p2p/options_test.go | 56 ++++++++++++++++++++++++++++++++ beacon-chain/usage.go | 1 + shared/cmd/flags.go | 7 ++++ 7 files changed, 93 insertions(+) diff --git a/beacon-chain/main.go b/beacon-chain/main.go index 7ac7113ef73e..651fbd7d7c81 100644 --- a/beacon-chain/main.go +++ b/beacon-chain/main.go @@ -64,6 +64,7 @@ var appFlags = []cli.Flag{ cmd.P2PPrivKey, cmd.P2PMetadata, cmd.P2PWhitelist, + cmd.P2PBlacklist, cmd.P2PEncoding, cmd.P2PPubsub, cmd.DataDirFlag, diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index baf3b08574a5..04b7bc1c6991 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -320,6 +320,7 @@ func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error { UDPPort: cliCtx.Uint(cmd.P2PUDPPort.Name), MaxPeers: cliCtx.Uint(cmd.P2PMaxPeers.Name), WhitelistCIDR: cliCtx.String(cmd.P2PWhitelist.Name), + BlacklistCIDR: sliceutil.SplitCommaSeparated(cliCtx.StringSlice(cmd.P2PBlacklist.Name)), EnableUPnP: cliCtx.Bool(cmd.EnableUPnPFlag.Name), DisableDiscv5: cliCtx.Bool(flags.DisableDiscv5.Name), Encoding: cliCtx.String(cmd.P2PEncoding.Name), diff --git a/beacon-chain/p2p/config.go b/beacon-chain/p2p/config.go index ac5c3c8917c0..469cf0e8c518 100644 --- a/beacon-chain/p2p/config.go +++ b/beacon-chain/p2p/config.go @@ -25,6 +25,7 @@ type Config struct { UDPPort uint MaxPeers uint WhitelistCIDR string + BlacklistCIDR []string Encoding string StateNotifier statefeed.Notifier PubSub string diff --git a/beacon-chain/p2p/options.go b/beacon-chain/p2p/options.go index ae7ac0f752f6..bcb568145694 100644 --- a/beacon-chain/p2p/options.go +++ b/beacon-chain/p2p/options.go @@ -26,6 +26,7 @@ func buildOptions(cfg *Config, ip net.IP, priKey *ecdsa.PrivateKey) []libp2p.Opt libp2p.EnableRelay(), libp2p.ListenAddrs(listen), whitelistSubnet(cfg.WhitelistCIDR), + blacklistSubnets(cfg.BlacklistCIDR), // Add one for the boot node and another for the relay, otherwise when we are close to maxPeers we will be above the high // water mark and continually trigger pruning. libp2p.ConnectionManager(connmgr.NewConnManager(int(cfg.MaxPeers+2), int(cfg.MaxPeers+2), 1*time.Second)), @@ -121,3 +122,28 @@ func whitelistSubnet(cidr string) libp2p.Option { return nil } } + +// blacklistSubnet adds a blacklist multiaddress filter for multiple given CIDR subnets. +// Example: 192.168.0.0/16 may be used to deny connections from your local +// network. +func blacklistSubnets(mulCidrs []string) libp2p.Option { + if len(mulCidrs) == 0 { + return func(_ *libp2p.Config) error { + return nil + } + } + return func(cfg *libp2p.Config) error { + if cfg.Filters == nil { + cfg.Filters = filter.NewFilters() + } + + for _, cidr := range mulCidrs { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + cfg.Filters.AddFilter(*ipnet, filter.ActionDeny) + } + return nil + } +} diff --git a/beacon-chain/p2p/options_test.go b/beacon-chain/p2p/options_test.go index f762148dd255..7a22d0fb993e 100644 --- a/beacon-chain/p2p/options_test.go +++ b/beacon-chain/p2p/options_test.go @@ -2,13 +2,18 @@ package p2p import ( "bytes" + "context" "crypto/rand" "encoding/hex" + "fmt" "io/ioutil" "os" "testing" + "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/multiformats/go-multiaddr" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -58,3 +63,54 @@ func TestPrivateKeyLoading(t *testing.T) { t.Errorf("Private keys do not match got %#x but wanted %#x", rawBytes, newRaw) } } + +func TestPeerBlacklist(t *testing.T) { + // create host with blacklist + ipAddr, pkey := createAddrAndPrivKey(t) + ipAddr2, pkey2 := createAddrAndPrivKey(t) + + mask := ipAddr2.DefaultMask() + ones, _ := mask.Size() + maskedIP := ipAddr2.Mask(mask) + cidr := maskedIP.String() + fmt.Sprintf("/%d", ones) + + listen, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, 2000)) + if err != nil { + t.Fatalf("Failed to p2p listen: %v", err) + } + h1, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey), libp2p.ListenAddrs(listen), blacklistSubnets([]string{cidr})}...) + if err != nil { + t.Fatal(err) + } + defer func() { + err := h1.Close() + if err != nil { + t.Fatal(err) + } + }() + + // create alternate host + listen, err = multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr2, 3000)) + if err != nil { + t.Fatalf("Failed to p2p listen: %v", err) + } + h2, err := libp2p.New(context.Background(), []libp2p.Option{privKeyOption(pkey2), libp2p.ListenAddrs(listen)}...) + if err != nil { + t.Fatal(err) + } + defer func() { + err := h2.Close() + if err != nil { + t.Fatal(err) + } + }() + multiAddress, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr2, 3000, h2.ID())) + addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddress) + if err != nil { + t.Fatal(err) + } + err = h1.Connect(context.Background(), *addrInfo) + if err == nil { + t.Error("Wanted connection to fail with blacklist") + } +} diff --git a/beacon-chain/usage.go b/beacon-chain/usage.go index fc6ba8d311c4..a3a31418f0db 100644 --- a/beacon-chain/usage.go +++ b/beacon-chain/usage.go @@ -109,6 +109,7 @@ var appHelpFlagGroups = []flagGroup{ cmd.P2PPrivKey, cmd.P2PMetadata, cmd.P2PWhitelist, + cmd.P2PBlacklist, cmd.StaticPeers, cmd.EnableUPnPFlag, cmd.P2PEncoding, diff --git a/shared/cmd/flags.go b/shared/cmd/flags.go index dade0f087cce..a46a5a15579e 100644 --- a/shared/cmd/flags.go +++ b/shared/cmd/flags.go @@ -125,6 +125,13 @@ var ( "would whitelist connections to peers on your local network only. The default " + "is to accept all connections.", } + // P2PBlacklist defines a list of CIDR subnets to disallow connections from them. + P2PBlacklist = &cli.StringSliceFlag{ + Name: "p2p-blacklist", + Usage: "The CIDR subnets for blacklisting peer connections. Example: 192.168.0.0/16 " + + "would blacklist connections from peers on your local network only. The default " + + "is to accept all connections.", + } // P2PEncoding defines the encoding format for p2p messages. P2PEncoding = &cli.StringFlag{ Name: "p2p-encoding",