From 7daed851916bba16251a7ce53df673d1150fecaf Mon Sep 17 00:00:00 2001 From: Igor Sirotin Date: Tue, 30 Sep 2025 23:06:40 +0100 Subject: [PATCH] fix: IP, Addr, AddrPort changes --- discover/lookup.go | 6 +++--- discover/metrics.go | 2 +- discover/v4_udp.go | 26 ++++++++++++++------------ discover/v4wire/v4wire.go | 16 ++++++++++------ discover/v5_udp.go | 4 +++- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/discover/lookup.go b/discover/lookup.go index 91ca7a2..cc868bb 100644 --- a/discover/lookup.go +++ b/discover/lookup.go @@ -140,7 +140,7 @@ func (it *lookup) slowdown() { } func (it *lookup) query(n *node, reply chan<- []*node) { - fails := it.tab.db.FindFails(n.ID(), n.IP()) + fails := it.tab.db.FindFails(n.ID(), n.IPAddr()) r, err := it.queryfunc(n) if errors.Is(err, errClosed) { // Avoid recording failures on shutdown. @@ -148,7 +148,7 @@ func (it *lookup) query(n *node, reply chan<- []*node) { return } else if len(r) == 0 { fails++ - it.tab.db.UpdateFindFails(n.ID(), n.IP(), fails) + it.tab.db.UpdateFindFails(n.ID(), n.IPAddr(), fails) // Remove the node from the local table if it fails to return anything useful too // many times, but only if there are enough other nodes in the bucket. if fails >= maxFindnodeFailures && it.tab.bucketLen(n.ID()) >= bucketSize/2 { @@ -156,7 +156,7 @@ func (it *lookup) query(n *node, reply chan<- []*node) { } } else if fails > 0 { // Reset failure counter because it counts _consecutive_ failures. - it.tab.db.UpdateFindFails(n.ID(), n.IP(), 0) + it.tab.db.UpdateFindFails(n.ID(), n.IPAddr(), 0) } // Grab as many nodes as possible. Some of them might not be alive anymore, but we'll diff --git a/discover/metrics.go b/discover/metrics.go index bf1a2fa..f219320 100644 --- a/discover/metrics.go +++ b/discover/metrics.go @@ -44,7 +44,7 @@ type meteredUdpConn struct { func newMeteredConn(conn UDPConn) UDPConn { // Short circuit if metrics are disabled - if !metrics.Enabled { + if !metrics.Enabled() { return conn } return &meteredUdpConn{UDPConn: conn} diff --git a/discover/v4_udp.go b/discover/v4_udp.go index d40b59b..e678397 100644 --- a/discover/v4_udp.go +++ b/discover/v4_udp.go @@ -26,6 +26,7 @@ import ( "fmt" "io" "net" + "net/netip" "sync" "time" @@ -34,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/netutil" + "github.com/waku-org/go-discover/discover/v4wire" ) @@ -242,7 +244,7 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r return matched, matched }) // Send the packet. - t.localNode.UDPContact(toaddr) + t.localNode.UDPContact(toaddr.AddrPort()) t.write(toaddr, toid, req.Name(), packet) return rm } @@ -560,15 +562,15 @@ func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { } // checkBond checks if the given node has a recent enough endpoint proof. -func (t *UDPv4) checkBond(id enode.ID, ip net.IP) bool { - return time.Since(t.db.LastPongReceived(id, ip)) < bondExpiration +func (t *UDPv4) checkBond(id enode.ID, addr netip.Addr) bool { + return time.Since(t.db.LastPongReceived(id, addr)) < bondExpiration } // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. // This ensures there is a valid endpoint proof on the remote end. func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { - tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration - if tooOld || t.db.FindFails(toid, toaddr.IP) > maxFindnodeFailures { + tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.AddrPort().Addr())) > bondExpiration + if tooOld || t.db.FindFails(toid, toaddr.AddrPort().Addr()) > maxFindnodeFailures { rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -668,7 +670,7 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I // Ping back if our last pong on file is too far in the past. n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) - if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { + if time.Since(t.db.LastPongReceived(n.ID(), from.AddrPort().Addr())) > bondExpiration { t.sendPing(fromID, from, func() { t.tab.addVerifiedNode(n) }) @@ -677,8 +679,8 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I } // Update node database and endpoint predictor. - t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now()) - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) + t.db.UpdateLastPingReceived(n.ID(), from.AddrPort().Addr(), time.Now()) + t.localNode.UDPEndpointStatement(from.AddrPort(), req.To.UDPAddrPort()) } // PONG/v4 @@ -692,8 +694,8 @@ func (t *UDPv4) verifyPong(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I if !t.handleReply(fromID, from.IP, req) { return errUnsolicitedReply } - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) - t.db.UpdateLastPongReceived(fromID, from.IP, time.Now()) + t.localNode.UDPEndpointStatement(from.AddrPort(), req.To.UDPAddrPort()) + t.db.UpdateLastPongReceived(fromID, from.AddrPort().Addr(), time.Now()) return nil } @@ -705,7 +707,7 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from.AddrPort().Addr()) { // No endpoint proof pong exists, we don't process the packet. This prevents an // attack vector where the discovery protocol could be used to amplify traffic in a // DDOS attack. A malicious actor would send a findnode request with the IP address @@ -765,7 +767,7 @@ func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID e if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from.AddrPort().Addr()) { return errUnknownNode } return nil diff --git a/discover/v4wire/v4wire.go b/discover/v4wire/v4wire.go index 3935068..dbcbefa 100644 --- a/discover/v4wire/v4wire.go +++ b/discover/v4wire/v4wire.go @@ -25,6 +25,7 @@ import ( "fmt" "math/big" "net" + "net/netip" "time" "github.com/ethereum/go-ethereum/common/math" @@ -151,13 +152,16 @@ type Endpoint struct { // NewEndpoint creates an endpoint. func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { - ip := net.IP{} - if ip4 := addr.IP.To4(); ip4 != nil { - ip = ip4 - } else if ip6 := addr.IP.To16(); ip6 != nil { - ip = ip6 + return Endpoint{ + IP: addr.IP, + UDP: uint16(addr.Port), + TCP: tcpPort, } - return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} +} + +func (ep *Endpoint) UDPAddrPort() netip.AddrPort { + addr, _ := netip.AddrFromSlice(ep.IP) + return netip.AddrPortFrom(addr, ep.UDP) } type Packet interface { diff --git a/discover/v5_udp.go b/discover/v5_udp.go index af0396d..614d78a 100644 --- a/discover/v5_udp.go +++ b/discover/v5_udp.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "net" + "net/netip" "sync" "time" @@ -761,7 +762,8 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) t.handlePing(p, fromID, fromAddr) case *v5wire.Pong: if t.handleCallResponse(fromID, fromAddr, p) { - t.localNode.UDPEndpointStatement(fromAddr, &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)}) + toAddr, _ := netip.AddrFromSlice(p.ToIP) + t.localNode.UDPEndpointStatement(fromAddr.AddrPort(), netip.AddrPortFrom(toAddr, p.ToPort)) } case *v5wire.Findnode: t.handleFindnode(p, fromID, fromAddr)