252 lines
11 KiB
Nim
252 lines
11 KiB
Nim
{.used.}
|
|
|
|
# Nim-Libp2p
|
|
# Copyright (c) 2023 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
|
|
import std/[strutils, sequtils, tables]
|
|
import chronos
|
|
import ../libp2p/[stream/connection,
|
|
transports/tcptransport,
|
|
upgrademngrs/upgrade,
|
|
multiaddress,
|
|
nameresolving/nameresolver,
|
|
nameresolving/dnsresolver,
|
|
nameresolving/mockresolver]
|
|
|
|
import ./helpers
|
|
#
|
|
#Cloudflare
|
|
const fallbackDnsServers = @[
|
|
initTAddress("1.1.1.1:53"),
|
|
initTAddress("1.0.0.1:53"),
|
|
initTAddress("[2606:4700:4700::1111]:53")
|
|
]
|
|
|
|
const unixPlatform = defined(linux) or defined(solaris) or
|
|
defined(macosx) or defined(freebsd) or
|
|
defined(netbsd) or defined(openbsd) or
|
|
defined(dragonfly)
|
|
|
|
|
|
proc guessOsNameServers(): seq[TransportAddress] =
|
|
when unixPlatform:
|
|
var resultSeq = newSeqOfCap[TransportAddress](3)
|
|
try:
|
|
for l in lines("/etc/resolv.conf"):
|
|
let lineParsed = l.strip().split(seps = Whitespace + {'%'}, maxsplit = 2)
|
|
if lineParsed.len < 2: continue
|
|
if lineParsed[0].startsWith('#'): continue
|
|
|
|
if lineParsed[0] == "nameserver":
|
|
resultSeq.add(initTAddress(lineParsed[1], Port(53)))
|
|
|
|
if resultSeq.len > 2: break #3 nameserver max on linux
|
|
except CatchableError as err:
|
|
echo "Failed to get unix nameservers ", err.msg
|
|
finally:
|
|
if resultSeq.len > 0:
|
|
return resultSeq
|
|
return fallbackDnsServers
|
|
elif defined(windows):
|
|
#TODO
|
|
return fallbackDnsServers
|
|
else:
|
|
return fallbackDnsServers
|
|
|
|
|
|
suite "Name resolving":
|
|
suite "Generic Resolving":
|
|
var resolver {.threadvar.}: MockResolver
|
|
|
|
proc testOne(input: string, output: seq[MultiAddress]): bool =
|
|
let resolved = waitFor resolver.resolveMAddress(MultiAddress.init(input).tryGet())
|
|
if resolved != output:
|
|
echo "Expected ", output
|
|
echo "Got ", resolved
|
|
return false
|
|
return true
|
|
|
|
proc testOne(input: string, output: seq[string]): bool =
|
|
testOne(input, output.mapIt(MultiAddress.init(it).tryGet()))
|
|
|
|
proc testOne(input, output: string): bool =
|
|
testOne(input, @[MultiAddress.init(output).tryGet()])
|
|
|
|
asyncSetup:
|
|
resolver = MockResolver.new()
|
|
|
|
asyncTest "test multi address dns resolve":
|
|
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"]
|
|
resolver.ipResponses[("localhost", true)] = @["::1"]
|
|
|
|
check testOne("/dns/localhost/udp/0", @["/ip4/127.0.0.1/udp/0", "/ip6/::1/udp/0"])
|
|
check testOne("/dns4/localhost/tcp/0", "/ip4/127.0.0.1/tcp/0")
|
|
check testOne("/dns6/localhost/tcp/0", "/ip6/::1/tcp/0")
|
|
check testOne("/dns6/localhost/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", "/ip6/::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN")
|
|
|
|
asyncTest "test non dns resolve":
|
|
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"]
|
|
resolver.ipResponses[("localhost", true)] = @["::1"]
|
|
|
|
check testOne("/ip6/::1/tcp/0", "/ip6/::1/tcp/0")
|
|
|
|
asyncTest "dnsaddr recursive test":
|
|
resolver.txtResponses["_dnsaddr.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb"
|
|
]
|
|
|
|
resolver.txtResponses["_dnsaddr.sjc-1.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"dnsaddr=/ip4/147.75.69.143/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"
|
|
]
|
|
|
|
resolver.txtResponses["_dnsaddr.ams-2.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/ip4/147.75.83.83/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
|
"dnsaddr=/ip6/2604:1380:2000:7a00::1/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb"
|
|
]
|
|
|
|
check testOne("/dnsaddr/bootstrap.libp2p.io/", @[
|
|
"/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"/ip4/147.75.69.143/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"/ip4/147.75.83.83/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
|
"/ip6/2604:1380:2000:7a00::1/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
|
])
|
|
|
|
asyncTest "dnsaddr suffix matching test":
|
|
resolver.txtResponses["_dnsaddr.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/tcp/4001/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
|
"dnsaddr=/dnsaddr/sjc-1.bootstrap.libp2p.io/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/tcp/4001/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
|
|
"dnsaddr=/dnsaddr/ewr-1.bootstrap.libp2p.io/tcp/4001/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
|
|
]
|
|
|
|
resolver.txtResponses["_dnsaddr.sjc-1.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/ip4/147.75.69.143/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"dnsaddr=/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
]
|
|
|
|
resolver.txtResponses["_dnsaddr.ams-1.bootstrap.libp2p.io"] = @[
|
|
"dnsaddr=/ip4/147.75.69.143/tcp/4001/p2p/shouldbefiltered",
|
|
"dnsaddr=/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/shouldbefiltered",
|
|
]
|
|
|
|
check testOne("/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", @[
|
|
"/ip4/147.75.69.143/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
"/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
])
|
|
|
|
asyncTest "dnsaddr infinite recursion":
|
|
resolver.txtResponses["_dnsaddr.bootstrap.libp2p.io"] = @["dnsaddr=/dnsaddr/bootstrap.libp2p.io"]
|
|
|
|
check testOne("/dnsaddr/bootstrap.libp2p.io/", newSeq[string]())
|
|
|
|
test "getHostname":
|
|
check:
|
|
MultiAddress.init("/dnsaddr/bootstrap.libp2p.io/").tryGet().getHostname == "bootstrap.libp2p.io"
|
|
MultiAddress.init("/ip4/147.75.69.143/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN").tryGet().getHostname == "147.75.69.143"
|
|
MultiAddress.init("/ip6/2604:1380:1000:6000::1/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN").tryGet().getHostname == "2604:1380:1000:6000::1"
|
|
MultiAddress.init("/dns/localhost/udp/0").tryGet().getHostname == "localhost"
|
|
MultiAddress.init("/dns4/hello.com/udp/0").tryGet().getHostname == "hello.com"
|
|
MultiAddress.init("/dns6/hello.com/udp/0").tryGet().getHostname == "hello.com"
|
|
MultiAddress.init("/wss/").tryGet().getHostname == ""
|
|
|
|
suite "DNS Resolving":
|
|
teardown:
|
|
checkTrackers()
|
|
|
|
asyncTest "test manual dns ip resolve":
|
|
## DNS mock server
|
|
proc clientMark1(transp: DatagramTransport,
|
|
raddr: TransportAddress): Future[void] {.async.} =
|
|
var msg = transp.getMessage()
|
|
let
|
|
resp = if msg[24] == 1: #AAAA or A
|
|
"\xae\xbf\x81\x80\x00\x01\x00\x03\x00\x00\x00\x00\x06\x73\x74\x61" &
|
|
"\x74\x75\x73\x02\x69\x6d\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\x68\x16\x18\xb5\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\xac\x43\x0a\xa1\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\x68\x16\x19\xb5"
|
|
else:
|
|
"\xe8\xc5\x81\x80\x00\x01\x00\x03\x00\x00\x00\x00\x06\x73\x74\x61" &
|
|
"\x74\x75\x73\x02\x69\x6d\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x10\x26\x06\x47\x00\x00\x10\x00\x00\x00" &
|
|
"\x00\x00\x00\x68\x16\x19\xb5\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00" &
|
|
"\x4f\x00\x10\x26\x06\x47\x00\x00\x10\x00\x00\x00\x00\x00\x00\x68" &
|
|
"\x16\x18\xb5\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00\x4f\x00\x10\x26" &
|
|
"\x06\x47\x00\x00\x10\x00\x00\x00\x00\x00\x00\xac\x43\x0a\xa1"
|
|
await transp.sendTo(raddr, resp)
|
|
|
|
let server = newDatagramTransport(clientMark1)
|
|
|
|
# The test
|
|
var dnsresolver = DnsResolver.new(@[server.localAddress])
|
|
|
|
check await(dnsresolver.resolveIp("status.im", 0.Port, Domain.AF_UNSPEC)) ==
|
|
mapIt(
|
|
@["104.22.24.181:0", "172.67.10.161:0", "104.22.25.181:0",
|
|
"[2606:4700:10::6816:19b5]:0", "[2606:4700:10::6816:18b5]:0", "[2606:4700:10::ac43:aa1]:0"
|
|
], initTAddress(it))
|
|
check await(dnsresolver.resolveIp("status.im", 0.Port, Domain.AF_INET)) ==
|
|
mapIt(@["104.22.24.181:0", "172.67.10.161:0", "104.22.25.181:0"], initTAddress(it))
|
|
check await(dnsresolver.resolveIp("status.im", 0.Port, Domain.AF_INET6)) ==
|
|
mapIt(@["[2606:4700:10::6816:19b5]:0", "[2606:4700:10::6816:18b5]:0", "[2606:4700:10::ac43:aa1]:0"], initTAddress(it))
|
|
|
|
await server.closeWait()
|
|
|
|
asyncTest "test unresponsive dns server":
|
|
var unresponsiveTentatives = 0
|
|
## DNS mock server
|
|
proc clientMark1(transp: DatagramTransport,
|
|
raddr: TransportAddress): Future[void] {.async.} =
|
|
unresponsiveTentatives.inc()
|
|
check unresponsiveTentatives == 1
|
|
|
|
proc clientMark2(transp: DatagramTransport,
|
|
raddr: TransportAddress): Future[void] {.async.} =
|
|
var msg = transp.getMessage()
|
|
let resp =
|
|
"\xae\xbf\x81\x80\x00\x01\x00\x03\x00\x00\x00\x00\x06\x73\x74\x61" &
|
|
"\x74\x75\x73\x02\x69\x6d\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\x68\x16\x18\xb5\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\xac\x43\x0a\xa1\xc0\x0c\x00\x01\x00" &
|
|
"\x01\x00\x00\x00\x4f\x00\x04\x68\x16\x19\xb5"
|
|
await transp.sendTo(raddr, resp)
|
|
|
|
let
|
|
unresponsiveServer = newDatagramTransport(clientMark1)
|
|
server = newDatagramTransport(clientMark2)
|
|
|
|
# The test
|
|
var dnsresolver = DnsResolver.new(@[unresponsiveServer.localAddress, server.localAddress])
|
|
|
|
check await(dnsresolver.resolveIp("status.im", 0.Port, Domain.AF_INET)) ==
|
|
mapIt(@["104.22.24.181:0", "172.67.10.161:0", "104.22.25.181:0"], initTAddress(it))
|
|
|
|
check await(dnsresolver.resolveIp("status.im", 0.Port, Domain.AF_INET)) ==
|
|
mapIt(@["104.22.24.181:0", "172.67.10.161:0", "104.22.25.181:0"], initTAddress(it))
|
|
|
|
await server.closeWait()
|
|
await unresponsiveServer.closeWait()
|
|
|
|
asyncTest "inexisting domain resolving":
|
|
var dnsresolver = DnsResolver.new(guessOsNameServers())
|
|
let invalid = await dnsresolver.resolveIp("thisdomain.doesnot.exist", 0.Port)
|
|
check invalid.len == 0
|
|
|
|
asyncTest "wrong domain resolving":
|
|
var dnsresolver = DnsResolver.new(guessOsNameServers())
|
|
let invalid = await dnsresolver.resolveIp("", 0.Port)
|
|
check invalid.len == 0
|
|
|
|
asyncTest "unreachable dns server":
|
|
var dnsresolver = DnsResolver.new(@[initTAddress("172.67.10.161:53")])
|
|
let invalid = await dnsresolver.resolveIp("google.fr", 0.Port)
|
|
check invalid.len == 0
|