Skip to content

Commit 9fd76e3

Browse files
authored
Merge pull request #16109 from karalabe/p2p-bond-check
p2p/discover: validate bond against lastpong, not db presence
2 parents 4e61ed0 + aeedec4 commit 9fd76e3

File tree

5 files changed

+26
-25
lines changed

5 files changed

+26
-25
lines changed

p2p/discover/database.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func (db *nodeDB) expireNodes() error {
257257
}
258258
// Skip the node if not expired yet (and not self)
259259
if !bytes.Equal(id[:], db.self[:]) {
260-
if seen := db.lastPong(id); seen.After(threshold) {
260+
if seen := db.bondTime(id); seen.After(threshold) {
261261
continue
262262
}
263263
}
@@ -278,13 +278,18 @@ func (db *nodeDB) updateLastPing(id NodeID, instance time.Time) error {
278278
return db.storeInt64(makeKey(id, nodeDBDiscoverPing), instance.Unix())
279279
}
280280

281-
// lastPong retrieves the time of the last successful contact from remote node.
282-
func (db *nodeDB) lastPong(id NodeID) time.Time {
281+
// bondTime retrieves the time of the last successful pong from remote node.
282+
func (db *nodeDB) bondTime(id NodeID) time.Time {
283283
return time.Unix(db.fetchInt64(makeKey(id, nodeDBDiscoverPong)), 0)
284284
}
285285

286-
// updateLastPong updates the last time a remote node successfully contacted.
287-
func (db *nodeDB) updateLastPong(id NodeID, instance time.Time) error {
286+
// hasBond reports whether the given node is considered bonded.
287+
func (db *nodeDB) hasBond(id NodeID) bool {
288+
return time.Since(db.bondTime(id)) < nodeDBNodeExpiration
289+
}
290+
291+
// updateBondTime updates the last pong time of a node.
292+
func (db *nodeDB) updateBondTime(id NodeID, instance time.Time) error {
288293
return db.storeInt64(makeKey(id, nodeDBDiscoverPong), instance.Unix())
289294
}
290295

@@ -327,7 +332,7 @@ seek:
327332
if n.ID == db.self {
328333
continue seek
329334
}
330-
if now.Sub(db.lastPong(n.ID)) > maxAge {
335+
if now.Sub(db.bondTime(n.ID)) > maxAge {
331336
continue seek
332337
}
333338
for i := range nodes {

p2p/discover/database_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ func TestNodeDBFetchStore(t *testing.T) {
125125
t.Errorf("ping: value mismatch: have %v, want %v", stored, inst)
126126
}
127127
// Check fetch/store operations on a node pong object
128-
if stored := db.lastPong(node.ID); stored.Unix() != 0 {
128+
if stored := db.bondTime(node.ID); stored.Unix() != 0 {
129129
t.Errorf("pong: non-existing object: %v", stored)
130130
}
131-
if err := db.updateLastPong(node.ID, inst); err != nil {
131+
if err := db.updateBondTime(node.ID, inst); err != nil {
132132
t.Errorf("pong: failed to update: %v", err)
133133
}
134-
if stored := db.lastPong(node.ID); stored.Unix() != inst.Unix() {
134+
if stored := db.bondTime(node.ID); stored.Unix() != inst.Unix() {
135135
t.Errorf("pong: value mismatch: have %v, want %v", stored, inst)
136136
}
137137
// Check fetch/store operations on a node findnode-failure object
@@ -224,8 +224,8 @@ func TestNodeDBSeedQuery(t *testing.T) {
224224
if err := db.updateNode(seed.node); err != nil {
225225
t.Fatalf("node %d: failed to insert: %v", i, err)
226226
}
227-
if err := db.updateLastPong(seed.node.ID, seed.pong); err != nil {
228-
t.Fatalf("node %d: failed to insert lastPong: %v", i, err)
227+
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
228+
t.Fatalf("node %d: failed to insert bondTime: %v", i, err)
229229
}
230230
}
231231

@@ -332,8 +332,8 @@ func TestNodeDBExpiration(t *testing.T) {
332332
if err := db.updateNode(seed.node); err != nil {
333333
t.Fatalf("node %d: failed to insert: %v", i, err)
334334
}
335-
if err := db.updateLastPong(seed.node.ID, seed.pong); err != nil {
336-
t.Fatalf("node %d: failed to update pong: %v", i, err)
335+
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
336+
t.Fatalf("node %d: failed to update bondTime: %v", i, err)
337337
}
338338
}
339339
// Expire some of them, and check the rest
@@ -365,8 +365,8 @@ func TestNodeDBSelfExpiration(t *testing.T) {
365365
if err := db.updateNode(seed.node); err != nil {
366366
t.Fatalf("node %d: failed to insert: %v", i, err)
367367
}
368-
if err := db.updateLastPong(seed.node.ID, seed.pong); err != nil {
369-
t.Fatalf("node %d: failed to update pong: %v", i, err)
368+
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
369+
t.Fatalf("node %d: failed to update bondTime: %v", i, err)
370370
}
371371
}
372372
// Expire the nodes and make sure self has been evacuated too

p2p/discover/table.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ func (tab *Table) loadSeedNodes(bond bool) {
455455
}
456456
for i := range seeds {
457457
seed := seeds[i]
458-
age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.lastPong(seed.ID)) }}
458+
age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.bondTime(seed.ID)) }}
459459
log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age)
460460
tab.add(seed)
461461
}
@@ -596,7 +596,7 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
596596
}
597597
// Start bonding if we haven't seen this node for a while or if it failed findnode too often.
598598
node, fails := tab.db.node(id), tab.db.findFails(id)
599-
age := time.Since(tab.db.lastPong(id))
599+
age := time.Since(tab.db.bondTime(id))
600600
var result error
601601
if fails > 0 || age > nodeDBNodeExpiration {
602602
log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age)
@@ -663,7 +663,7 @@ func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error {
663663
if err := tab.net.ping(id, addr); err != nil {
664664
return err
665665
}
666-
tab.db.updateLastPong(id, time.Now())
666+
tab.db.updateBondTime(id, time.Now())
667667
return nil
668668
}
669669

p2p/discover/udp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte
613613
if expired(req.Expiration) {
614614
return errExpired
615615
}
616-
if t.db.node(fromID) == nil {
616+
if !t.db.hasBond(fromID) {
617617
// No bond exists, we don't process the packet. This prevents
618618
// an attack vector where the discovery protocol could be used
619619
// to amplify traffic in a DDOS attack. A malicious actor

p2p/discover/udp_test.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,8 @@ func TestUDP_findnode(t *testing.T) {
247247

248248
// ensure there's a bond with the test node,
249249
// findnode won't be accepted otherwise.
250-
test.table.db.updateNode(NewNode(
251-
PubkeyID(&test.remotekey.PublicKey),
252-
test.remoteaddr.IP,
253-
uint16(test.remoteaddr.Port),
254-
99,
255-
))
250+
test.table.db.updateBondTime(PubkeyID(&test.remotekey.PublicKey), time.Now())
251+
256252
// check that closest neighbors are returned.
257253
test.packetIn(nil, findnodePacket, &findnode{Target: testTarget, Expiration: futureExp})
258254
expected := test.table.closest(targetHash, bucketSize)

0 commit comments

Comments
 (0)