nim-libp2p/libp2p/nameresolving/nameresolver.nim

143 lines
3.8 KiB
Nim
Raw Normal View History

2022-07-01 20:19:57 +02:00
# Nim-LibP2P
2023-01-20 15:47:40 +01:00
# Copyright (c) 2023 Status Research & Development GmbH
2022-07-01 20:19:57 +02:00
# 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.
2023-06-07 13:12:49 +02:00
{.push raises: [].}
import std/[sugar, sets, sequtils, strutils]
2022-09-26 11:03:24 +02:00
import
chronos,
chronicles,
stew/endians2
2024-03-06 13:12:05 +01:00
import ".."/[errors, multiaddress, multicodec]
logScope:
topics = "libp2p nameresolver"
2022-09-26 11:03:24 +02:00
type
NameResolver* = ref object of RootObj
method resolveTxt*(
2024-03-06 13:12:05 +01:00
self: NameResolver,
address: string
): Future[seq[string]] {.async: (raises: [CancelledError], raw: true), base.} =
## Get TXT record
2022-09-26 11:03:24 +02:00
##
2024-03-06 13:12:05 +01:00
raiseAssert("Not implemented!")
method resolveIp*(
2024-03-06 13:12:05 +01:00
self: NameResolver,
address: string,
port: Port,
domain: Domain = Domain.AF_UNSPEC
): Future[seq[TransportAddress]] {.async: (raises: [
CancelledError], raw: true), base.} =
## Resolve the specified address
2022-09-26 11:03:24 +02:00
##
2024-03-06 13:12:05 +01:00
raiseAssert("Not implemented!")
proc getHostname*(ma: MultiAddress): string =
2022-09-26 11:03:24 +02:00
let
firstPart = ma[0].valueOr: return ""
fpSplitted = ($firstPart).split('/', 2)
if fpSplitted.len > 2: fpSplitted[2]
else: ""
2022-09-26 11:03:24 +02:00
proc resolveOneAddress(
2024-03-06 13:12:05 +01:00
self: NameResolver,
ma: MultiAddress,
domain: Domain = Domain.AF_UNSPEC,
prefix = ""
): Future[seq[MultiAddress]] {.async: (raises: [CancelledError, LPError]).} =
#Resolve a single address
var pbuf: array[2, byte]
var dnsval = getHostname(ma)
2024-03-06 13:12:05 +01:00
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)
2022-09-26 11:03:24 +02:00
return collect(newSeqOfCap(4)):
for address in resolvedAddresses:
2024-03-06 13:12:05 +01:00
var createdAddress = MultiAddress.init(address)
.tryGet()[0].tryGet()
for part in ma:
2022-09-26 11:03:24 +02:00
if DNS.match(part.tryGet()): continue
createdAddress &= part.tryGet()
createdAddress
2022-09-26 11:03:24 +02:00
proc resolveDnsAddr*(
2024-03-06 13:12:05 +01:00
self: NameResolver,
ma: MultiAddress,
depth: int = 0
): Future[seq[MultiAddress]] {.async: (raises: [CancelledError, LPError]).} =
2022-09-26 11:03:24 +02:00
if not DNSADDR.matchPartial(ma):
return @[ma]
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()
2024-03-06 13:12:05 +01:00
if entryValue.contains(multiCodec("p2p")).tryGet() and
ma.contains(multiCodec("p2p")).tryGet():
2022-09-26 11:03:24 +02:00
if entryValue[multiCodec("p2p")] != ma[multiCodec("p2p")]:
continue
2022-09-26 11:03:24 +02:00
let resolved = await self.resolveDnsAddr(entryValue, depth + 1)
for r in resolved:
result.add(r)
if result.len == 0:
2022-09-26 11:03:24 +02:00
debug "Failed to resolve a DNSADDR", ma
return @[]
return result
proc resolveMAddress*(
2024-03-06 13:12:05 +01:00
self: NameResolver,
address: MultiAddress
): Future[seq[MultiAddress]] {.async: (raises: [CancelledError, LPError]).} =
var res = initOrderedSet[MultiAddress]()
if not DNS.matchPartial(address):
res.incl(address)
else:
2024-03-06 13:12:05 +01:00
let code = address[0].tryGet()
.protoCode().tryGet()
let seq = case code:
of multiCodec("dns"):
2022-09-26 11:03:24 +02:00
await self.resolveOneAddress(address)
of multiCodec("dns4"):
2022-09-26 11:03:24 +02:00
await self.resolveOneAddress(address, Domain.AF_INET)
of multiCodec("dns6"):
2022-09-26 11:03:24 +02:00
await self.resolveOneAddress(address, Domain.AF_INET6)
of multiCodec("dnsaddr"):
await self.resolveDnsAddr(address)
else:
assert false
@[address]
for ad in seq:
res.incl(ad)
return res.toSeq