-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: accept DNS resolver when resolving DNSADDR addresses
Accept a `DNS` instance from `@multiformats/dns` when resolving DNSADDR addresses. Gives the user flexibility to control which DNS servers are used to resolve TXT records.
- Loading branch information
1 parent
9ce73b2
commit 5be4646
Showing
9 changed files
with
275 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { CodeError } from '@libp2p/interface' | ||
import { dns, RecordType } from '@multiformats/dns' | ||
import { raceSignal } from 'race-signal' | ||
import { multiaddr } from '../index.js' | ||
import { getProtocol } from '../protocols-table.js' | ||
import type { Resolver } from './index.js' | ||
import type { AbortOptions, Multiaddr } from '../index.js' | ||
import type { DNS } from '@multiformats/dns' | ||
|
||
const MAX_RECURSIVE_DEPTH = 32 | ||
const { code: dnsaddrCode } = getProtocol('dnsaddr') | ||
|
||
export interface DNSADDROptions extends AbortOptions { | ||
/** | ||
* An optional DNS resolver | ||
*/ | ||
dns?: DNS | ||
|
||
/** | ||
* When resolving DNSADDR Multiaddrs that resolve to other DNSADDR Multiaddrs, | ||
* limit how many times we will recursively resolve them. | ||
* | ||
* @default 32 | ||
*/ | ||
maxRecursiveDepth?: number | ||
} | ||
|
||
export const dnsaddr: Resolver<DNSADDROptions> = async function dnsaddr (ma: Multiaddr, options: DNSADDROptions = {}): Promise<Multiaddr[]> { | ||
const recursionLimit = options.maxRecursiveDepth ?? MAX_RECURSIVE_DEPTH | ||
|
||
if (recursionLimit === 0) { | ||
throw new CodeError('Max recursive depth reached', 'ERR_MAX_RECURSIVE_DEPTH_REACHED') | ||
} | ||
|
||
const [, hostname] = ma.stringTuples().find(([proto]) => proto === dnsaddrCode) ?? [] | ||
|
||
const resolver = options?.dns ?? dns() | ||
const result = await raceSignal(resolver.query(`_dnsaddr.${hostname}`, { | ||
signal: options?.signal, | ||
types: [ | ||
RecordType.TXT | ||
] | ||
}), options.signal) | ||
|
||
const peerId = ma.getPeerId() | ||
const output: Multiaddr[] = [] | ||
|
||
for (const answer of result.Answer) { | ||
const addr = answer.data.split('=')[1] | ||
|
||
if (addr == null) { | ||
continue | ||
} | ||
|
||
if (peerId != null && !addr.includes(peerId)) { | ||
continue | ||
} | ||
|
||
const ma = multiaddr(addr) | ||
|
||
if (addr.startsWith('/dnsaddr')) { | ||
const resolved = await ma.resolve({ | ||
...options, | ||
maxRecursiveDepth: recursionLimit - 1 | ||
}) | ||
|
||
output.push(...resolved) | ||
} else { | ||
output.push(ma) | ||
} | ||
} | ||
|
||
return output | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,7 @@ | ||
/** | ||
* @packageDocumentation | ||
* | ||
* Provides strategies for resolving multiaddrs. | ||
*/ | ||
|
||
import { getProtocol } from '../protocols-table.js' | ||
import Resolver from './dns.js' | ||
import type { AbortOptions, Multiaddr } from '../index.js' | ||
|
||
const { code: dnsaddrCode } = getProtocol('dnsaddr') | ||
|
||
/** | ||
* Resolver for dnsaddr addresses. | ||
* | ||
* @example | ||
* | ||
* ```typescript | ||
* import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' | ||
* import { multiaddr } from '@multiformats/multiaddr' | ||
* | ||
* const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io') | ||
* const addresses = await dnsaddrResolver(ma) | ||
* | ||
* console.info(addresses) | ||
* //[ | ||
* // '/dnsaddr/am6.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', | ||
* // '/dnsaddr/ny5.bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa', | ||
* // '/dnsaddr/sg1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt', | ||
* // '/dnsaddr/sv15.bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN' | ||
* //] | ||
* ``` | ||
*/ | ||
export async function dnsaddrResolver (addr: Multiaddr, options: AbortOptions = {}): Promise<string[]> { | ||
const resolver = new Resolver() | ||
|
||
if (options.signal != null) { | ||
options.signal.addEventListener('abort', () => { | ||
resolver.cancel() | ||
}) | ||
} | ||
|
||
const peerId = addr.getPeerId() | ||
const [, hostname] = addr.stringTuples().find(([proto]) => proto === dnsaddrCode) ?? [] | ||
|
||
if (hostname == null) { | ||
throw new Error('No hostname found in multiaddr') | ||
} | ||
|
||
const records = await resolver.resolveTxt(`_dnsaddr.${hostname}`) | ||
|
||
let addresses = records.flat().map((a) => a.split('=')[1]).filter(Boolean) | ||
|
||
if (peerId != null) { | ||
addresses = addresses.filter((entry) => entry.includes(peerId)) | ||
} | ||
|
||
return addresses | ||
export interface Resolver<ResolveOptions extends AbortOptions = AbortOptions> { | ||
(ma: Multiaddr, options?: ResolveOptions): Promise<Multiaddr[]> | ||
} | ||
|
||
export { dnsaddr } from './dnsaddr.js' |
Oops, something went wrong.