mirror of
https://github.com/logos-storage/nim-libp2p.git
synced 2026-01-03 22:23:09 +00:00
DNS Addresses handling (#580)
* add 'dns' multiaddr protocol * multiaddr: isWire is true for DNS protocols * resolve dns on connect * fix typo * add dns test * update resolveDns error handling * handle multiple dns entries * start of new resolver * working dns resolver * use the DnsResolver * fix json logs * small overhaul * fix dns implem in lp2p * update dnsclient repo * add dns test to testnative * dummy dns server for ut * better mocked * moved resolving to transport * moved mockresolver to libp2p * test resolve in switch test * try multiple txt & track leaks * raise e * catchable error instead of exception * save failed dns server * moved resolve back to dialer * remove nameresolver from dialer
This commit is contained in:
parent
e58658d822
commit
f274bfe19d
@ -9,6 +9,7 @@ skipDirs = @["tests", "examples", "Nim", "tools", "scripts", "docs"]
|
|||||||
|
|
||||||
requires "nim >= 1.2.0",
|
requires "nim >= 1.2.0",
|
||||||
"nimcrypto >= 0.4.1",
|
"nimcrypto >= 0.4.1",
|
||||||
|
"https://github.com/ba0f3/dnsclient.nim == 0.1.0",
|
||||||
"bearssl >= 0.1.4",
|
"bearssl >= 0.1.4",
|
||||||
"chronicles#ba2817f1",
|
"chronicles#ba2817f1",
|
||||||
"chronos >= 2.5.2",
|
"chronos >= 2.5.2",
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import
|
|||||||
muxers/[muxer, mplex/mplex],
|
muxers/[muxer, mplex/mplex],
|
||||||
protocols/[identify, secure/secure, secure/noise],
|
protocols/[identify, secure/secure, secure/noise],
|
||||||
connmanager, upgrademngrs/muxedupgrade,
|
connmanager, upgrademngrs/muxedupgrade,
|
||||||
|
nameresolving/nameresolver,
|
||||||
errors
|
errors
|
||||||
|
|
||||||
export
|
export
|
||||||
@ -45,6 +46,7 @@ type
|
|||||||
maxConnsPerPeer: int
|
maxConnsPerPeer: int
|
||||||
protoVersion: string
|
protoVersion: string
|
||||||
agentVersion: string
|
agentVersion: string
|
||||||
|
nameResolver: NameResolver
|
||||||
|
|
||||||
proc new*(T: type[SwitchBuilder]): T =
|
proc new*(T: type[SwitchBuilder]): T =
|
||||||
|
|
||||||
@ -129,6 +131,10 @@ proc withAgentVersion*(b: SwitchBuilder, agentVersion: string): SwitchBuilder =
|
|||||||
b.agentVersion = agentVersion
|
b.agentVersion = agentVersion
|
||||||
b
|
b
|
||||||
|
|
||||||
|
proc withNameResolver*(b: SwitchBuilder, nameResolver: NameResolver): SwitchBuilder =
|
||||||
|
b.nameResolver = nameResolver
|
||||||
|
b
|
||||||
|
|
||||||
proc build*(b: SwitchBuilder): Switch
|
proc build*(b: SwitchBuilder): Switch
|
||||||
{.raises: [Defect, LPError].} =
|
{.raises: [Defect, LPError].} =
|
||||||
|
|
||||||
@ -184,7 +190,8 @@ proc build*(b: SwitchBuilder): Switch
|
|||||||
muxers = muxers,
|
muxers = muxers,
|
||||||
secureManagers = secureManagerInstances,
|
secureManagers = secureManagerInstances,
|
||||||
connManager = connManager,
|
connManager = connManager,
|
||||||
ms = ms)
|
ms = ms,
|
||||||
|
nameResolver = b.nameResolver)
|
||||||
|
|
||||||
return switch
|
return switch
|
||||||
|
|
||||||
@ -201,7 +208,8 @@ proc newStandardSwitch*(
|
|||||||
maxConnections = MaxConnections,
|
maxConnections = MaxConnections,
|
||||||
maxIn = -1,
|
maxIn = -1,
|
||||||
maxOut = -1,
|
maxOut = -1,
|
||||||
maxConnsPerPeer = MaxConnectionsPerPeer): Switch
|
maxConnsPerPeer = MaxConnectionsPerPeer,
|
||||||
|
nameResolver: NameResolver = nil): Switch
|
||||||
{.raises: [Defect, LPError].} =
|
{.raises: [Defect, LPError].} =
|
||||||
if SecureProtocol.Secio in secureManagers:
|
if SecureProtocol.Secio in secureManagers:
|
||||||
quit("Secio is deprecated!") # use of secio is unsafe
|
quit("Secio is deprecated!") # use of secio is unsafe
|
||||||
@ -216,6 +224,7 @@ proc newStandardSwitch*(
|
|||||||
.withMaxConnsPerPeer(maxConnsPerPeer)
|
.withMaxConnsPerPeer(maxConnsPerPeer)
|
||||||
.withMplex(inTimeout, outTimeout)
|
.withMplex(inTimeout, outTimeout)
|
||||||
.withTcpTransport(transportFlags)
|
.withTcpTransport(transportFlags)
|
||||||
|
.withNameResolver(nameResolver)
|
||||||
.withNoise()
|
.withNoise()
|
||||||
|
|
||||||
if privKey.isSome():
|
if privKey.isSome():
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import std/[nativesockets, hashes]
|
import std/[nativesockets, hashes]
|
||||||
import tables, strutils, stew/shims/net
|
import tables, strutils, sets, stew/shims/net
|
||||||
import multicodec, multihash, multibase, transcoder, vbuffer, peerid,
|
import multicodec, multihash, multibase, transcoder, vbuffer, peerid,
|
||||||
protobuf/minprotobuf, errors
|
protobuf/minprotobuf, errors
|
||||||
import stew/[base58, base32, endians2, results]
|
import stew/[base58, base32, endians2, results]
|
||||||
@ -377,6 +377,10 @@ const
|
|||||||
mcodec: multiCodec("unix"), kind: Path, size: 0,
|
mcodec: multiCodec("unix"), kind: Path, size: 0,
|
||||||
coder: TranscoderUnix
|
coder: TranscoderUnix
|
||||||
),
|
),
|
||||||
|
MAProtocol(
|
||||||
|
mcodec: multiCodec("dns"), kind: Length, size: 0,
|
||||||
|
coder: TranscoderDNS
|
||||||
|
),
|
||||||
MAProtocol(
|
MAProtocol(
|
||||||
mcodec: multiCodec("dns4"), kind: Length, size: 0,
|
mcodec: multiCodec("dns4"), kind: Length, size: 0,
|
||||||
coder: TranscoderDNS
|
coder: TranscoderDNS
|
||||||
@ -403,11 +407,13 @@ const
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
DNSANY* = mapEq("dns")
|
||||||
DNS4* = mapEq("dns4")
|
DNS4* = mapEq("dns4")
|
||||||
DNS6* = mapEq("dns6")
|
DNS6* = mapEq("dns6")
|
||||||
|
DNSADDR* = mapEq("dnsaddr")
|
||||||
IP4* = mapEq("ip4")
|
IP4* = mapEq("ip4")
|
||||||
IP6* = mapEq("ip6")
|
IP6* = mapEq("ip6")
|
||||||
DNS* = mapOr(mapEq("dnsaddr"), DNS4, DNS6)
|
DNS* = mapOr(DNSANY, DNS4, DNS6, DNSADDR)
|
||||||
IP* = mapOr(IP4, IP6)
|
IP* = mapOr(IP4, IP6)
|
||||||
TCP* = mapOr(mapAnd(DNS, mapEq("tcp")), mapAnd(IP, mapEq("tcp")))
|
TCP* = mapOr(mapAnd(DNS, mapEq("tcp")), mapAnd(IP, mapEq("tcp")))
|
||||||
UDP* = mapOr(mapAnd(DNS, mapEq("udp")), mapAnd(IP, mapEq("udp")))
|
UDP* = mapOr(mapAnd(DNS, mapEq("udp")), mapAnd(IP, mapEq("udp")))
|
||||||
@ -934,13 +940,24 @@ proc `&=`*(m1: var MultiAddress, m2: MultiAddress) {.
|
|||||||
|
|
||||||
m1.append(m2).tryGet()
|
m1.append(m2).tryGet()
|
||||||
|
|
||||||
|
proc `==`*(m1: var MultiAddress, m2: MultiAddress): bool =
|
||||||
|
## Check of two MultiAddress are equal
|
||||||
|
m1.data == m2.data
|
||||||
|
|
||||||
proc isWire*(ma: MultiAddress): bool =
|
proc isWire*(ma: MultiAddress): bool =
|
||||||
## Returns ``true`` if MultiAddress ``ma`` is one of:
|
## Returns ``true`` if MultiAddress ``ma`` is one of:
|
||||||
## - {IP4}/{TCP, UDP}
|
## - {IP4}/{TCP, UDP}
|
||||||
## - {IP6}/{TCP, UDP}
|
## - {IP6}/{TCP, UDP}
|
||||||
## - {UNIX}/{PATH}
|
## - {UNIX}/{PATH}
|
||||||
var
|
|
||||||
state = 0
|
var state = 0
|
||||||
|
const
|
||||||
|
wireProtocols = toHashSet([
|
||||||
|
multiCodec("ip4"), multiCodec("ip6"),
|
||||||
|
])
|
||||||
|
wireTransports = toHashSet([
|
||||||
|
multiCodec("tcp"), multiCodec("udp")
|
||||||
|
])
|
||||||
try:
|
try:
|
||||||
for rpart in ma.items():
|
for rpart in ma.items():
|
||||||
if rpart.isErr():
|
if rpart.isErr():
|
||||||
@ -953,7 +970,7 @@ proc isWire*(ma: MultiAddress): bool =
|
|||||||
return false
|
return false
|
||||||
let code = rcode.get()
|
let code = rcode.get()
|
||||||
|
|
||||||
if code == multiCodec("ip4") or code == multiCodec("ip6"):
|
if code in wireProtocols:
|
||||||
inc(state)
|
inc(state)
|
||||||
continue
|
continue
|
||||||
elif code == multiCodec("unix"):
|
elif code == multiCodec("unix"):
|
||||||
@ -968,7 +985,7 @@ proc isWire*(ma: MultiAddress): bool =
|
|||||||
return false
|
return false
|
||||||
let code = rcode.get()
|
let code = rcode.get()
|
||||||
|
|
||||||
if code == multiCodec("tcp") or code == multiCodec("udp"):
|
if code in wireTransports:
|
||||||
inc(state)
|
inc(state)
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -201,6 +201,7 @@ const MultiCodecList = [
|
|||||||
("p2p-webrtc-direct", 0x0114), # not in multicodec list
|
("p2p-webrtc-direct", 0x0114), # not in multicodec list
|
||||||
("onion", 0x01BC),
|
("onion", 0x01BC),
|
||||||
("p2p-circuit", 0x0122),
|
("p2p-circuit", 0x0122),
|
||||||
|
("dns", 0x35),
|
||||||
("dns4", 0x36),
|
("dns4", 0x36),
|
||||||
("dns6", 0x37),
|
("dns6", 0x37),
|
||||||
("dnsaddr", 0x38),
|
("dnsaddr", 0x38),
|
||||||
|
|||||||
160
libp2p/nameresolving/dnsresolver.nim
Normal file
160
libp2p/nameresolving/dnsresolver.nim
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
## Nim-LibP2P
|
||||||
|
## Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/[streams, strutils, sets, sequtils],
|
||||||
|
chronos, chronicles,
|
||||||
|
dnsclientpkg/[protocol, types]
|
||||||
|
|
||||||
|
import
|
||||||
|
nameresolver
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "libp2p dnsresolver"
|
||||||
|
|
||||||
|
type
|
||||||
|
DnsResolver* = ref object of NameResolver
|
||||||
|
nameServers*: seq[TransportAddress]
|
||||||
|
|
||||||
|
proc questionToBuf(address: string, kind: QKind): seq[byte] =
|
||||||
|
try:
|
||||||
|
var
|
||||||
|
header = initHeader()
|
||||||
|
question = initQuestion(address, kind)
|
||||||
|
|
||||||
|
requestStream = header.toStream()
|
||||||
|
question.toStream(requestStream)
|
||||||
|
|
||||||
|
let dataLen = requestStream.getPosition()
|
||||||
|
requestStream.setPosition(0)
|
||||||
|
|
||||||
|
var buf = newSeq[byte](dataLen)
|
||||||
|
discard requestStream.readData(addr buf[0], dataLen)
|
||||||
|
return buf
|
||||||
|
except CatchableError as exc:
|
||||||
|
info "Failed to created DNS buffer", msg = exc.msg
|
||||||
|
return newSeq[byte](0)
|
||||||
|
|
||||||
|
proc getDnsResponse(
|
||||||
|
dnsServer: TransportAddress,
|
||||||
|
address: string,
|
||||||
|
kind: QKind): Future[Response] {.async.} =
|
||||||
|
|
||||||
|
var sendBuf = questionToBuf(address, kind)
|
||||||
|
|
||||||
|
if sendBuf.len == 0:
|
||||||
|
raise newException(ValueError, "Incorrect DNS query")
|
||||||
|
|
||||||
|
let receivedDataFuture = newFuture[void]()
|
||||||
|
|
||||||
|
proc datagramDataReceived(transp: DatagramTransport,
|
||||||
|
raddr: TransportAddress): Future[void] {.async, closure.} =
|
||||||
|
receivedDataFuture.complete()
|
||||||
|
|
||||||
|
let sock =
|
||||||
|
if dnsServer.family == AddressFamily.IPv6:
|
||||||
|
newDatagramTransport6(datagramDataReceived)
|
||||||
|
else:
|
||||||
|
newDatagramTransport(datagramDataReceived)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await sock.sendTo(dnsServer, addr sendBuf[0], sendBuf.len)
|
||||||
|
|
||||||
|
await receivedDataFuture or sleepAsync(5.seconds) #unix default
|
||||||
|
|
||||||
|
if not receivedDataFuture.finished:
|
||||||
|
raise newException(IOError, "DNS server timeout")
|
||||||
|
|
||||||
|
var
|
||||||
|
rawResponse = sock.getMessage()
|
||||||
|
dataStream = newStringStream()
|
||||||
|
dataStream.writeData(addr rawResponse[0], rawResponse.len)
|
||||||
|
dataStream.setPosition(0)
|
||||||
|
return parseResponse(dataStream)
|
||||||
|
finally:
|
||||||
|
await sock.closeWait()
|
||||||
|
|
||||||
|
method resolveIp*(
|
||||||
|
self: DnsResolver,
|
||||||
|
address: string,
|
||||||
|
port: Port,
|
||||||
|
domain: Domain = Domain.AF_UNSPEC): Future[seq[TransportAddress]] {.async.} =
|
||||||
|
|
||||||
|
trace "Resolving IP using DNS", address, servers = self.nameservers.mapIt($it), domain
|
||||||
|
for _ in 0 ..< self.nameservers.len:
|
||||||
|
let server = self.nameservers[0]
|
||||||
|
var responseFutures: seq[Future[Response]]
|
||||||
|
if domain == Domain.AF_INET or domain == Domain.AF_UNSPEC:
|
||||||
|
responseFutures.add(getDnsResponse(server, address, A))
|
||||||
|
|
||||||
|
if domain == Domain.AF_INET6 or domain == Domain.AF_UNSPEC:
|
||||||
|
let fut = getDnsResponse(server, address, AAAA)
|
||||||
|
if server.family == AddressFamily.IPv6:
|
||||||
|
trace "IPv6 DNS server, puting AAAA records first", server = $server
|
||||||
|
responseFutures.insert(fut)
|
||||||
|
else:
|
||||||
|
responseFutures.add(fut)
|
||||||
|
|
||||||
|
var
|
||||||
|
resolvedAddresses: OrderedSet[string]
|
||||||
|
resolveFailed = false
|
||||||
|
for fut in responseFutures:
|
||||||
|
try:
|
||||||
|
let resp = await fut
|
||||||
|
for answer in resp.answers:
|
||||||
|
resolvedAddresses.incl(answer.toString())
|
||||||
|
except CancelledError as e:
|
||||||
|
raise e
|
||||||
|
except ValueError as e:
|
||||||
|
info "Invalid DNS query", address, error=e.msg
|
||||||
|
return @[]
|
||||||
|
except CatchableError as e:
|
||||||
|
info "Failed to query DNS", address, error=e.msg
|
||||||
|
resolveFailed = true
|
||||||
|
break
|
||||||
|
|
||||||
|
if resolveFailed:
|
||||||
|
self.nameservers.add(self.nameservers[0])
|
||||||
|
self.nameservers.delete(0)
|
||||||
|
continue
|
||||||
|
|
||||||
|
trace "Got IPs from DNS server", resolvedAddresses, server = $server
|
||||||
|
return resolvedAddresses.toSeq().mapIt(initTAddress(it, port))
|
||||||
|
|
||||||
|
debug "Failed to resolve address, returning empty set"
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
method resolveTxt*(
|
||||||
|
self: DnsResolver,
|
||||||
|
address: string): Future[seq[string]] {.async.} =
|
||||||
|
|
||||||
|
trace "Resolving TXT using DNS", address, servers = self.nameservers.mapIt($it)
|
||||||
|
for _ in 0 ..< self.nameservers.len:
|
||||||
|
let server = self.nameservers[0]
|
||||||
|
try:
|
||||||
|
let response = await getDnsResponse(server, address, TXT)
|
||||||
|
trace "Got TXT response", server = $server, answer=response.answers.mapIt(it.toString())
|
||||||
|
return response.answers.mapIt(it.toString())
|
||||||
|
except CancelledError as e:
|
||||||
|
raise e
|
||||||
|
except CatchableError as e:
|
||||||
|
info "Failed to query DNS", address, error=e.msg
|
||||||
|
self.nameservers.add(self.nameservers[0])
|
||||||
|
self.nameservers.delete(0)
|
||||||
|
continue
|
||||||
|
|
||||||
|
debug "Failed to resolve TXT, returning empty set"
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
proc new*(
|
||||||
|
T: typedesc[DnsResolver],
|
||||||
|
nameServers: seq[TransportAddress]): T =
|
||||||
|
T(nameServers: nameServers)
|
||||||
46
libp2p/nameresolving/mockresolver.nim
Normal file
46
libp2p/nameresolving/mockresolver.nim
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
## Nim-LibP2P
|
||||||
|
## Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/[streams, strutils, tables],
|
||||||
|
chronos, chronicles
|
||||||
|
|
||||||
|
import nameresolver
|
||||||
|
|
||||||
|
export tables
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "libp2p mockresolver"
|
||||||
|
|
||||||
|
type MockResolver* = ref object of NameResolver
|
||||||
|
txtResponses*: Table[string, seq[string]]
|
||||||
|
# key: address, isipv6?
|
||||||
|
ipResponses*: Table[(string, bool), seq[string]]
|
||||||
|
|
||||||
|
method resolveIp*(
|
||||||
|
self: MockResolver,
|
||||||
|
address: string,
|
||||||
|
port: Port,
|
||||||
|
domain: Domain = Domain.AF_UNSPEC): Future[seq[TransportAddress]] {.async.} =
|
||||||
|
if domain == Domain.AF_INET or domain == Domain.AF_UNSPEC:
|
||||||
|
for resp in self.ipResponses.getOrDefault((address, false)):
|
||||||
|
result.add(initTAddress(resp, port))
|
||||||
|
|
||||||
|
if domain == Domain.AF_INET6 or domain == Domain.AF_UNSPEC:
|
||||||
|
for resp in self.ipResponses.getOrDefault((address, true)):
|
||||||
|
result.add(initTAddress(resp, port))
|
||||||
|
|
||||||
|
method resolveTxt*(
|
||||||
|
self: MockResolver,
|
||||||
|
address: string): Future[seq[string]] {.async.} =
|
||||||
|
return self.txtResponses.getOrDefault(address)
|
||||||
|
|
||||||
|
proc new*(T: typedesc[MockResolver]): T = T()
|
||||||
148
libp2p/nameresolving/nameresolver.nim
Normal file
148
libp2p/nameresolving/nameresolver.nim
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
## Nim-LibP2P
|
||||||
|
## Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
|
import std/[sugar, sets, sequtils, strutils]
|
||||||
|
import
|
||||||
|
chronos,
|
||||||
|
chronicles,
|
||||||
|
stew/[endians2, byteutils]
|
||||||
|
import ".."/[multiaddress, multicodec]
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "libp2p nameresolver"
|
||||||
|
|
||||||
|
type
|
||||||
|
NameResolver* = ref object of RootObj
|
||||||
|
|
||||||
|
method resolveTxt*(
|
||||||
|
self: NameResolver,
|
||||||
|
address: string): Future[seq[string]] {.async, base.} =
|
||||||
|
## Get TXT record
|
||||||
|
##
|
||||||
|
|
||||||
|
doAssert(false, "Not implemented!")
|
||||||
|
|
||||||
|
method resolveIp*(
|
||||||
|
self: NameResolver,
|
||||||
|
address: string,
|
||||||
|
port: Port,
|
||||||
|
domain: Domain = Domain.AF_UNSPEC): Future[seq[TransportAddress]] {.async, base.} =
|
||||||
|
## Resolve the specified address
|
||||||
|
##
|
||||||
|
|
||||||
|
doAssert(false, "Not implemented!")
|
||||||
|
|
||||||
|
proc getHostname(ma: MultiAddress): string =
|
||||||
|
var dnsbuf = newSeq[byte](256)
|
||||||
|
|
||||||
|
let dnsLen = ma[0].get().protoArgument(dnsbuf).get()
|
||||||
|
dnsbuf.setLen(dnsLen)
|
||||||
|
return string.fromBytes(dnsbuf)
|
||||||
|
|
||||||
|
proc resolveDnsAddress(
|
||||||
|
self: NameResolver,
|
||||||
|
ma: MultiAddress,
|
||||||
|
domain: Domain = Domain.AF_UNSPEC,
|
||||||
|
prefix = ""): Future[seq[MultiAddress]]
|
||||||
|
{.async, raises: [Defect, MaError, TransportAddressError].} =
|
||||||
|
#Resolve a single address
|
||||||
|
var pbuf: array[2, byte]
|
||||||
|
|
||||||
|
var dnsval = getHostname(ma)
|
||||||
|
|
||||||
|
if ma[1].tryGet().protoArgument(pbuf).tryGet() == 0:
|
||||||
|
raise newException(MaError, "Incorrect port number")
|
||||||
|
let
|
||||||
|
port = Port(fromBytesBE(uint16, pbuf))
|
||||||
|
resolvedAddresses = await self.resolveIp(prefix & dnsval, port, domain)
|
||||||
|
|
||||||
|
var addressSuffix = ma
|
||||||
|
return collect(newSeqOfCap(4)):
|
||||||
|
for address in resolvedAddresses:
|
||||||
|
var createdAddress = MultiAddress.init(address).tryGet()[0].tryGet()
|
||||||
|
for part in ma:
|
||||||
|
if DNS.match(part.get()): continue
|
||||||
|
createdAddress &= part.tryGet()
|
||||||
|
createdAddress
|
||||||
|
|
||||||
|
func matchDnsSuffix(m1, m2: MultiAddress): MaResult[bool] =
|
||||||
|
for partMaybe in m1:
|
||||||
|
let part = ?partMaybe
|
||||||
|
if DNS.match(part): continue
|
||||||
|
let entryProt = ?m2[?part.protoCode()]
|
||||||
|
if entryProt != part:
|
||||||
|
return ok(false)
|
||||||
|
return ok(true)
|
||||||
|
|
||||||
|
proc resolveDnsAddr(
|
||||||
|
self: NameResolver,
|
||||||
|
ma: MultiAddress,
|
||||||
|
depth: int = 0): Future[seq[MultiAddress]]
|
||||||
|
{.async.} =
|
||||||
|
|
||||||
|
trace "Resolving dnsaddr", ma
|
||||||
|
if depth > 6:
|
||||||
|
info "Stopping DNSADDR recursion, probably malicious", ma
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
var dnsval = getHostname(ma)
|
||||||
|
|
||||||
|
let txt = await self.resolveTxt("_dnsaddr." & dnsval)
|
||||||
|
|
||||||
|
trace "txt entries", txt
|
||||||
|
|
||||||
|
var result: seq[MultiAddress]
|
||||||
|
for entry in txt:
|
||||||
|
if not entry.startsWith("dnsaddr="): continue
|
||||||
|
let entryValue = MultiAddress.init(entry[8..^1]).tryGet()
|
||||||
|
|
||||||
|
if not matchDnsSuffix(ma, entryValue).tryGet(): continue
|
||||||
|
|
||||||
|
# The spec is not clear wheter only DNSADDR can be recursived
|
||||||
|
# or any DNS addr. Only handling DNSADDR because it's simpler
|
||||||
|
# to avoid infinite recursion
|
||||||
|
if DNSADDR.matchPartial(entryValue):
|
||||||
|
let resolved = await self.resolveDnsAddr(entryValue, depth + 1)
|
||||||
|
for r in resolved:
|
||||||
|
result.add(r)
|
||||||
|
else:
|
||||||
|
result.add(entryValue)
|
||||||
|
|
||||||
|
if result.len == 0:
|
||||||
|
debug "Failed to resolve any DNSADDR", ma
|
||||||
|
return @[ma]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
proc resolveMAddresses*(
|
||||||
|
self: NameResolver,
|
||||||
|
addrs: seq[MultiAddress]): Future[seq[MultiAddress]] {.async.} =
|
||||||
|
var res = initOrderedSet[MultiAddress]()
|
||||||
|
|
||||||
|
for address in addrs:
|
||||||
|
if not DNS.matchPartial(address):
|
||||||
|
res.incl(address)
|
||||||
|
else:
|
||||||
|
let code = address[0].get().protoCode().get()
|
||||||
|
let seq = case code:
|
||||||
|
of multiCodec("dns"):
|
||||||
|
await self.resolveDnsAddress(address)
|
||||||
|
of multiCodec("dns4"):
|
||||||
|
await self.resolveDnsAddress(address, Domain.AF_INET)
|
||||||
|
of multiCodec("dns6"):
|
||||||
|
await self.resolveDnsAddress(address, Domain.AF_INET6)
|
||||||
|
of multiCodec("dnsaddr"):
|
||||||
|
await self.resolveDnsAddr(address)
|
||||||
|
else:
|
||||||
|
@[address]
|
||||||
|
for ad in seq:
|
||||||
|
res.incl(ad)
|
||||||
|
return res.toSeq
|
||||||
@ -32,6 +32,7 @@ import stream/connection,
|
|||||||
muxers/muxer,
|
muxers/muxer,
|
||||||
utils/semaphore,
|
utils/semaphore,
|
||||||
connmanager,
|
connmanager,
|
||||||
|
nameresolving/nameresolver,
|
||||||
peerid,
|
peerid,
|
||||||
peerstore,
|
peerstore,
|
||||||
errors,
|
errors,
|
||||||
@ -62,6 +63,7 @@ type
|
|||||||
acceptFuts: seq[Future[void]]
|
acceptFuts: seq[Future[void]]
|
||||||
dialer*: Dial
|
dialer*: Dial
|
||||||
peerStore*: PeerStore
|
peerStore*: PeerStore
|
||||||
|
nameResolver*: NameResolver
|
||||||
|
|
||||||
proc addConnEventHandler*(s: Switch,
|
proc addConnEventHandler*(s: Switch,
|
||||||
handler: ConnEventHandler,
|
handler: ConnEventHandler,
|
||||||
@ -256,7 +258,8 @@ proc newSwitch*(peerInfo: PeerInfo,
|
|||||||
muxers: Table[string, MuxerProvider],
|
muxers: Table[string, MuxerProvider],
|
||||||
secureManagers: openarray[Secure] = [],
|
secureManagers: openarray[Secure] = [],
|
||||||
connManager: ConnManager,
|
connManager: ConnManager,
|
||||||
ms: MultistreamSelect): Switch
|
ms: MultistreamSelect,
|
||||||
|
nameResolver: NameResolver = nil): Switch
|
||||||
{.raises: [Defect, LPError].} =
|
{.raises: [Defect, LPError].} =
|
||||||
if secureManagers.len == 0:
|
if secureManagers.len == 0:
|
||||||
raise newException(LPError, "Provide at least one secure manager")
|
raise newException(LPError, "Provide at least one secure manager")
|
||||||
@ -267,7 +270,8 @@ proc newSwitch*(peerInfo: PeerInfo,
|
|||||||
transports: transports,
|
transports: transports,
|
||||||
connManager: connManager,
|
connManager: connManager,
|
||||||
peerStore: PeerStore.new(),
|
peerStore: PeerStore.new(),
|
||||||
dialer: Dialer.new(peerInfo, connManager, transports, ms))
|
dialer: Dialer.new(peerInfo, connManager, transports, ms),
|
||||||
|
nameResolver: nameResolver)
|
||||||
|
|
||||||
switch.mount(identity)
|
switch.mount(identity)
|
||||||
return switch
|
return switch
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export asyncunit
|
|||||||
const
|
const
|
||||||
StreamTransportTrackerName = "stream.transport"
|
StreamTransportTrackerName = "stream.transport"
|
||||||
StreamServerTrackerName = "stream.server"
|
StreamServerTrackerName = "stream.server"
|
||||||
|
DgramTransportTrackerName = "datagram.transport"
|
||||||
|
|
||||||
trackerNames = [
|
trackerNames = [
|
||||||
LPStreamTrackerName,
|
LPStreamTrackerName,
|
||||||
@ -25,8 +26,9 @@ const
|
|||||||
BufferStreamTrackerName,
|
BufferStreamTrackerName,
|
||||||
TcpTransportTrackerName,
|
TcpTransportTrackerName,
|
||||||
StreamTransportTrackerName,
|
StreamTransportTrackerName,
|
||||||
ChronosStreamTrackerName,
|
StreamServerTrackerName,
|
||||||
StreamServerTrackerName
|
DgramTransportTrackerName,
|
||||||
|
ChronosStreamTrackerName
|
||||||
]
|
]
|
||||||
|
|
||||||
iterator testTrackers*(extras: openArray[string] = []): TrackerBase =
|
iterator testTrackers*(extras: openArray[string] = []): TrackerBase =
|
||||||
|
|||||||
@ -53,6 +53,10 @@ const
|
|||||||
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
|
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
|
||||||
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
||||||
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
|
||||||
|
"/dns/example.io/udp/65535",
|
||||||
|
"/dns4/example.io/udp/65535",
|
||||||
|
"/dns6/example.io/udp/65535",
|
||||||
|
"/dnsaddr/example.io/udp/65535",
|
||||||
]
|
]
|
||||||
|
|
||||||
FailureVectors = [
|
FailureVectors = [
|
||||||
@ -257,7 +261,7 @@ const
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
PatternVector(pattern: DNS,
|
PatternVector(pattern: DNS,
|
||||||
good: @["/dnsaddr/example.io", "/dns4/example.io", "/dns6/example.io"],
|
good: @["/dns/example.io", "/dnsaddr/example.io", "/dns4/example.io", "/dns6/example.io"],
|
||||||
bad: @["/ip4/127.0.0.1"],
|
bad: @["/ip4/127.0.0.1"],
|
||||||
),
|
),
|
||||||
PatternVector(pattern: WebRTCDirect,
|
PatternVector(pattern: WebRTCDirect,
|
||||||
|
|||||||
247
tests/testnameresolve.nim
Normal file
247
tests/testnameresolve.nim
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
{.used.}
|
||||||
|
|
||||||
|
import std/[streams, strutils, sets, sequtils, tables, algorithm]
|
||||||
|
import chronos, stew/byteutils
|
||||||
|
import ../libp2p/[stream/connection,
|
||||||
|
transports/transport,
|
||||||
|
transports/tcptransport,
|
||||||
|
upgrademngrs/upgrade,
|
||||||
|
multiaddress,
|
||||||
|
errors,
|
||||||
|
nameresolving/nameresolver,
|
||||||
|
nameresolving/dnsresolver,
|
||||||
|
nameresolving/mockresolver,
|
||||||
|
wire]
|
||||||
|
|
||||||
|
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 Exception as e:
|
||||||
|
echo "Failed to get unix nameservers ", e.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.resolveMAddresses(@[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 "test multiple resolve":
|
||||||
|
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"]
|
||||||
|
resolver.ipResponses[("localhost", true)] = @["::1"]
|
||||||
|
|
||||||
|
let resolved = waitFor resolver.resolveMAddresses(@[
|
||||||
|
Multiaddress.init("/dns/localhost/udp/0").tryGet(),
|
||||||
|
Multiaddress.init("/dns4/localhost/udp/0").tryGet(),
|
||||||
|
Multiaddress.init("/dns6/localhost/udp/0").tryGet(),
|
||||||
|
])
|
||||||
|
|
||||||
|
check resolved == @[Multiaddress.init("/ip4/127.0.0.1/udp/0").tryGet(), Multiaddress.init("/ip6/::1/udp/0").tryGet()]
|
||||||
|
|
||||||
|
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/", "/dnsaddr/bootstrap.libp2p.io/")
|
||||||
|
|
||||||
|
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
|
||||||
@ -17,6 +17,7 @@ import testmultibase,
|
|||||||
testpeerid
|
testpeerid
|
||||||
|
|
||||||
import testtcptransport,
|
import testtcptransport,
|
||||||
|
testnameresolve,
|
||||||
testwstransport,
|
testwstransport,
|
||||||
testmultistream,
|
testmultistream,
|
||||||
testbufferstream,
|
testbufferstream,
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import ../libp2p/[errors,
|
|||||||
muxers/muxer,
|
muxers/muxer,
|
||||||
muxers/mplex/lpchannel,
|
muxers/mplex/lpchannel,
|
||||||
stream/lpstream,
|
stream/lpstream,
|
||||||
|
nameresolving/nameresolver,
|
||||||
|
nameresolving/mockresolver,
|
||||||
stream/chronosstream,
|
stream/chronosstream,
|
||||||
transports/tcptransport]
|
transports/tcptransport]
|
||||||
import ./helpers
|
import ./helpers
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user