peer: Allow OnVersion callback to reject peer.

This modifies the OnVersion callback to allow a reject message to be
returned in which case the message will be sent to the peer and the peer
will be disconnected.

Backported from Decred.
This commit is contained in:
Dave Collins 2018-08-10 21:24:53 -05:00
parent 118f55233b
commit 7b103e2434
No known key found for this signature in database
GPG key ID: B8904D9D9C93D1F2
4 changed files with 20 additions and 10 deletions

View file

@ -1,4 +1,5 @@
// Copyright (c) 2015-2016 The btcsuite developers // Copyright (c) 2015-2018 The btcsuite developers
// Copyright (c) 2016-2018 The Decred developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -72,8 +73,9 @@ func Example_newOutboundPeer() {
Services: 0, Services: 0,
TrickleInterval: time.Second * 10, TrickleInterval: time.Second * 10,
Listeners: peer.MessageListeners{ Listeners: peer.MessageListeners{
OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) { OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
fmt.Println("outbound: received version") fmt.Println("outbound: received version")
return nil
}, },
OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) { OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) {
verack <- struct{}{} verack <- struct{}{}

View file

@ -187,7 +187,9 @@ type MessageListeners struct {
OnMerkleBlock func(p *Peer, msg *wire.MsgMerkleBlock) OnMerkleBlock func(p *Peer, msg *wire.MsgMerkleBlock)
// OnVersion is invoked when a peer receives a version bitcoin message. // OnVersion is invoked when a peer receives a version bitcoin message.
OnVersion func(p *Peer, msg *wire.MsgVersion) // The caller may return a reject message in which case the message will
// be sent to the peer and the peer will be disconnected.
OnVersion func(p *Peer, msg *wire.MsgVersion) *wire.MsgReject
// OnVerAck is invoked when a peer receives a verack bitcoin message. // OnVerAck is invoked when a peer receives a verack bitcoin message.
OnVerAck func(p *Peer, msg *wire.MsgVerAck) OnVerAck func(p *Peer, msg *wire.MsgVerAck)
@ -1944,7 +1946,11 @@ func (p *Peer) readRemoteVersionMsg() error {
// Invoke the callback if specified. // Invoke the callback if specified.
if p.cfg.Listeners.OnVersion != nil { if p.cfg.Listeners.OnVersion != nil {
p.cfg.Listeners.OnVersion(p, msg) rejectMsg := p.cfg.Listeners.OnVersion(p, msg)
if rejectMsg != nil {
_ = p.writeMessage(rejectMsg, wire.LatestEncoding)
return errors.New(rejectMsg.Reason)
}
} }
// Notify and disconnect clients that have a protocol version that is // Notify and disconnect clients that have a protocol version that is

View file

@ -432,8 +432,9 @@ func TestPeerListeners(t *testing.T) {
OnMerkleBlock: func(p *peer.Peer, msg *wire.MsgMerkleBlock) { OnMerkleBlock: func(p *peer.Peer, msg *wire.MsgMerkleBlock) {
ok <- msg ok <- msg
}, },
OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) { OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
ok <- msg ok <- msg
return nil
}, },
OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) { OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) {
verack <- struct{}{} verack <- struct{}{}

View file

@ -1,5 +1,5 @@
// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2017 The Decred developers // Copyright (c) 2015-2018 The Decred developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -388,11 +388,11 @@ func (sp *serverPeer) addBanScore(persistent, transient uint32, reason string) {
// OnVersion is invoked when a peer receives a version bitcoin message // OnVersion is invoked when a peer receives a version bitcoin message
// and is used to negotiate the protocol version details as well as kick start // and is used to negotiate the protocol version details as well as kick start
// the communications. // the communications.
func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) { func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
// Ignore peers that have a protcol version that is too old. The peer // Ignore peers that have a protcol version that is too old. The peer
// negotiation logic will disconnect it after this callback returns. // negotiation logic will disconnect it after this callback returns.
if msg.ProtocolVersion < int32(peer.MinAcceptableProtocolVersion) { if msg.ProtocolVersion < int32(peer.MinAcceptableProtocolVersion) {
return return nil
} }
// Add the remote peer time as a sample for creating an offset against // Add the remote peer time as a sample for creating an offset against
@ -424,7 +424,7 @@ func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) {
if err != nil { if err != nil {
peerLog.Errorf("Unable to query for segwit "+ peerLog.Errorf("Unable to query for segwit "+
"soft-fork state: %v", err) "soft-fork state: %v", err)
return return nil
} }
if segwitActive && !sp.IsWitnessEnabled() { if segwitActive && !sp.IsWitnessEnabled() {
@ -432,7 +432,7 @@ func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) {
"peer %v, isn't segwit enabled and "+ "peer %v, isn't segwit enabled and "+
"we need more segwit enabled peers", sp) "we need more segwit enabled peers", sp)
sp.Disconnect() sp.Disconnect()
return return nil
} }
// TODO(davec): Only do this if not doing the initial block // TODO(davec): Only do this if not doing the initial block
@ -463,6 +463,7 @@ func (sp *serverPeer) OnVersion(_ *peer.Peer, msg *wire.MsgVersion) {
// Add valid peer to the server. // Add valid peer to the server.
sp.server.AddPeer(sp) sp.server.AddPeer(sp)
return nil
} }
// OnMemPool is invoked when a peer receives a mempool bitcoin message. // OnMemPool is invoked when a peer receives a mempool bitcoin message.