peer error introduces more differentiation and verify func is called on peer

- keep missing, mismatch and invalid pubkey errors to errPubkeyInvalid -> DiscInvalidIdentity
- introduce errBlacklistedPeer, errSelfConnection, errConnectedPeer, errRejectedPeer -> DiscUselessPeer
- peer.pubkeyHook -> peer.verifyPeerHook
- peer.verifyPeerHook called on peer by protocol after handshake info set
- peer.Pubkey looks into identity.Pubkey  too (redundant though)
This commit is contained in:
zelig 2015-01-08 11:35:55 +00:00
parent 67ccc4f2f6
commit c8aa9f1e75
6 changed files with 40 additions and 31 deletions

View file

@ -93,7 +93,7 @@ type Peer struct {
ourListenAddr *peerAddr // listen addr of Server, nil if not listening
addPeer func(*peerAddr) error // tell server about received peers
getPeers func(...[]byte) []*peerAddr // should return the list of all peers
pubkeyHook func(*peerAddr) error // called at end of handshake to validate pubkey
verifyPeerHook func(*Peer) error // called at end of handshake to validate peer
}
// NewPeer returns a peer for testing purposes.
@ -152,13 +152,14 @@ func (self *Peer) Hash() []byte {
func (self *Peer) Pubkey() (pubkey []byte) {
self.infolock.Lock()
defer self.infolock.Unlock()
if self.dialAddr != nil {
switch {
case self.identity != nil:
pubkey = self.identity.Pubkey()
case self.dialAddr != nil:
pubkey = self.dialAddr.Pubkey
} else {
if self.listenAddr != nil {
case self.listenAddr != nil:
pubkey = self.listenAddr.Pubkey
}
}
return
}

View file

@ -14,7 +14,11 @@ const (
errP2PVersionMismatch
errPubkeyMissing
errPubkeyInvalid
errPubkeyForbidden
errPubkeyMismatch
errBlacklistedPeer
errSelfConnection
errConnectedPeer
errRejectedPeer
errProtocolBreach
errPingTimeout
errInvalidNetworkId
@ -31,7 +35,11 @@ var errorToString = map[int]string{
errP2PVersionMismatch: "P2P Version Mismatch",
errPubkeyMissing: "Public key missing",
errPubkeyInvalid: "Public key invalid",
errPubkeyForbidden: "Public key forbidden",
errPubkeyMismatch: "Public key mismatch",
errBlacklistedPeer: "Blacklisted peer",
errSelfConnection: "Self connection",
errConnectedPeer: "Connected peer",
errRejectedPeer: "Rejected peer",
errProtocolBreach: "Protocol Breach",
errPingTimeout: "Ping timeout",
errInvalidNetworkId: "Invalid network id",
@ -117,9 +125,9 @@ func discReasonForError(err error) DiscReason {
switch peerError.Code {
case errP2PVersionMismatch:
return DiscIncompatibleVersion
case errPubkeyMissing, errPubkeyInvalid:
case errPubkeyMissing, errPubkeyMismatch, errPubkeyInvalid:
return DiscInvalidIdentity
case errPubkeyForbidden:
case errBlacklistedPeer, errSelfConnection, errConnectedPeer, errRejectedPeer:
return DiscUselessPeer
case errInvalidMsgCode, errMagicTokenMismatch, errProtocolBreach:
return DiscProtocolError

View file

@ -34,7 +34,7 @@ func testPeer(protos []Protocol) (net.Conn, *Peer, <-chan error) {
peer.init(conn1)
peer.protocols = protos
peer.ourID = &peerId{}
peer.pubkeyHook = func(*peerAddr) error { return nil }
peer.verifyPeerHook = func(*Peer) error { return nil }
errc := make(chan error, 1)
go func() {
_, err := peer.loop()

View file

@ -249,13 +249,9 @@ func (bp *baseProtocol) readHandshake() error {
// verify that the peer we wanted to connect to
// actually holds the target public key.
if da.Pubkey != nil && !bytes.Equal(da.Pubkey, hs.NodeID) {
return newPeerError(errPubkeyForbidden, "dial address pubkey mismatch")
return newPeerError(errPubkeyMismatch, "dial address pubkey mismatch: %x vs %x", da.Pubkey, hs.NodeID)
}
}
pa := newPeerAddr(bp.peer.conn.RemoteAddr(), hs.NodeID)
if err := bp.peer.pubkeyHook(pa); err != nil {
return newPeerError(errPubkeyForbidden, "%v", err)
}
// TODO: remove Caps with empty name
var addr *peerAddr
if hs.ListenPort != 0 {
@ -263,6 +259,9 @@ func (bp *baseProtocol) readHandshake() error {
addr.Port = hs.ListenPort
}
bp.peer.setHandshakeInfo(&hs, addr, hs.Caps)
if err := bp.peer.verifyPeerHook(bp.peer); err != nil {
return err
}
bp.peer.startSubprotocols(hs.Caps)
return nil
}

View file

@ -29,7 +29,7 @@ func (self *peerId) Pubkey() (pubkey []byte) {
func newTestPeer() (peer *Peer) {
peer = NewPeer(&peerId{}, []Cap{})
peer.pubkeyHook = func(*peerAddr) error { return nil }
peer.verifyPeerHook = func(*Peer) error { return nil }
peer.ourID = &peerId{}
peer.listenAddr = &peerAddr{}
peer.getPeers = func(...[]byte) []*peerAddr { return nil }
@ -110,7 +110,7 @@ func TestBaseProtocolPeers(t *testing.T) {
func TestBaseProtocolDisconnect(t *testing.T) {
peer := NewPeer(&peerId{}, nil)
peer.ourID = &peerId{}
peer.pubkeyHook = func(*peerAddr) error { return nil }
peer.verifyPeerHook = func(*Peer) error { return nil }
rw1, rw2 := MsgPipe()
done := make(chan struct{})

View file

@ -189,7 +189,7 @@ func (srv *Server) connect(p *Peer, conn net.Conn) {
p.ourID = srv.Identity
p.addPeer = srv.AddPeer
p.getPeers = srv.GetPeers
p.pubkeyHook = srv.verifyPeer
p.verifyPeerHook = srv.verifyPeer
p.runBaseProtocol = true
p.protocols = srv.Protocols
@ -427,20 +427,21 @@ func (srv *Server) removePeer(peer *Peer) {
srv.peerSlots <- peer.slot
}
func (srv *Server) verifyPeer(addr *peerAddr) error {
if srv.Blacklist.Exists(addr.Pubkey) {
return errors.New("blacklisted")
func (srv *Server) verifyPeer(peer *Peer) error {
pubkey := peer.Pubkey()
if srv.Blacklist.Exists(pubkey) {
return newPeerError(errBlacklistedPeer, "")
}
if bytes.Equal(srv.Identity.Pubkey()[1:], addr.Pubkey) {
return newPeerError(errPubkeyForbidden, "not allowed to connect to srv")
if bytes.Equal(srv.Identity.Pubkey()[1:], pubkey) {
return newPeerError(errSelfConnection, "")
}
srv.lock.RLock()
defer srv.lock.RUnlock()
for _, peer := range srv.peers {
if peer != nil {
id := peer.Identity()
if id != nil && bytes.Equal(id.Pubkey(), addr.Pubkey) {
return errors.New("already connected")
if id != nil && bytes.Equal(id.Pubkey(), pubkey) {
return newPeerError(errConnectedPeer, "")
}
}
}