mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
p2p: avoid node update if DNS lookup returns unchanged IP
This commit is contained in:
parent
8bec25759c
commit
7ffb97c414
1 changed files with 65 additions and 47 deletions
68
p2p/dial.go
68
p2p/dial.go
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -93,6 +94,7 @@ var (
|
||||||
type dialScheduler struct {
|
type dialScheduler struct {
|
||||||
dialConfig
|
dialConfig
|
||||||
setupFunc dialSetupFunc
|
setupFunc dialSetupFunc
|
||||||
|
dnsLookupFunc func(ctx context.Context, network string, name string) ([]netip.Addr, error)
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
@ -164,6 +166,7 @@ func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupF
|
||||||
dialConfig: cfg,
|
dialConfig: cfg,
|
||||||
historyTimer: mclock.NewAlarm(cfg.clock),
|
historyTimer: mclock.NewAlarm(cfg.clock),
|
||||||
setupFunc: setupFunc,
|
setupFunc: setupFunc,
|
||||||
|
dnsLookupFunc: net.DefaultResolver.LookupNetIP,
|
||||||
dialing: make(map[enode.ID]*dialTask),
|
dialing: make(map[enode.ID]*dialTask),
|
||||||
static: make(map[enode.ID]*dialTask),
|
static: make(map[enode.ID]*dialTask),
|
||||||
peers: make(map[enode.ID]struct{}),
|
peers: make(map[enode.ID]struct{}),
|
||||||
|
|
@ -442,37 +445,53 @@ func (d *dialScheduler) dnsResolveHostname(n *enode.Node) (*enode.Node, error) {
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
d.log.Trace("Attempting DNS resolution", "id", n.ID(), "name", n.Hostname())
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
ips, err := net.LookupIP(n.Hostname())
|
defer cancel()
|
||||||
|
foundIPs, err := d.dnsLookupFunc(ctx, "ip", n.Hostname())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
d.log.Debug("DNS lookup succeeded", "id", n.ID(), "name", n.Hostname(), "ipcount", len(ips))
|
|
||||||
|
|
||||||
// Set new IPs in node record.
|
// Check for IP updates.
|
||||||
rec := n.Record()
|
var (
|
||||||
var foundIP bool
|
nodeIP4, nodeIP6 netip.Addr
|
||||||
for _, ip := range ips {
|
foundIP4, foundIP6 netip.Addr
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
)
|
||||||
rec.Set(enr.IPv4(ip4))
|
n.Load((*enr.IPv4Addr)(&nodeIP4))
|
||||||
foundIP = true
|
n.Load((*enr.IPv6Addr)(&nodeIP6))
|
||||||
break
|
for _, ip := range foundIPs {
|
||||||
|
if ip.Is4() && !foundIP4.IsValid() {
|
||||||
|
foundIP4 = ip
|
||||||
}
|
}
|
||||||
}
|
if ip.Is6() && !foundIP6.IsValid() {
|
||||||
for _, ip := range ips {
|
foundIP6 = ip
|
||||||
if ip6 := ip.To16(); ip6 != nil {
|
|
||||||
rec.Set(enr.IPv6(ip6))
|
|
||||||
foundIP = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundIP {
|
if !foundIP4.IsValid() && !foundIP6.IsValid() {
|
||||||
|
// Lookup failed.
|
||||||
return n, errNoResolvedIP
|
return n, errNoResolvedIP
|
||||||
}
|
}
|
||||||
|
if foundIP4 == nodeIP4 && foundIP6 == nodeIP6 {
|
||||||
|
// No updates necessary.
|
||||||
|
d.log.Trace("Node DNS lookup had no update", "id", n.ID(), "name", n.Hostname(), "ip", foundIP4, "ip6", foundIP6)
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Update the node.
|
// Update the node. Note this invalidates the ENR signature, because we use SignNull
|
||||||
|
// to create a modified copy. But this should be OK, since we just use the node as a
|
||||||
|
// dial target. And nodes will usually only have a DNS hostname if they came from a
|
||||||
|
// enode:// URL, which has no signature anyway. If it ever becomes a problem, the
|
||||||
|
// resolved IP could also be stored into dialTask instead of the node.
|
||||||
|
rec := n.Record()
|
||||||
|
if foundIP4.IsValid() {
|
||||||
|
rec.Set(enr.IPv4Addr(foundIP4))
|
||||||
|
}
|
||||||
|
if foundIP6.IsValid() {
|
||||||
|
rec.Set(enr.IPv6Addr(foundIP6))
|
||||||
|
}
|
||||||
newNode := enode.SignNull(rec, n.ID()).WithHostname(n.Hostname())
|
newNode := enode.SignNull(rec, n.ID()).WithHostname(n.Hostname())
|
||||||
|
d.log.Trace("Node updated from DNS lookup", "id", n.ID(), "name", n.Hostname(), "ip", newNode.IP())
|
||||||
return newNode, nil
|
return newNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -518,19 +537,18 @@ func (t *dialTask) dest() *enode.Node {
|
||||||
func (t *dialTask) run(d *dialScheduler) {
|
func (t *dialTask) run(d *dialScheduler) {
|
||||||
if t.isStatic() {
|
if t.isStatic() {
|
||||||
// Resolve DNS.
|
// Resolve DNS.
|
||||||
node := t.dest()
|
if n := t.dest(); n.Hostname() != "" {
|
||||||
if node.Hostname() != "" {
|
resolved, err := d.dnsResolveHostname(n)
|
||||||
resolved, err := d.dnsResolveHostname(node)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.log.Warn("DNS resolve of static node failed", "id", node.ID(), "name", node.Hostname(), "err", err)
|
d.log.Warn("DNS lookup of static node failed", "id", n.ID(), "name", n.Hostname(), "err", err)
|
||||||
} else {
|
} else {
|
||||||
t.destPtr.Store(resolved)
|
t.destPtr.Store(resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try resolving node ID through the DHT if there is no IP address.
|
// Try resolving node ID through the DHT if there is no IP address.
|
||||||
if !node.IPAddr().IsValid() {
|
if !t.dest().IPAddr().IsValid() {
|
||||||
if !t.resolve(d) {
|
if !t.resolve(d) {
|
||||||
return // DHT resolve failed
|
return // DHT resolve failed, skip dial.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue