Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions apps/wakunode2/internal_config.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import
chronicles,
chronos,
libp2p/crypto/crypto,
libp2p/multiaddress,
gabrielmer marked this conversation as resolved.
Show resolved Hide resolved
libp2p/nameresolving/dnsresolver,
std/options,
stew/shims/net,
stew/results,
libp2p/crypto/crypto,
libp2p/multiaddress
stew/shims/net
import
../../waku/common/utils/nat,
../../waku/node/config,
Expand All @@ -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)
gabrielmer marked this conversation as resolved.
Show resolved Hide resolved

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 =
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
61 changes: 60 additions & 1 deletion tests/test_wakunode.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{.used.}

import
std/sequtils,
std/[sequtils,strutils],
stew/byteutils,
stew/shims/net as stewNet,
testutils/unittests,
Expand Down Expand Up @@ -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
Expand Down
23 changes: 22 additions & 1 deletion tests/testlib/wakunode.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import
../../../waku/node/peer_manager,
../../../waku/waku_enr,
../../../waku/waku_discv5,
../../apps/wakunode2/internal_config,
../wakunode2/test_app,
./common


Expand All @@ -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
gabrielmer marked this conversation as resolved.
Show resolved Hide resolved
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,
Expand Down
3 changes: 2 additions & 1 deletion tests/wakunode2/test_app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")],
gabrielmer marked this conversation as resolved.
Show resolved Hide resolved
nat: "any",
maxConnections: 50,
topics: @["/waku/2/default-waku/proto"],
Expand Down
Loading