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 ourListenAddr *peerAddr // listen addr of Server, nil if not listening
addPeer func(*peerAddr) error // tell server about received peers addPeer func(*peerAddr) error // tell server about received peers
getPeers func(...[]byte) []*peerAddr // should return the list of all 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. // NewPeer returns a peer for testing purposes.
@ -152,13 +152,14 @@ func (self *Peer) Hash() []byte {
func (self *Peer) Pubkey() (pubkey []byte) { func (self *Peer) Pubkey() (pubkey []byte) {
self.infolock.Lock() self.infolock.Lock()
defer self.infolock.Unlock() 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 pubkey = self.dialAddr.Pubkey
} else { case self.listenAddr != nil:
if self.listenAddr != nil {
pubkey = self.listenAddr.Pubkey pubkey = self.listenAddr.Pubkey
} }
}
return return
} }

View file

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

View file

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

View file

@ -249,13 +249,9 @@ func (bp *baseProtocol) readHandshake() error {
// verify that the peer we wanted to connect to // verify that the peer we wanted to connect to
// actually holds the target public key. // actually holds the target public key.
if da.Pubkey != nil && !bytes.Equal(da.Pubkey, hs.NodeID) { 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 // TODO: remove Caps with empty name
var addr *peerAddr var addr *peerAddr
if hs.ListenPort != 0 { if hs.ListenPort != 0 {
@ -263,6 +259,9 @@ func (bp *baseProtocol) readHandshake() error {
addr.Port = hs.ListenPort addr.Port = hs.ListenPort
} }
bp.peer.setHandshakeInfo(&hs, addr, hs.Caps) bp.peer.setHandshakeInfo(&hs, addr, hs.Caps)
if err := bp.peer.verifyPeerHook(bp.peer); err != nil {
return err
}
bp.peer.startSubprotocols(hs.Caps) bp.peer.startSubprotocols(hs.Caps)
return nil return nil
} }

View file

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

View file

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