Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit d5a1b89

Browse files
niinpatelAlan Shaw
authored and
Alan Shaw
committed
feat: recursive dnslink lookups (#1935)
Co-Authored-By: niinpatel <[email protected]>
1 parent 20beea2 commit d5a1b89

File tree

5 files changed

+65
-9
lines changed

5 files changed

+65
-9
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ The core API is grouped into several areas:
639639
- [`ipfs.stop([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#stop)
640640
- `ipfs.isOnline()`
641641
- [`ipfs.resolve(name, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#resolve)
642+
- [`ipfs.dns(name, [options], [callback]`](https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#dns)
642643
643644
- [repo](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/REPO.md)
644645
- `ipfs.repo.init`

src/cli/commands/dns.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@ module.exports = {
77
describe: 'Resolve DNS links',
88

99
builder: {
10+
recursive: {
11+
type: 'boolean',
12+
default: true,
13+
alias: 'r',
14+
desc: 'Resolve until the result is not a DNS link'
15+
},
1016
format: {
1117
type: 'string'
1218
}
1319
},
1420

15-
handler ({ getIpfs, domain, resolve }) {
21+
handler ({ getIpfs, domain, resolve, recursive, format }) {
1622
resolve((async () => {
1723
const ipfs = await getIpfs()
18-
const path = await ipfs.dns(domain)
24+
const path = await ipfs.dns(domain, { recursive, format })
1925
print(path)
2026
})())
2127
}

src/core/runtime/dns-nodejs.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,29 @@
22

33
const dns = require('dns')
44
const _ = require('lodash')
5+
const isIPFS = require('is-ipfs')
56
const errcode = require('err-code')
67

8+
const MAX_RECURSIVE_DEPTH = 32
9+
710
module.exports = (domain, opts, callback) => {
8-
resolveDnslink(domain)
11+
// recursive is true by default, it's set to false only if explicitly passed as argument in opts
12+
const recursive = opts.recursive == null ? true : Boolean(opts.recursive)
13+
14+
let depth
15+
if (recursive) {
16+
depth = MAX_RECURSIVE_DEPTH
17+
}
18+
19+
return recursiveResolveDnslink(domain, depth, callback)
20+
}
21+
22+
function recursiveResolveDnslink (domain, depth, callback) {
23+
if (depth === 0) {
24+
return callback(errcode(`recursion limit exceeded`, 'ERR_DNSLINK_RECURSION_LIMIT'))
25+
}
26+
27+
return resolveDnslink(domain)
928
.catch(err => {
1029
// If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND or ENODATA then throw the error
1130
if (err.code !== 'ENOTFOUND' && err.code !== 'ERR_DNSLINK_NOT_FOUND' && err.code !== 'ENODATA') throw err
@@ -22,7 +41,14 @@ module.exports = (domain, opts, callback) => {
2241
return resolveDnslink(_dnslinkDomain)
2342
})
2443
.then(dnslinkRecord => {
25-
callback(null, dnslinkRecord.replace('dnslink=', ''))
44+
const result = dnslinkRecord.replace('dnslink=', '')
45+
const domainOrCID = result.split('/')[2]
46+
const isIPFSCID = isIPFS.cid(domainOrCID)
47+
48+
if (isIPFSCID || !depth) {
49+
return callback(null, result)
50+
}
51+
return recursiveResolveDnslink(domainOrCID, depth - 1, callback)
2652
})
2753
.catch(callback)
2854
}

src/http/api/resources/dns.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
const Boom = require('boom')
44

55
module.exports = async (request, h) => {
6-
if (!request.query.arg) {
6+
const domain = request.query.arg
7+
8+
if (!domain) {
79
throw Boom.badRequest("Argument 'domain' is required")
810
}
911

10-
const path = await request.server.app.ipfs.dns(request.query.arg)
12+
const format = request.query.format
13+
14+
// query parameters are passed as strings and need to be parsed to expected type
15+
let recursive = request.query.recursive || request.query.r
16+
recursive = !(recursive && recursive === 'false')
17+
18+
const path = await request.server.app.ipfs.dns(domain, { recursive, format })
1119
return h.response({
1220
Path: path
1321
})

test/cli/dns.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
const expect = require('chai').expect
55
const runOnAndOff = require('../utils/on-and-off')
6+
const isIPFS = require('is-ipfs')
67

78
describe('dns', () => runOnAndOff((thing) => {
89
let ipfs
@@ -12,19 +13,33 @@ describe('dns', () => runOnAndOff((thing) => {
1213
ipfs = thing.ipfs
1314
})
1415

15-
it('resolve ipfs.io dns', function () {
16+
it('recursively resolve ipfs.io dns', function () {
1617
this.timeout(60 * 1000)
1718

1819
return ipfs('dns ipfs.io').then((res) => {
19-
expect(res.substr(0, 6)).to.eql('/ipns/')
20+
expect(res.substr(0, 6)).to.eql('/ipfs/')
21+
const resultingDomainOrCid = res.split('/')[2].trim()
22+
expect(isIPFS.cid(resultingDomainOrCid)).to.eql(true)
2023
})
2124
})
2225

23-
it('resolve _dnslink.ipfs.io dns', function () {
26+
it('recursively resolve _dnslink.ipfs.io dns', function () {
2427
this.timeout(60 * 1000)
2528

2629
return ipfs('dns _dnslink.ipfs.io').then((res) => {
30+
expect(res.substr(0, 6)).to.eql('/ipfs/')
31+
const resultingDomainOrCid = res.split('/')[2].trim()
32+
expect(isIPFS.cid(resultingDomainOrCid)).to.eql(true)
33+
})
34+
})
35+
36+
it('non-recursive resolve ipfs.io', function () {
37+
this.timeout(60 * 1000)
38+
39+
return ipfs('dns --recursive false ipfs.io').then((res) => {
2740
expect(res.substr(0, 6)).to.eql('/ipns/')
41+
const resultingDomainOrCid = res.split('/')[2].trim()
42+
expect(isIPFS.cid(resultingDomainOrCid)).to.eql(false)
2843
})
2944
})
3045

0 commit comments

Comments
 (0)