p2p: use new DNS hostname methods

This commit is contained in:
Felix Lange 2024-12-12 18:09:56 +01:00
parent 83f5e0c5f7
commit cbccd92851

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/p2p/netutil"
) )
@ -275,7 +276,7 @@ loop:
case node := <-d.addStaticCh: case node := <-d.addStaticCh:
id := node.ID() id := node.ID()
_, exists := d.static[id] _, exists := d.static[id]
d.log.Trace("Adding static node", "id", id, "endpoint", node.Endpoint(), "added", !exists) d.log.Trace("Adding static node", "id", id, "endpoint", nodeEndpointForLog(node), "added", !exists)
if exists { if exists {
continue loop continue loop
} }
@ -434,42 +435,51 @@ func (d *dialScheduler) removeFromStaticPool(idx int) {
task.staticPoolIndex = -1 task.staticPoolIndex = -1
} }
func (d *dialScheduler) resolve(n *enode.Node) (*enode.Node, error) { // dnsResolve updates the given node from its DNS hostname.
if n.NeedResolve() { // This is used to resolve static dial targets.
d.log.Debug("Attempting DNS resolution", "id", n.ID(), "name", n.Hostname()) func (d *dialScheduler) dnsResolve(n *enode.Node) (*enode.Node, error) {
if n.Hostname() == "" {
return n, nil
}
d.log.Trace("Attempting DNS resolution", "id", n.ID(), "name", n.Hostname())
ips, err := net.LookupIP(n.Hostname()) ips, err := net.LookupIP(n.Hostname())
if err != nil { if err != nil {
d.log.Debug("DNS resolution failed", "id", n.ID(), "name", n.Hostname(), "err", err)
return n, err return n, err
} }
d.log.Debug("DNS lookup succeeded", "id", n.ID(), "name", n.Hostname(), "ipcount", len(ips)) d.log.Debug("DNS lookup succeeded", "id", n.ID(), "name", n.Hostname(), "ipcount", len(ips))
// Try IPv4 first // Set new IPs in node record.
rec := n.Record()
var foundIP bool
for _, ip := range ips { for _, ip := range ips {
if ip4 := ip.To4(); ip4 != nil { if ip4 := ip.To4(); ip4 != nil {
resolved := enode.NewV4WithDNS(n.Pubkey(), ip4, n.Hostname(), n.TCP(), n.UDP()) rec.Set(enr.IPv4(ip4))
d.log.Debug("DNS resolved to IPv4", "id", n.ID(), "name", n.Hostname(), "ip", ip4) foundIP = true
return resolved, nil break
} }
} }
// Then try IPv6
for _, ip := range ips { for _, ip := range ips {
if ip6 := ip.To16(); ip6 != nil { if ip6 := ip.To16(); ip6 != nil {
resolved := enode.NewV4WithDNS(n.Pubkey(), ip6, n.Hostname(), n.TCP(), n.UDP()) rec.Set(enr.IPv6(ip6))
d.log.Debug("DNS resolved to IPv6", "id", n.ID(), "name", n.Hostname(), "ip", ip6) foundIP = true
return resolved, nil break
} }
} }
d.log.Debug("DNS resolution found no usable IPs", "id", n.ID(), "name", n.Hostname())
if !foundIP {
return n, errNoResolvedIP return n, errNoResolvedIP
} }
return n, nil
// Update the node.
newNode := enode.SignNull(rec, n.ID()).WithHostname(n.Hostname())
return newNode, nil
} }
// startDial runs the given dial task in a separate goroutine. // startDial runs the given dial task in a separate goroutine.
func (d *dialScheduler) startDial(task *dialTask) { func (d *dialScheduler) startDial(task *dialTask) {
node := task.dest() node := task.dest()
d.log.Trace("Starting p2p dial", "id", node.ID(), "endpoint", node.Endpoint(), "flag", task.flags) d.log.Trace("Starting p2p dial", "id", node.ID(), "endpoint", nodeEndpointForLog(node), "flag", task.flags)
hkey := string(node.ID().Bytes()) hkey := string(node.ID().Bytes())
d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration))
d.dialing[node.ID()] = task d.dialing[node.ID()] = task
@ -506,23 +516,30 @@ func (t *dialTask) dest() *enode.Node {
} }
func (t *dialTask) run(d *dialScheduler) { func (t *dialTask) run(d *dialScheduler) {
if t.isStatic() {
// Resolve DNS.
node := t.dest() node := t.dest()
if node.NeedResolve() { if node.Hostname() != "" {
resolved, err := d.resolve(node) resolved, err := d.dnsResolve(node)
if err != nil { if err != nil {
return d.log.Warn("DNS resolve of static node failed", "id", node.ID(), "name", node.Hostname(), "err", err)
} } else {
t.destPtr.Store(resolved) t.destPtr.Store(resolved)
} }
}
if t.needResolve() && !t.resolve(d) { // Try resolving node ID through the DHT if there is no IP address.
return if !node.IPAddr().IsValid() {
if !t.resolve(d) {
return // DHT resolve failed
}
}
} }
err := t.dial(d, t.dest()) err := t.dial(d, t.dest())
if err != nil { if err != nil {
// For static nodes, resolve one more time if dialing fails. // For static nodes, resolve one more time if dialing fails.
if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { var dialErr *dialError
if errors.As(err, &dialErr) && t.isStatic() {
if t.resolve(d) { if t.resolve(d) {
t.dial(d, t.dest()) t.dial(d, t.dest())
} }
@ -530,8 +547,8 @@ func (t *dialTask) run(d *dialScheduler) {
} }
} }
func (t *dialTask) needResolve() bool { func (t *dialTask) isStatic() bool {
return t.flags&staticDialedConn != 0 && !t.dest().IPAddr().IsValid() return t.flags&staticDialedConn != 0
} }
// resolve attempts to find the current endpoint for the destination // resolve attempts to find the current endpoint for the destination
@ -595,3 +612,10 @@ func cleanupDialErr(err error) error {
} }
return err return err
} }
func nodeEndpointForLog(n *enode.Node) string {
if n.Hostname() != "" {
return n.Hostname()
}
return n.IPAddr().String()
}