Skip to content

Commit bffd1a0

Browse files
authored
Merge pull request #2681 from CortexFoundation/dev
host name resloved
2 parents fa68054 + 5bcecf1 commit bffd1a0

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

p2p/discover/table.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ package discover
2525
import (
2626
"context"
2727
"fmt"
28+
"net"
2829
"net/netip"
2930
"slices"
3031
"sync"
@@ -36,6 +37,7 @@ import (
3637
"github.com/CortexFoundation/CortexTheseus/log"
3738
"github.com/CortexFoundation/CortexTheseus/metrics"
3839
"github.com/CortexFoundation/CortexTheseus/p2p/enode"
40+
"github.com/CortexFoundation/CortexTheseus/p2p/enr"
3941
"github.com/CortexFoundation/CortexTheseus/p2p/netutil"
4042
)
4143

@@ -205,6 +207,13 @@ func (tab *Table) close() {
205207
func (tab *Table) setFallbackNodes(nodes []*enode.Node) error {
206208
nursery := make([]*enode.Node, 0, len(nodes))
207209
for _, n := range nodes {
210+
if n.Hostname() != "" && !n.IPAddr().IsValid() {
211+
resolved, err := resolveBootnodeHostname(n, tab.log)
212+
if err != nil {
213+
return fmt.Errorf("bad bootstrap node %q: %v", n, err)
214+
}
215+
n = resolved
216+
}
208217
if err := n.ValidateComplete(); err != nil {
209218
return fmt.Errorf("bad bootstrap node %q: %v", n, err)
210219
}
@@ -218,6 +227,42 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error {
218227
return nil
219228
}
220229

230+
// resolveBootnodeHostname resolves the DNS hostname of a bootstrap node to an IP address.
231+
func resolveBootnodeHostname(n *enode.Node, logger log.Logger) (*enode.Node, error) {
232+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
233+
defer cancel()
234+
235+
ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", n.Hostname())
236+
if err != nil {
237+
return nil, fmt.Errorf("DNS lookup failed for %q: %v", n.Hostname(), err)
238+
}
239+
240+
var ip4, ip6 netip.Addr
241+
for _, ip := range ips {
242+
if ip.Is4() && !ip4.IsValid() {
243+
ip4 = ip
244+
}
245+
if ip.Is6() && !ip6.IsValid() {
246+
ip6 = ip
247+
}
248+
}
249+
if !ip4.IsValid() && !ip6.IsValid() {
250+
return nil, fmt.Errorf("no IP addresses found for hostname %q", n.Hostname())
251+
}
252+
253+
rec := n.Record()
254+
if ip4.IsValid() {
255+
rec.Set(enr.IPv4Addr(ip4))
256+
}
257+
if ip6.IsValid() {
258+
rec.Set(enr.IPv6Addr(ip6))
259+
}
260+
rec.SetSeq(n.Seq())
261+
resolved := enode.SignNull(rec, n.ID()).WithHostname(n.Hostname())
262+
logger.Debug("Resolved bootstrap node hostname", "name", n.Hostname(), "ip", resolved.IP())
263+
return resolved, nil
264+
}
265+
221266
// isInitDone returns whether the table's initial seeding procedure has completed.
222267
func (tab *Table) isInitDone() bool {
223268
select {

p2p/discover/table_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,66 @@ func quickcfg() *quick.Config {
490490
}
491491
}
492492

493+
func TestSetFallbackNodes_DNSHostname(t *testing.T) {
494+
// Create a node with a DNS hostname but no IP, simulating an enode URL
495+
// like enode://<key>@localhost:30303.
496+
key := newkey()
497+
node := enode.NewV4(&key.PublicKey, nil, 30303, 30303).WithHostname("localhost")
498+
499+
// Verify the node has a hostname but no valid IP.
500+
if node.Hostname() != "localhost" {
501+
t.Fatal("expected hostname to be set")
502+
}
503+
if node.IPAddr().IsValid() {
504+
t.Fatal("expected no IP address")
505+
}
506+
507+
// Create a table and set the hostname node as a bootnode.
508+
// This should resolve the hostname to an IP address.
509+
db, _ := enode.OpenDB(t.TempDir() + "/node.db")
510+
defer db.Close()
511+
512+
cfg := Config{Log: testlog.Logger(t, log.LvlTrace)}
513+
cfg = cfg.withDefaults()
514+
tab := &Table{
515+
cfg: cfg,
516+
log: cfg.Log,
517+
refreshReq: make(chan chan struct{}),
518+
revalResponseCh: make(chan revalidationResponse),
519+
addNodeCh: make(chan addNodeOp),
520+
addNodeHandled: make(chan bool),
521+
trackRequestCh: make(chan trackRequestOp),
522+
initDone: make(chan struct{}),
523+
closeReq: make(chan struct{}),
524+
closed: make(chan struct{}),
525+
ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit},
526+
}
527+
for i := range tab.buckets {
528+
tab.buckets[i] = &bucket{
529+
index: i,
530+
ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit},
531+
}
532+
}
533+
534+
err := tab.setFallbackNodes([]*enode.Node{node})
535+
if err != nil {
536+
t.Fatalf("setFallbackNodes failed: %v", err)
537+
}
538+
if len(tab.nursery) != 1 {
539+
t.Fatalf("expected 1 nursery node, got %d", len(tab.nursery))
540+
}
541+
542+
// The resolved node should have a valid IP and retain the hostname.
543+
resolved := tab.nursery[0]
544+
if !resolved.IPAddr().IsValid() {
545+
t.Fatal("expected resolved node to have a valid IP")
546+
}
547+
if resolved.Hostname() != "localhost" {
548+
t.Errorf("expected hostname to be preserved, got %q", resolved.Hostname())
549+
}
550+
t.Logf("resolved localhost to %v", resolved.IPAddr())
551+
}
552+
493553
func newkey() *ecdsa.PrivateKey {
494554
key, err := crypto.GenerateKey()
495555
if err != nil {

0 commit comments

Comments
 (0)