do not even try to dial ourselves

also, remove address from the book (plus mark it as our address)
and return an error if we fail to parse peers list
This commit is contained in:
Anton Kaliaev 2018-04-05 15:21:11 +02:00
parent 7f6ee7a46b
commit 6e39ec6e26
No known key found for this signature in database
GPG Key ID: 7B6881D965918214
4 changed files with 77 additions and 35 deletions

View File

@ -33,13 +33,15 @@ type AddrBook interface {
// Add our own addresses so we don't later add ourselves // Add our own addresses so we don't later add ourselves
AddOurAddress(*p2p.NetAddress) AddOurAddress(*p2p.NetAddress)
// Check if it is our address // Check if it is our address
OurAddress(*p2p.NetAddress) bool OurAddress(*p2p.NetAddress) bool
// Add and remove an address // Add and remove an address
AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error
RemoveAddress(addr *p2p.NetAddress) RemoveAddress(*p2p.NetAddress)
// Check if the address is in the book
HasAddress(*p2p.NetAddress) bool
// Do we need more peers? // Do we need more peers?
NeedMoreAddrs() bool NeedMoreAddrs() bool
@ -196,6 +198,14 @@ func (a *addrBook) IsGood(addr *p2p.NetAddress) bool {
return a.addrLookup[addr.ID].isOld() return a.addrLookup[addr.ID].isOld()
} }
// HasAddress returns true if the address is in the book.
func (a *addrBook) HasAddress(addr *p2p.NetAddress) bool {
a.mtx.Lock()
defer a.mtx.Unlock()
ka := a.addrLookup[addr.ID]
return ka != nil
}
// NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book. // NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book.
func (a *addrBook) NeedMoreAddrs() bool { func (a *addrBook) NeedMoreAddrs() bool {
return a.Size() < needAddressThreshold return a.Size() < needAddressThreshold

View File

@ -338,3 +338,19 @@ func TestAddrBookGetSelectionWithBias(t *testing.T) {
t.Fatalf("expected more good peers (%% got: %d, %% expected: %d, number of good addrs: %d, total: %d)", got, expected, good, len(selection)) t.Fatalf("expected more good peers (%% got: %d, %% expected: %d, number of good addrs: %d, total: %d)", got, expected, good, len(selection))
} }
} }
func TestAddrBookHasAddress(t *testing.T) {
fname := createTempFileName("addrbook_test")
defer deleteTempFile(fname)
book := NewAddrBook(fname, true)
book.SetLogger(log.TestingLogger())
addr := randIPv4Address(t)
book.AddAddress(addr, addr)
assert.True(t, book.HasAddress(addr))
book.RemoveAddress(addr)
assert.False(t, book.HasAddress(addr))
}

View File

@ -40,6 +40,8 @@ type AddrBook interface {
AddOurAddress(*NetAddress) AddOurAddress(*NetAddress)
OurAddress(*NetAddress) bool OurAddress(*NetAddress) bool
MarkGood(*NetAddress) MarkGood(*NetAddress)
RemoveAddress(*NetAddress)
HasAddress(*NetAddress) bool
Save() Save()
} }
@ -351,18 +353,21 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
for _, err := range errs { for _, err := range errs {
sw.Logger.Error("Error in peer's address", "err", err) sw.Logger.Error("Error in peer's address", "err", err)
} }
if len(errs) > 0 {
return errors.New("Errors in peer addresses (see errors above)")
}
ourAddr := sw.nodeInfo.NetAddress()
// TODO: move this out of here ?
if addrBook != nil { if addrBook != nil {
// add peers to `addrBook` // add peers to `addrBook`
ourAddr := sw.nodeInfo.NetAddress()
for _, netAddr := range netAddrs { for _, netAddr := range netAddrs {
// do not add our address or ID // do not add our address or ID
if netAddr.Same(ourAddr) { if !netAddr.Same(ourAddr) {
continue
}
// TODO: move this out of here ?
addrBook.AddAddress(netAddr, ourAddr) addrBook.AddAddress(netAddr, ourAddr)
} }
}
// Persist some peers to disk right away. // Persist some peers to disk right away.
// NOTE: integration tests depend on this // NOTE: integration tests depend on this
addrBook.Save() addrBook.Save()
@ -372,8 +377,14 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
perm := sw.rng.Perm(len(netAddrs)) perm := sw.rng.Perm(len(netAddrs))
for i := 0; i < len(perm); i++ { for i := 0; i < len(perm); i++ {
go func(i int) { go func(i int) {
sw.randomSleep(0)
j := perm[i] j := perm[i]
// do not dial ourselves
if netAddrs[j].Same(ourAddr) {
return
}
sw.randomSleep(0)
err := sw.DialPeerWithAddress(netAddrs[j], persistent) err := sw.DialPeerWithAddress(netAddrs[j], persistent)
if err != nil { if err != nil {
sw.Logger.Error("Error dialing peer", "err", err) sw.Logger.Error("Error dialing peer", "err", err)
@ -386,11 +397,6 @@ func (sw *Switch) DialPeersAsync(addrBook AddrBook, peers []string, persistent b
// DialPeerWithAddress dials the given peer and runs sw.addPeer if it connects and authenticates successfully. // DialPeerWithAddress dials the given peer and runs sw.addPeer if it connects and authenticates successfully.
// If `persistent == true`, the switch will always try to reconnect to this peer if the connection ever fails. // If `persistent == true`, the switch will always try to reconnect to this peer if the connection ever fails.
func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) error { func (sw *Switch) DialPeerWithAddress(addr *NetAddress, persistent bool) error {
// do not dial ourselves
if sw.addrBook.OurAddress(addr) {
return ErrSwitchConnectToSelf
}
sw.dialing.Set(string(addr.ID), addr) sw.dialing.Set(string(addr.ID), addr)
defer sw.dialing.Delete(string(addr.ID)) defer sw.dialing.Delete(string(addr.ID))
return sw.addOutboundPeerWithConfig(addr, sw.peerConfig, persistent) return sw.addOutboundPeerWithConfig(addr, sw.peerConfig, persistent)
@ -532,9 +538,14 @@ func (sw *Switch) addPeer(pc peerConn) error {
// Avoid self // Avoid self
if sw.nodeKey.ID() == peerID { if sw.nodeKey.ID() == peerID {
// add given address to the address book to avoid dialing ourselves again addr := peerNodeInfo.NetAddress()
// this is our public address
sw.addrBook.AddOurAddress(peerNodeInfo.NetAddress()) // remove the given address from the address book if we're added it earlier
sw.addrBook.RemoveAddress(addr)
// add the given address to the address book to avoid dialing ourselves
// again this is our public address
sw.addrBook.AddOurAddress(addr)
return ErrSwitchConnectToSelf return ErrSwitchConnectToSelf
} }

View File

@ -90,7 +90,9 @@ func MakeSwitchPair(t testing.TB, initSwitch func(int, *Switch) *Switch) (*Switc
} }
func initSwitchFunc(i int, sw *Switch) *Switch { func initSwitchFunc(i int, sw *Switch) *Switch {
sw.SetAddrBook(&addrBookMock{ourAddrs: make(map[string]struct{})}) sw.SetAddrBook(&addrBookMock{
addrs: make(map[string]struct{}, 0),
ourAddrs: make(map[string]struct{}, 0)})
// Make two reactors of two channels each // Make two reactors of two channels each
sw.AddReactor("foo", NewTestReactor([]*conn.ChannelDescriptor{ sw.AddReactor("foo", NewTestReactor([]*conn.ChannelDescriptor{
@ -180,32 +182,24 @@ func TestConnAddrFilter(t *testing.T) {
func TestSwitchFiltersOutItself(t *testing.T) { func TestSwitchFiltersOutItself(t *testing.T) {
s1 := MakeSwitch(config, 1, "127.0.0.2", "123.123.123", initSwitchFunc) s1 := MakeSwitch(config, 1, "127.0.0.2", "123.123.123", initSwitchFunc)
addr := s1.NodeInfo().NetAddress() // addr := s1.NodeInfo().NetAddress()
// add ourselves like we do in node.go#427 // // add ourselves like we do in node.go#427
s1.addrBook.AddOurAddress(addr) // s1.addrBook.AddOurAddress(addr)
// addr should be rejected immediately because of the same IP & port
err := s1.DialPeerWithAddress(addr, false)
if assert.Error(t, err) {
assert.Equal(t, ErrSwitchConnectToSelf, err)
}
// simulate s1 having a public IP by creating a remote peer with the same ID // simulate s1 having a public IP by creating a remote peer with the same ID
rp := &remotePeer{PrivKey: s1.nodeKey.PrivKey, Config: DefaultPeerConfig()} rp := &remotePeer{PrivKey: s1.nodeKey.PrivKey, Config: DefaultPeerConfig()}
rp.Start() rp.Start()
// addr should be rejected in addPeer based on the same ID // addr should be rejected in addPeer based on the same ID
err = s1.DialPeerWithAddress(rp.Addr(), false) err := s1.DialPeerWithAddress(rp.Addr(), false)
if assert.Error(t, err) { if assert.Error(t, err) {
assert.Equal(t, ErrSwitchConnectToSelf, err) assert.Equal(t, ErrSwitchConnectToSelf, err)
} }
// addr should be rejected immediately because during previous step we changed node's public IP assert.True(t, s1.addrBook.OurAddress(rp.Addr()))
err = s1.DialPeerWithAddress(rp.Addr(), false)
if assert.Error(t, err) { assert.False(t, s1.addrBook.HasAddress(rp.Addr()))
assert.Equal(t, ErrSwitchConnectToSelf, err)
}
rp.Stop() rp.Stop()
@ -379,16 +373,27 @@ func BenchmarkSwitchBroadcast(b *testing.B) {
} }
type addrBookMock struct { type addrBookMock struct {
addrs map[string]struct{}
ourAddrs map[string]struct{} ourAddrs map[string]struct{}
} }
var _ AddrBook = (*addrBookMock)(nil) var _ AddrBook = (*addrBookMock)(nil)
func (book *addrBookMock) AddAddress(addr *NetAddress, src *NetAddress) error { return nil } func (book *addrBookMock) AddAddress(addr *NetAddress, src *NetAddress) error {
book.addrs[addr.String()] = struct{}{}
return nil
}
func (book *addrBookMock) AddOurAddress(addr *NetAddress) { book.ourAddrs[addr.String()] = struct{}{} } func (book *addrBookMock) AddOurAddress(addr *NetAddress) { book.ourAddrs[addr.String()] = struct{}{} }
func (book *addrBookMock) OurAddress(addr *NetAddress) bool { func (book *addrBookMock) OurAddress(addr *NetAddress) bool {
_, ok := book.ourAddrs[addr.String()] _, ok := book.ourAddrs[addr.String()]
return ok return ok
} }
func (book *addrBookMock) MarkGood(*NetAddress) {} func (book *addrBookMock) MarkGood(*NetAddress) {}
func (book *addrBookMock) HasAddress(addr *NetAddress) bool {
_, ok := book.addrs[addr.String()]
return ok
}
func (book *addrBookMock) RemoveAddress(addr *NetAddress) {
delete(book.addrs, addr.String())
}
func (book *addrBookMock) Save() {} func (book *addrBookMock) Save() {}