From 010766fe9e3037502f351619ffc7c5f82c5c6487 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 21 Mar 2016 15:22:36 +0000 Subject: [PATCH] Check entries claiming to originate from us against our current data, and override if necessary --- nameserver/entry.go | 20 ++++++++++++++++++-- nameserver/nameserver.go | 25 +++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/nameserver/entry.go b/nameserver/entry.go index cb0830fa..89a48ca7 100644 --- a/nameserver/entry.go +++ b/nameserver/entry.go @@ -105,6 +105,11 @@ func (e1 *Entry) addLowercase() { e1.lHostname = strings.ToLower(e1.Hostname) } +func (e *Entry) tombstone() { + e.Version++ + e.Tombstone = now() +} + func check(es SortableEntries) error { if !sort.IsSorted(es) { return fmt.Errorf("Not sorted!") @@ -182,8 +187,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries tombstoned := Entries{} for i, e := range *es { if f(&e) && e.Origin == ourname { - e.Version++ - e.Tombstone = now() + e.tombstone() (*es)[i] = e tombstoned = append(tombstoned, e) } @@ -191,6 +195,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries return tombstoned } +// note f() may only modify entries such that they remain in order defined by less() func (es *Entries) filter(f func(*Entry) bool) { defer es.checkAndPanic().checkAndPanic() @@ -205,6 +210,17 @@ func (es *Entries) filter(f func(*Entry) bool) { *es = (*es)[:i] } +func (es Entries) findEqual(e *Entry) (*Entry, bool) { + i := sort.Search(len(es), func(i int) bool { + return !es[i].insensitiveLess(e) + }) + if i < len(es) && es[i].equal(*e) { + return &es[i], true + } else { + return nil, false + } +} + func (es Entries) lookup(hostname string) Entries { es.checkAndPanic() diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index 806db03b..002c7f29 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -203,16 +203,33 @@ func (n *Nameserver) receiveGossip(msg []byte) (mesh.GossipData, mesh.GossipData return nil, nil, fmt.Errorf("clock skew of %d detected", delta) } - n.Lock() - isKnownPeer := n.isKnownPeer - n.Unlock() // Don't hold the lock over call out to code elsewhere + // Filter to remove entries from unknown peers, done before we take + // the nameserver lock, so we don't have to worry what isKnownPeer locks. gossip.Entries.filter(func(e *Entry) bool { - return isKnownPeer(e.Origin) + return n.isKnownPeer(e.Origin) }) n.Lock() defer n.Unlock() + // Check entries claiming to originate from us against our current data + gossip.Entries.filter(func(e *Entry) bool { + if e.Origin == n.ourName { + if ourEntry, ok := n.entries.findEqual(e); ok { + if ourEntry.Version < e.Version || + (ourEntry.Version == e.Version && ourEntry.Tombstone != e.Tombstone) { + // Take our version of the data, but make the version higher than the incoming + nextVersion := e.Version + 1 + *e = *ourEntry + e.Version = nextVersion + } + } else { // We have no entry matching the one that came in with us as Origin + e.tombstone() + } + } + return true + }) + newEntries := n.entries.merge(gossip.Entries) if len(newEntries) > 0 { return &GossipData{Entries: newEntries, Timestamp: now()}, &gossip, nil