-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
server: Use local addr var in version handler. #1256
Merged
Roasbeef
merged 10 commits into
btcsuite:master
from
davecgh:server_onversion_use_local_for_net_addr
Oct 13, 2018
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
25dfda9
peer: Add duplicate version message test.
davecgh 118f552
peer: Rework version negotiation.
davecgh 7b103e2
peer: Allow OnVersion callback to reject peer.
davecgh 9151ebc
server: Reject outbound conns to non-full nodes.
davecgh 4d1e1db
peer: Improve net address service adverts.
davecgh 24e2352
addrmgr: Expose method to update services.
davecgh 4b20d4f
server: Update addrmgr services on outbound conns.
davecgh d2c7892
server: Use local inbound var in version handler.
davecgh c8b9fab
server: Only advertise local addr when current.
davecgh 8c981e4
server: Use local addr var in version handler.
davecgh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,9 +34,9 @@ const ( | |
// inv message to a peer. | ||
DefaultTrickleInterval = 10 * time.Second | ||
|
||
// minAcceptableProtocolVersion is the lowest protocol version that a | ||
// MinAcceptableProtocolVersion is the lowest protocol version that a | ||
// connected peer may support. | ||
minAcceptableProtocolVersion = wire.MultipleAddressVersion | ||
MinAcceptableProtocolVersion = wire.MultipleAddressVersion | ||
|
||
// outputBufferSize is the number of elements the output channels use. | ||
outputBufferSize = 50 | ||
|
@@ -187,7 +187,9 @@ type MessageListeners struct { | |
OnMerkleBlock func(p *Peer, msg *wire.MsgMerkleBlock) | ||
|
||
// 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 func(p *Peer, msg *wire.MsgVerAck) | ||
|
@@ -1369,7 +1371,7 @@ out: | |
p.stallControl <- stallControlMsg{sccHandlerStart, rmsg} | ||
switch msg := rmsg.(type) { | ||
case *wire.MsgVersion: | ||
|
||
// Limit to one version message per peer. | ||
p.PushRejectMsg(msg.Command(), wire.RejectDuplicate, | ||
"duplicate version message", nil, true) | ||
break out | ||
|
@@ -1875,26 +1877,42 @@ func (p *Peer) Disconnect() { | |
close(p.quit) | ||
} | ||
|
||
// handleRemoteVersionMsg is invoked when a version bitcoin message is received | ||
// from the remote peer. It will return an error if the remote peer's version | ||
// is not compatible with ours. | ||
func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error { | ||
// readRemoteVersionMsg waits for the next message to arrive from the remote | ||
// peer. If the next message is not a version message or the version is not | ||
// acceptable then return an error. | ||
func (p *Peer) readRemoteVersionMsg() error { | ||
// Read their version message. | ||
remoteMsg, _, err := p.readMessage(wire.LatestEncoding) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Notify and disconnect clients if the first message is not a version | ||
// message. | ||
msg, ok := remoteMsg.(*wire.MsgVersion) | ||
if !ok { | ||
reason := "a version message must precede all others" | ||
rejectMsg := wire.NewMsgReject(msg.Command(), wire.RejectMalformed, | ||
reason) | ||
_ = p.writeMessage(rejectMsg, wire.LatestEncoding) | ||
return errors.New(reason) | ||
} | ||
|
||
// Detect self connections. | ||
if !allowSelfConns && sentNonces.Exists(msg.Nonce) { | ||
return errors.New("disconnecting peer connected to self") | ||
} | ||
|
||
// Notify and disconnect clients that have a protocol version that is | ||
// too old. | ||
// | ||
// NOTE: If minAcceptableProtocolVersion is raised to be higher than | ||
// wire.RejectVersion, this should send a reject packet before | ||
// disconnecting. | ||
if uint32(msg.ProtocolVersion) < minAcceptableProtocolVersion { | ||
reason := fmt.Sprintf("protocol version must be %d or greater", | ||
minAcceptableProtocolVersion) | ||
return errors.New(reason) | ||
} | ||
// Negotiate the protocol version and set the services to what the remote | ||
// peer advertised. | ||
p.flagsMtx.Lock() | ||
p.advertisedProtoVer = uint32(msg.ProtocolVersion) | ||
p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer) | ||
p.versionKnown = true | ||
p.services = msg.Services | ||
p.flagsMtx.Unlock() | ||
log.Debugf("Negotiated protocol version %d for peer %s", | ||
p.protocolVersion, p) | ||
|
||
// Updating a bunch of stats including block based stats, and the | ||
// peer's time offset. | ||
|
@@ -1904,22 +1922,10 @@ func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error { | |
p.timeOffset = msg.Timestamp.Unix() - time.Now().Unix() | ||
p.statsMtx.Unlock() | ||
|
||
// Negotiate the protocol version. | ||
// Set the peer's ID, user agent, and potentially the flag which | ||
// specifies the witness support is enabled. | ||
p.flagsMtx.Lock() | ||
p.advertisedProtoVer = uint32(msg.ProtocolVersion) | ||
p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer) | ||
p.versionKnown = true | ||
log.Debugf("Negotiated protocol version %d for peer %s", | ||
p.protocolVersion, p) | ||
|
||
// Set the peer's ID. | ||
p.id = atomic.AddInt32(&nodeCount, 1) | ||
|
||
// Set the supported services for the peer to what the remote peer | ||
// advertised. | ||
p.services = msg.Services | ||
|
||
// Set the remote peer's user agent. | ||
p.userAgent = msg.UserAgent | ||
|
||
// Determine if the peer would like to receive witness data with | ||
|
@@ -1938,36 +1944,33 @@ func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error { | |
p.wireEncoding = wire.WitnessEncoding | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// readRemoteVersionMsg waits for the next message to arrive from the remote | ||
// peer. If the next message is not a version message or the version is not | ||
// acceptable then return an error. | ||
func (p *Peer) readRemoteVersionMsg() error { | ||
// Read their version message. | ||
msg, _, err := p.readMessage(wire.LatestEncoding) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
remoteVerMsg, ok := msg.(*wire.MsgVersion) | ||
if !ok { | ||
errStr := "A version message must precede all others" | ||
log.Errorf(errStr) | ||
|
||
rejectMsg := wire.NewMsgReject(msg.Command(), wire.RejectMalformed, | ||
errStr) | ||
return p.writeMessage(rejectMsg, wire.LatestEncoding) | ||
// Invoke the callback if specified. | ||
if p.cfg.Listeners.OnVersion != nil { | ||
rejectMsg := p.cfg.Listeners.OnVersion(p, msg) | ||
if rejectMsg != nil { | ||
_ = p.writeMessage(rejectMsg, wire.LatestEncoding) | ||
return errors.New(rejectMsg.Reason) | ||
} | ||
} | ||
|
||
if err := p.handleRemoteVersionMsg(remoteVerMsg); err != nil { | ||
return err | ||
// Notify and disconnect clients that have a protocol version that is | ||
// too old. | ||
// | ||
// NOTE: If minAcceptableProtocolVersion is raised to be higher than | ||
// wire.RejectVersion, this should send a reject packet before | ||
// disconnecting. | ||
if uint32(msg.ProtocolVersion) < MinAcceptableProtocolVersion { | ||
// Send a reject message indicating the protocol version is | ||
// obsolete and wait for the message to be sent before | ||
// disconnecting. | ||
reason := fmt.Sprintf("protocol version must be %d or greater", | ||
MinAcceptableProtocolVersion) | ||
rejectMsg := wire.NewMsgReject(msg.Command(), wire.RejectObsolete, | ||
reason) | ||
_ = p.writeMessage(rejectMsg, wire.LatestEncoding) | ||
return errors.New(reason) | ||
} | ||
|
||
if p.cfg.Listeners.OnVersion != nil { | ||
p.cfg.Listeners.OnVersion(p, remoteVerMsg) | ||
} | ||
return nil | ||
} | ||
|
||
|
@@ -1992,7 +1995,8 @@ func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) { | |
proxyaddress, _, err := net.SplitHostPort(p.cfg.Proxy) | ||
// invalid proxy means poorly configured, be on the safe side. | ||
if err != nil || p.na.IP.String() == proxyaddress { | ||
theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, 0) | ||
theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, | ||
theirNA.Services) | ||
} | ||
} | ||
|
||
|
@@ -2020,25 +2024,7 @@ func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) { | |
msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion, | ||
p.cfg.UserAgentComments...) | ||
|
||
// XXX: bitcoind appears to always enable the full node services flag | ||
// of the remote peer netaddress field in the version message regardless | ||
// of whether it knows it supports it or not. Also, bitcoind sets | ||
// the services field of the local peer to 0 regardless of support. | ||
// | ||
// Realistically, this should be set as follows: | ||
// - For outgoing connections: | ||
// - Set the local netaddress services to what the local peer | ||
// actually supports | ||
// - Set the remote netaddress services to 0 to indicate no services | ||
// as they are still unknown | ||
// - For incoming connections: | ||
// - Set the local netaddress services to what the local peer | ||
// actually supports | ||
// - Set the remote netaddress services to the what was advertised by | ||
// by the remote peer in its version message | ||
msg.AddrYou.Services = wire.SFNodeNetwork | ||
|
||
// Advertise the services flag | ||
// Advertise local services. | ||
msg.Services = p.cfg.Services | ||
|
||
// Advertise our max supported protocol version. | ||
|
@@ -2099,9 +2085,11 @@ func (p *Peer) start() error { | |
select { | ||
case err := <-negotiateErr: | ||
if err != nil { | ||
p.Disconnect() | ||
return err | ||
} | ||
case <-time.After(negotiateTimeout): | ||
p.Disconnect() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! I think this might explain some issues I've seen where the connection count keeps rising (towards max connected), yet the number of stable peers queryable is much lower. |
||
return errors.New("protocol negotiation timeout") | ||
} | ||
log.Debugf("Connected to %s", p.Addr()) | ||
|
@@ -2224,14 +2212,13 @@ func NewOutboundPeer(cfg *Config, addr string) (*Peer, error) { | |
} | ||
|
||
if cfg.HostToNetAddress != nil { | ||
na, err := cfg.HostToNetAddress(host, uint16(port), cfg.Services) | ||
na, err := cfg.HostToNetAddress(host, uint16(port), 0) | ||
if err != nil { | ||
return nil, err | ||
} | ||
p.na = na | ||
} else { | ||
p.na = wire.NewNetAddressIPPort(net.ParseIP(host), uint16(port), | ||
cfg.Services) | ||
p.na = wire.NewNetAddressIPPort(net.ParseIP(host), uint16(port), 0) | ||
} | ||
|
||
return p, nil | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, this isn't yet useful as we don't currently store the services on disk within the addrmgr. However, it does pave the way for us properly updating the services for a peer as they change overtime once we start to store the services on disk properly.