Skip to content

Commit 7d79567

Browse files
fjljakub-freebit
authored andcommitted
p2p/discover: add liveness check in collectTableNodes (ethereum#28686)
* p2p/discover: add liveness check in collectTableNodes * p2p/discover: fix test * p2p/discover: rename to appendLiveNodes * p2p/discover: add dedup logic back * p2p/discover: simplify * p2p/discover: fix issue found by test
1 parent 7068539 commit 7d79567

File tree

7 files changed

+43
-23
lines changed

7 files changed

+43
-23
lines changed

p2p/discover/table.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,32 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *
462462
return nodes
463463
}
464464

465+
// appendLiveNodes adds nodes at the given distance to the result slice.
466+
func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node {
467+
if dist > 256 {
468+
return result
469+
}
470+
if dist == 0 {
471+
return append(result, tab.self())
472+
}
473+
474+
tab.mutex.Lock()
475+
defer tab.mutex.Unlock()
476+
for _, n := range tab.bucketAtDistance(int(dist)).entries {
477+
// MODIFIED by Jakub Pajek (mobile connectivity)
478+
// WAN bootnodes can not correctly perform a liveness check of mobile nodes
479+
// (Private addresses behind CGNAT are always unreachable from the Internet).
480+
// Unless we explicitly allow unverified mobile nodes here, they will never
481+
// be advertised.
482+
//if n.livenessChecks >= 1 {
483+
if n.livenessChecks >= 1 || netutil.IsMobileLAN(n.IP()) {
484+
node := n.Node // avoid handing out pointer to struct field
485+
result = append(result, &node)
486+
}
487+
}
488+
return result
489+
}
490+
465491
// len returns the number of nodes in the table.
466492
func (tab *Table) len() (n int) {
467493
tab.mutex.Lock()

p2p/discover/table_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func TestTable_findnodeByID(t *testing.T) {
199199
tab, db := newTestTable(transport)
200200
defer db.Close()
201201
defer tab.close()
202-
fillTable(tab, test.All)
202+
fillTable(tab, test.All, true)
203203

204204
// check that closest(Target, N) returns nodes
205205
result := tab.findnodeByID(test.Target, test.N, false).entries

p2p/discover/table_util_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,11 @@ func fillBucket(tab *Table, n *node) (last *node) {
109109

110110
// fillTable adds nodes the table to the end of their corresponding bucket
111111
// if the bucket is not full. The caller must not hold tab.mutex.
112-
func fillTable(tab *Table, nodes []*node) {
112+
func fillTable(tab *Table, nodes []*node, setLive bool) {
113113
for _, n := range nodes {
114+
if setLive {
115+
n.livenessChecks = 1
116+
}
114117
tab.addSeenNode(n)
115118
}
116119
}

p2p/discover/v4_lookup_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestUDPv4_Lookup(t *testing.T) {
4040
}
4141

4242
// Seed table with initial node.
43-
fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))})
43+
fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))}, true)
4444

4545
// Start the lookup.
4646
resultC := make(chan []*enode.Node, 1)
@@ -74,7 +74,7 @@ func TestUDPv4_LookupIterator(t *testing.T) {
7474
for i := range lookupTestnet.dists[256] {
7575
bootnodes[i] = wrapNode(lookupTestnet.node(256, i))
7676
}
77-
fillTable(test.table, bootnodes)
77+
fillTable(test.table, bootnodes, true)
7878
go serveTestnet(test, lookupTestnet)
7979

8080
// Create the iterator and collect the nodes it yields.
@@ -109,7 +109,7 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) {
109109
for i := range lookupTestnet.dists[256] {
110110
bootnodes[i] = wrapNode(lookupTestnet.node(256, i))
111111
}
112-
fillTable(test.table, bootnodes)
112+
fillTable(test.table, bootnodes, true)
113113
go serveTestnet(test, lookupTestnet)
114114

115115
it := test.udp.RandomNodes()

p2p/discover/v4_udp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ func TestUDPv4_findnode(t *testing.T) {
273273
}
274274
nodes.push(n, numCandidates)
275275
}
276-
fillTable(test.table, nodes.entries)
276+
fillTable(test.table, nodes.entries, false)
277277

278278
// ensure there's a bond with the test node,
279279
// findnode won't be accepted otherwise.

p2p/discover/v5_udp.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr *ne
851851

852852
// collectTableNodes creates a FINDNODE result set for the given distances.
853853
func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*enode.Node {
854+
var bn []*enode.Node
854855
var nodes []*enode.Node
855856
var processed = make(map[uint]struct{})
856857
for _, dist := range distances {
@@ -859,21 +860,11 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en
859860
if seen || dist > 256 {
860861
continue
861862
}
862-
863-
// Get the nodes.
864-
var bn []*enode.Node
865-
if dist == 0 {
866-
bn = []*enode.Node{t.Self()}
867-
} else if dist <= 256 {
868-
t.tab.mutex.Lock()
869-
bn = unwrapNodes(t.tab.bucketAtDistance(int(dist)).entries)
870-
t.tab.mutex.Unlock()
871-
}
872863
processed[dist] = struct{}{}
873864

874-
// Apply some pre-checks to avoid sending invalid nodes.
875-
for _, n := range bn {
876-
// TODO livenessChecks > 1
865+
for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) {
866+
// Apply some pre-checks to avoid sending invalid nodes.
867+
// Note liveness is checked by appendLiveNodes.
877868
if netutil.CheckRelayIP(rip, n.IP()) != nil {
878869
continue
879870
}

p2p/discover/v5_udp_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ func TestUDPv5_findnodeHandling(t *testing.T) {
164164
nodes253 := nodesAtDistance(test.table.self().ID(), 253, 16)
165165
nodes249 := nodesAtDistance(test.table.self().ID(), 249, 4)
166166
nodes248 := nodesAtDistance(test.table.self().ID(), 248, 10)
167-
fillTable(test.table, wrapNodes(nodes253))
168-
fillTable(test.table, wrapNodes(nodes249))
169-
fillTable(test.table, wrapNodes(nodes248))
167+
fillTable(test.table, wrapNodes(nodes253), true)
168+
fillTable(test.table, wrapNodes(nodes249), true)
169+
fillTable(test.table, wrapNodes(nodes248), true)
170170

171171
// Requesting with distance zero should return the node's own record.
172172
test.packetIn(&v5wire.Findnode{ReqID: []byte{0}, Distances: []uint{0}})
@@ -594,7 +594,7 @@ func TestUDPv5_lookup(t *testing.T) {
594594

595595
// Seed table with initial node.
596596
initialNode := lookupTestnet.node(256, 0)
597-
fillTable(test.table, []*node{wrapNode(initialNode)})
597+
fillTable(test.table, []*node{wrapNode(initialNode)}, true)
598598

599599
// Start the lookup.
600600
resultC := make(chan []*enode.Node, 1)

0 commit comments

Comments
 (0)