chore: resolving DNS IP and publishing it when no extIp is provided (#2030)

This commit is contained in:
gabrielmer 2023-09-27 16:02:24 +03:00 committed by GitHub
parent 89854a96f6
commit 7797b2cd03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 8 deletions

View File

@ -1,9 +1,12 @@
import
std/options,
stew/shims/net,
stew/results,
chronicles,
chronos,
libp2p/crypto/crypto,
libp2p/multiaddress
libp2p/multiaddress,
libp2p/nameresolving/dnsresolver,
std/options,
stew/results,
stew/shims/net
import
../../waku/common/utils/nat,
../../waku/node/config,
@ -18,6 +21,23 @@ proc validateExtMultiAddrs*(vals: seq[string]):
multiaddrs.add(multiaddr)
return ok(multiaddrs)
proc dnsResolve*(domain: string, conf: WakuNodeConf): Future[Result[string, string]] {.async} =
# Use conf's DNS servers
var nameServers: seq[TransportAddress]
for ip in conf.dnsAddrsNameServers:
nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53
let dnsResolver = DnsResolver.new(nameServers)
# Resolve domain IP
let resolved = await dnsResolver.resolveIp(domain, 0.Port, Domain.AF_UNSPEC)
if resolved.len > 0:
return ok(resolved[0].host) # Use only first answer
else:
return err("Could not resolve IP from DNS: empty response")
proc networkConfiguration*(conf: WakuNodeConf,
clientId: string,
): NetConfigResult =
@ -30,7 +50,7 @@ proc networkConfiguration*(conf: WakuNodeConf,
if natRes.isErr():
return err("failed to setup NAT: " & $natRes.error)
let (extIp, extTcpPort, _) = natRes.get()
var (extIp, extTcpPort, _) = natRes.get()
let
dns4DomainName = if conf.dns4DomainName != "": some(conf.dns4DomainName)
@ -69,6 +89,18 @@ proc networkConfiguration*(conf: WakuNodeConf,
relay = conf.relay
)
# Resolve and use DNS domain IP
if dns4DomainName.isSome() and extIp.isNone():
try:
let dnsRes = waitFor dnsResolve(conf.dns4DomainName, conf)
if dnsRes.isErr():
return err($dnsRes.error) # Pass error down the stack
extIp = some(ValidIpAddress.init(dnsRes.get()))
except CatchableError:
return err("Could not update extIp to resolved DNS IP: " & getCurrentExceptionMsg())
# Wrap in none because NetConfig does not have a default constructor
# TODO: We could change bindIp in NetConfig to be something less restrictive
# than ValidIpAddress, which doesn't allow default construction

View File

@ -1,7 +1,7 @@
{.used.}
import
std/sequtils,
std/[sequtils,strutils],
stew/byteutils,
stew/shims/net as stewNet,
testutils/unittests,
@ -215,6 +215,65 @@ suite "WakuNode":
node.announcedAddresses.len == 1
node.announcedAddresses.contains(expectedDns4Addr)
asyncTest "Node uses dns4 resolved ip in announced addresses if no extIp is provided":
let
nodeKey = generateSecp256k1Key()
bindIp = ValidIpAddress.init("0.0.0.0")
bindPort = Port(0)
domainName = "status.im"
node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(domainName))
var ipStr = ""
var enrIp = node.enr.tryGet("ip", array[4, byte])
if enrIp.isSome():
ipStr &= $ipv4(enrIp.get())
# Check that the IP filled is the one received by the DNS lookup
# As IPs may change, we check that it's not empty, not the 0 IP and not localhost
check:
ipStr.len() > 0
not ipStr.contains("0.0.0.0")
not ipStr.contains("127.0.0.1")
asyncTest "Node creation fails when invalid dns4 address is provided":
let
nodeKey = generateSecp256k1Key()
bindIp = ValidIpAddress.init("0.0.0.0")
bindPort = Port(0)
inexistentDomain = "thisdomain.doesnot.exist"
invalidDomain = ""
expectedError = "Could not resolve IP from DNS: empty response"
var inexistentDomainErr, invalidDomainErr: string = ""
# Create node with inexistent domain
try:
let node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(inexistentDomain))
except Exception as e:
inexistentDomainErr = e.msg
# Create node with invalid domain
try:
let node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(invalidDomain))
except Exception as e:
invalidDomainErr = e.msg
# Check that exceptions were raised in both cases
check:
inexistentDomainErr == expectedError
invalidDomainErr == expectedError
asyncTest "Agent string is set and advertised correctly":
let

View File

@ -13,6 +13,8 @@ import
../../../waku/node/peer_manager,
../../../waku/waku_enr,
../../../waku/waku_discv5,
../../apps/wakunode2/internal_config,
../wakunode2/test_app,
./common
@ -38,10 +40,29 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
discv5UdpPort = none(Port),
agentString = none(string),
peerStoreCapacity = none(int)): WakuNode =
var resolvedExtIp = extIp
# Update extPort to default value if it's missing and there's an extIp or a DNS domain
let extPort = if (extIp.isSome() or dns4DomainName.isSome()) and
extPort.isNone():
some(Port(60000))
else:
extPort
if dns4DomainName.isSome() and extIp.isNone():
let conf = defaultTestWakuNodeConf()
# If there's an error resolving the IP, an exception is thrown and test fails
let dnsRes = waitFor dnsResolve(dns4DomainName.get(), conf)
if dnsRes.isErr():
raise newException(Defect, $dnsRes.error)
else:
resolvedExtIp = some(ValidIpAddress.init(dnsRes.get()))
let netConfigRes = NetConfig.init(
bindIp = bindIp,
bindPort = bindPort,
extIp = extIp,
extIp = resolvedExtIp,
extPort = extPort,
extMultiAddrs = extMultiAddrs,
wsBindPort = wsBindPort,

View File

@ -15,12 +15,13 @@ import
../testlib/common,
../testlib/wakucore
proc defaultTestWakuNodeConf(): WakuNodeConf =
proc defaultTestWakuNodeConf*(): WakuNodeConf =
WakuNodeConf(
listenAddress: ValidIpAddress.init("127.0.0.1"),
rpcAddress: ValidIpAddress.init("127.0.0.1"),
restAddress: ValidIpAddress.init("127.0.0.1"),
metricsServerAddress: ValidIpAddress.init("127.0.0.1"),
dnsAddrsNameServers: @[ValidIpAddress.init("1.1.1.1"), ValidIpAddress.init("1.0.0.1")],
nat: "any",
maxConnections: 50,
topics: @["/waku/2/default-waku/proto"],