Skip to content

Commit c0bfb8e

Browse files
committed
feat: add json option to spoofPacket, bump deps
1 parent 1134107 commit c0bfb8e

File tree

8 files changed

+94
-43
lines changed

8 files changed

+94
-43
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@
5151
* [`tangerine.resolveSoa(hostname[, options, abortController]))`](#tangerineresolvesoahostname-options-abortcontroller)
5252
* [`tangerine.resolveSrv(hostname[, options, abortController]))`](#tangerineresolvesrvhostname-options-abortcontroller)
5353
* [`tangerine.resolveTxt(hostname[, options, abortController]))`](#tangerineresolvetxthostname-options-abortcontroller)
54-
* [`tangerine.resolveCert(hostname, [, options, abortController]))`](#tangerineresolvecerthostname--options-abortcontroller)
55-
* [`tangerine.resolveTlsa(hostname, [, options, abortController]))`](#tangerineresolvetlsahostname--options-abortcontroller)
54+
* [`tangerine.resolveCert(hostname[, options, abortController]))`](#tangerineresolvecerthostname-options-abortcontroller)
55+
* [`tangerine.resolveTlsa(hostname[, options, abortController]))`](#tangerineresolvetlsahostname-options-abortcontroller)
5656
* [`tangerine.reverse(ip[, abortController, purgeCache])`](#tangerinereverseip-abortcontroller-purgecache)
5757
* [`tangerine.setDefaultResultOrder(order)`](#tangerinesetdefaultresultorderorder)
5858
* [`tangerine.setServers(servers)`](#tangerinesetserversservers)
59-
* [`tangerine.spoofPacket(hostname, rrtype, answers)`](#tangerinespoofpackethostname-rrtype-answers)
59+
* [`tangerine.spoofPacket(hostname, rrtype, answers[, json])`](#tangerinespoofpackethostname-rrtype-answers-json)
6060
* [Options](#options)
6161
* [Cache](#cache)
6262
* [Compatibility](#compatibility)
@@ -274,7 +274,7 @@ Tangerine supports a new `ecsSubnet` property in the `options` Object argument.
274274

275275
### `tangerine.resolveTxt(hostname[, options, abortController]))`
276276

277-
### `tangerine.resolveCert(hostname, [, options, abortController]))`
277+
### `tangerine.resolveCert(hostname[, options, abortController]))`
278278

279279
This function returns a Promise that resolves with an Array with parsed values from results:
280280

@@ -293,7 +293,7 @@ This function returns a Promise that resolves with an Array with parsed values f
293293

294294
This mirrors output from <https://github.com/rthalley/dnspython>.
295295

296-
### `tangerine.resolveTlsa(hostname, [, options, abortController]))`
296+
### `tangerine.resolveTlsa(hostname[, options, abortController]))`
297297

298298
This method was added for DANE and TLSA support. See this [excellent article](https://www.mailhardener.com/kb/dane), [index.js](https://github.com/forwardemail/tangerine/blob/main/index.js), and <https://github.com/nodejs/node/issues/39569> for more insight.
299299

@@ -332,12 +332,14 @@ This mirrors output from <https://github.com/rthalley/dnspython>.
332332
333333
### `tangerine.setServers(servers)`
334334
335-
### `tangerine.spoofPacket(hostname, rrtype, answers)`
335+
### `tangerine.spoofPacket(hostname, rrtype, answers[, json])`
336336
337337
This method is useful for writing tests to spoof DNS packets in-memory.
338338
339339
The `rrtype` must be either `"TXT"` or `"MX"`, and `answers` must be an Array of DNS resource record answers.
340340
341+
If you pass `json` as `true`, then value returned will be converted to JSON via `JSON.stringify`.
342+
341343
For example, if you want to spoof TXT and MX records:
342344
343345
```js

benchmarks/http.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const http = require('node:http');
22
const process = require('node:process');
3-
43
const Benchmark = require('benchmark');
54
const axios = require('axios');
65
const fetch = require('node-fetch');

benchmarks/lookup.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
const dns = require('node:dns');
2-
32
const Benchmark = require('benchmark');
4-
53
const Tangerine = require('..');
64

75
const opts = { timeout: 5000, tries: 1 };

benchmarks/resolve.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
const dns = require('node:dns');
2-
32
const Benchmark = require('benchmark');
4-
53
const Tangerine = require('..');
64

75
const opts = { timeout: 5000, tries: 1 };

benchmarks/reverse.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
const dns = require('node:dns');
2-
32
const Benchmark = require('benchmark');
4-
53
const Tangerine = require('..');
64

75
const opts = { timeout: 5000, tries: 1 };

index.js

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ const { Buffer } = require('node:buffer');
66
const { debuglog } = require('node:util');
77
const { getEventListeners, setMaxListeners } = require('node:events');
88
const { isIP, isIPv4, isIPv6 } = require('node:net');
9-
109
const { toASCII } = require('punycode/');
11-
1210
const autoBind = require('auto-bind');
1311
const getStream = require('get-stream');
1412
const hostile = require('hostile');
@@ -21,7 +19,6 @@ const packet = require('dns-packet');
2119
const semver = require('semver');
2220
const structuredClone = require('@ungap/structured-clone').default;
2321
const { getService } = require('port-numbers');
24-
2522
const pkg = require('./package.json');
2623

2724
const debug = debuglog('tangerine');
@@ -123,21 +120,21 @@ class Tangerine extends dns.promises.Resolver {
123120

124121
// if all errors had `name` and they were all the same then preserve it
125122
if (
126-
typeof errors[0].name !== 'undefined' &&
123+
errors[0].name !== undefined &&
127124
errors.every((e) => e.name === errors[0].name)
128125
)
129126
err.name = errors[0].name;
130127

131128
// if all errors had `code` and they were all the same then preserve it
132129
if (
133-
typeof errors[0].code !== 'undefined' &&
130+
errors[0].code !== undefined &&
134131
errors.every((e) => e.code === errors[0].code)
135132
)
136133
err.code = errors[0].code;
137134

138135
// if all errors had `errno` and they were all the same then preserve it
139136
if (
140-
typeof errors[0].errno !== 'undefined' &&
137+
errors[0].errno !== undefined &&
141138
errors.every((e) => e.errno === errors[0].errno)
142139
)
143140
err.errno = errors[0].errno;
@@ -607,7 +604,7 @@ class Tangerine extends dns.promises.Resolver {
607604

608605
options = { family: options };
609606
} else if (
610-
typeof options?.family !== 'undefined' &&
607+
options?.family !== undefined &&
611608
![0, 4, 6, 'IPv4', 'IPv6'].includes(options.family)
612609
) {
613610
// validate family
@@ -761,7 +758,7 @@ class Tangerine extends dns.promises.Resolver {
761758
if (answers.length > 0)
762759
answers =
763760
answers[0].length > 0 &&
764-
(typeof options.family === 'undefined' || options.family === 0)
761+
(options.family === undefined || options.family === 0)
765762
? answers[0]
766763
: answers.flat();
767764

@@ -1428,7 +1425,7 @@ class Tangerine extends dns.promises.Resolver {
14281425
this.options.servers = new Set(servers);
14291426
}
14301427

1431-
spoofPacket(name, rrtype, answers = []) {
1428+
spoofPacket(name, rrtype, answers = [], json = false) {
14321429
if (typeof name !== 'string') {
14331430
const err = new TypeError('The "name" argument must be of type string.');
14341431
err.code = 'ERR_INVALID_ARG_TYPE';
@@ -1455,7 +1452,7 @@ class Tangerine extends dns.promises.Resolver {
14551452
throw err;
14561453
}
14571454

1458-
return {
1455+
const obj = {
14591456
id: 0,
14601457
type: 'response',
14611458
flags: 384,
@@ -1494,6 +1491,8 @@ class Tangerine extends dns.promises.Resolver {
14941491
ttl: 300,
14951492
expires: Date.now() + 10000
14961493
};
1494+
1495+
return json ? JSON.stringify(obj) : obj;
14971496
}
14981497

14991498
// eslint-disable-next-line complexity
@@ -1909,11 +1908,10 @@ class Tangerine extends dns.promises.Resolver {
19091908
algorithm: answer.data.subarray(4, 5).readUInt8(),
19101909
certificate: answer.data.subarray(5).toString('base64')
19111910
};
1912-
obj.certificate_type = this.constructor.CTYPE_BY_VALUE[
1913-
obj.certificate_type
1914-
]
1915-
? this.constructor.CTYPE_BY_VALUE[obj.certificate_type]
1916-
: obj.certificate_type.toString();
1911+
if (this.constructor.CTYPE_BY_VALUE[obj.certificate_type])
1912+
obj.certificate_type =
1913+
this.constructor.CTYPE_BY_VALUE[obj.certificate_type];
1914+
else obj.certificate_type = obj.certificate_type.toString();
19171915
return obj;
19181916
} catch (err) {
19191917
this.options.logger.error(err, { name, rrtype, options, answer });

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
"Forward Email (https://forwardemail.net)"
1111
],
1212
"dependencies": {
13-
"@ungap/structured-clone": "^1.0.2",
13+
"@ungap/structured-clone": "^1.2.0",
1414
"auto-bind": "4",
15-
"dns-packet": "^5.4.0",
15+
"dns-packet": "^5.6.0",
1616
"dohdec": "^5.0.3",
1717
"get-stream": "6",
1818
"hostile": "^1.3.3",
@@ -21,16 +21,16 @@
2121
"p-map": "4",
2222
"p-timeout": "4",
2323
"p-wait-for": "3",
24-
"port-numbers": "^6.0.1",
24+
"port-numbers": "6.0.1",
2525
"private-ip": "^3.0.0",
2626
"punycode": "^2.3.0",
27-
"semver": "^7.3.8"
27+
"semver": "^7.5.1"
2828
},
2929
"devDependencies": {
30-
"@commitlint/cli": "^17.4.4",
31-
"@commitlint/config-conventional": "^17.4.4",
30+
"@commitlint/cli": "^17.6.3",
31+
"@commitlint/config-conventional": "^17.6.3",
3232
"ava": "^5.2.0",
33-
"axios": "^1.3.4",
33+
"axios": "^1.4.0",
3434
"benchmark": "^2.1.4",
3535
"cross-env": "^7.0.3",
3636
"eslint": "^8.34.0",
@@ -39,12 +39,12 @@
3939
"fixpack": "^4.0.0",
4040
"got": "11",
4141
"husky": "^8.0.3",
42-
"ioredis": "^5.3.1",
43-
"ioredis-mock": "^8.2.6",
42+
"ioredis": "^5.3.2",
43+
"ioredis-mock": "^8.7.0",
4444
"is-ci": "^3.0.1",
45-
"lint-staged": "^13.1.2",
45+
"lint-staged": "^13.2.2",
4646
"lodash": "^4.17.21",
47-
"nock": "^13.3.0",
47+
"nock": "^13.3.1",
4848
"node-fetch": "2",
4949
"nyc": "^15.1.0",
5050
"phin": "^3.7.0",
@@ -53,8 +53,8 @@
5353
"request": "^2.88.2",
5454
"sort-keys": "4.2.0",
5555
"superagent": "^8.0.9",
56-
"undici": "^5.20.0",
57-
"xo": "^0.53.1"
56+
"undici": "^5.22.1",
57+
"xo": "^0.54.2"
5858
},
5959
"engines": {
6060
"node": ">=16"

test/test.js

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ const dns = require('node:dns');
22
const fs = require('node:fs');
33
const { Buffer } = require('node:buffer');
44
const { isIP, isIPv4, isIPv6 } = require('node:net');
5-
65
const isCI = require('is-ci');
76
const Redis = require('ioredis-mock');
87
const _ = require('lodash');
98
const got = require('got');
109
const sortKeys = require('sort-keys');
1110
const test = require('ava');
12-
1311
const Tangerine = require('..');
1412

1513
const { Resolver } = dns.promises;
@@ -949,6 +947,66 @@ test('resolveTlsa', async (t) => {
949947
}
950948
});
951949

950+
test('spoofPacket with json', async (t) => {
951+
const cache = new Redis();
952+
const tangerine = new Tangerine({ cache });
953+
954+
const txt = tangerine.spoofPacket(
955+
'forwardemail.net',
956+
'TXT',
957+
[`v=spf1 ip4:127.0.0.1 -all`],
958+
true
959+
);
960+
961+
t.deepEqual(_.omit(JSON.parse(txt), ['expires']), {
962+
id: 0,
963+
type: 'response',
964+
flags: 384,
965+
flag_qr: true,
966+
opcode: 'QUERY',
967+
flag_aa: false,
968+
flag_tc: false,
969+
flag_rd: true,
970+
flag_ra: true,
971+
flag_z: false,
972+
flag_ad: false,
973+
flag_cd: false,
974+
rcode: 'NOERROR',
975+
questions: [{ name: 'forwardemail.net', type: 'TXT', class: 'IN' }],
976+
answers: [
977+
{
978+
name: 'forwardemail.net',
979+
type: 'TXT',
980+
ttl: 300,
981+
class: 'IN',
982+
flush: false,
983+
data: ['v=spf1 ip4:127.0.0.1 -all']
984+
}
985+
],
986+
authorities: [],
987+
additionals: [
988+
{
989+
name: '.',
990+
type: 'OPT',
991+
udpPayloadSize: 1232,
992+
extendedRcode: 0,
993+
ednsVersion: 0,
994+
flags: 0,
995+
flag_do: false,
996+
options: [null]
997+
}
998+
],
999+
ttl: 300
1000+
// expires: 1684087106042
1001+
});
1002+
1003+
await cache.set('txt:forwardemail.net', txt);
1004+
1005+
const txtDns = await tangerine.resolveTxt('forwardemail.net');
1006+
1007+
t.deepEqual(txtDns, [['v=spf1 ip4:127.0.0.1 -all']]);
1008+
});
1009+
9521010
test('spoofPacket', async (t) => {
9531011
const cache = new Redis();
9541012
const tangerine = new Tangerine({ cache });

0 commit comments

Comments
 (0)