dns2 2.0.5 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -7
- package/client/doh.js +80 -40
- package/client/google.js +1 -1
- package/client/tcp.js +43 -28
- package/client/udp.js +81 -13
- package/example/client/doh.js +18 -8
- package/index.js +27 -17
- package/lib/reader.js +4 -2
- package/lib/writer.js +0 -1
- package/package.json +27 -13
- package/packet.js +232 -49
- package/server/dns.js +19 -2
- package/server/doh.js +9 -8
- package/server/tcp.js +1 -1
- package/server/udp.js +2 -2
- package/ts/index.d.ts +371 -0
- package/ts/tsconfig.json +13 -0
- package/ts/typings-check.ts +124 -0
- package/.eslintrc +0 -16
- package/.github/FUNDING.yml +0 -12
- package/.github/workflows/lint.js.yml +0 -17
- package/.github/workflows/node.js.yml +0 -29
- package/SECURITY.md +0 -21
- package/test/index.js +0 -402
- package/test/test.js +0 -34
package/package.json
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dns2",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "A DNS Server and Client Implementation in Pure JavaScript with no dependencies.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "ts/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"client",
|
|
10
|
+
"server",
|
|
11
|
+
"packet.js",
|
|
12
|
+
"example",
|
|
13
|
+
"ts"
|
|
14
|
+
],
|
|
6
15
|
"scripts": {
|
|
7
|
-
"test": "node test",
|
|
8
|
-
"
|
|
16
|
+
"test": "node --test",
|
|
17
|
+
"test:coverage": "node --test --experimental-test-coverage",
|
|
18
|
+
"test:coverage:lcov": "mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info",
|
|
19
|
+
"lint": "npx eslint .",
|
|
20
|
+
"lint:fix": "npx eslint . --fix",
|
|
9
21
|
"example-server-udp": "node example/server/udp.js",
|
|
10
22
|
"example-server-tcp": "node example/server/tcp.js",
|
|
11
23
|
"example-server-doh": "node example/server/doh.js",
|
|
@@ -13,30 +25,32 @@
|
|
|
13
25
|
"example-client-udp": "node example/client/udp.js",
|
|
14
26
|
"example-client-tcp": "node example/client/tcp.js",
|
|
15
27
|
"example-client-google": "node example/client/google.js",
|
|
16
|
-
"example-client-udp-subnet": "node example/client/udp-subnet.js"
|
|
28
|
+
"example-client-udp-subnet": "node example/client/udp-subnet.js",
|
|
29
|
+
"benchmark": "node benchmark/udp.js"
|
|
17
30
|
},
|
|
18
31
|
"keywords": [
|
|
19
32
|
"dns"
|
|
20
33
|
],
|
|
21
|
-
"author": "Liu Song <
|
|
34
|
+
"author": "Liu Song <song940@gmail.com>",
|
|
22
35
|
"contributors": [
|
|
23
36
|
"Andris Reinman <andris.reinman@gmail.com>",
|
|
24
37
|
"Eviltik <eviltik@gmail.com>",
|
|
25
|
-
"Martin Heidegger <martin.heidegger@gmail.com>"
|
|
38
|
+
"Martin Heidegger <martin.heidegger@gmail.com>",
|
|
39
|
+
"Matt Simerson <matt@tnpi.net>"
|
|
26
40
|
],
|
|
27
41
|
"license": "MIT",
|
|
28
42
|
"repository": {
|
|
29
43
|
"type": "git",
|
|
30
|
-
"url": "git+https://github.com/
|
|
44
|
+
"url": "git+https://github.com/lsongdev/node-dns.git"
|
|
31
45
|
},
|
|
32
46
|
"bugs": {
|
|
33
|
-
"url": "https://github.com/
|
|
47
|
+
"url": "https://github.com/lsongdev/node-dns/issues"
|
|
34
48
|
},
|
|
35
|
-
"homepage": "https://github.com/
|
|
49
|
+
"homepage": "https://github.com/lsongdev/node-dns#readme",
|
|
36
50
|
"devDependencies": {
|
|
37
|
-
"eslint": "^
|
|
38
|
-
"eslint-
|
|
39
|
-
"eslint
|
|
40
|
-
"
|
|
51
|
+
"@eslint/js": "^10.0.1",
|
|
52
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
53
|
+
"eslint": "^10.4.0",
|
|
54
|
+
"globals": "^17.6.0"
|
|
41
55
|
}
|
|
42
56
|
}
|
package/packet.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const { debuglog } = require('util');
|
|
1
|
+
const { debuglog } = require('node:util');
|
|
2
|
+
const { randomInt } = require('node:crypto');
|
|
2
3
|
const BufferReader = require('./lib/reader');
|
|
3
4
|
const BufferWriter = require('./lib/writer');
|
|
4
5
|
|
|
@@ -9,6 +10,34 @@ const toIPv6 = buffer => buffer
|
|
|
9
10
|
.join(':')
|
|
10
11
|
.replace(/\b(?:0+:){1,}/, ':');
|
|
11
12
|
|
|
13
|
+
const fromIPv6 = (address) => {
|
|
14
|
+
const digits = address.split(':');
|
|
15
|
+
// CAVEAT edge case for :: and IPs starting
|
|
16
|
+
// or ending by ::
|
|
17
|
+
if (digits[0] === '') {
|
|
18
|
+
digits.shift();
|
|
19
|
+
}
|
|
20
|
+
if (digits[digits.length - 1] === '') {
|
|
21
|
+
digits.pop();
|
|
22
|
+
}
|
|
23
|
+
// node js 10 does not support Array.prototype.flatMap
|
|
24
|
+
if (!Array.prototype.flatMap) {
|
|
25
|
+
Array.prototype.flatMap = function(f, ctx) {
|
|
26
|
+
return this.reduce((r, x, i, a) => r.concat(f.call(ctx, x, i, a)), []);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// CAVEAT we have to take into account
|
|
31
|
+
// the extra space used by the empty string
|
|
32
|
+
const missingFields = 8 - digits.length + 1;
|
|
33
|
+
return digits.flatMap((digit) => {
|
|
34
|
+
if (digit === '') {
|
|
35
|
+
return Array(missingFields).fill('0');
|
|
36
|
+
}
|
|
37
|
+
return digit.padStart(4, '0');
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
12
41
|
/**
|
|
13
42
|
* [Packet description]
|
|
14
43
|
* @param {[type]} data [description]
|
|
@@ -55,31 +84,32 @@ function Packet(data) {
|
|
|
55
84
|
* @docs https://tools.ietf.org/html/rfc1035#section-3.2.2
|
|
56
85
|
*/
|
|
57
86
|
Packet.TYPE = {
|
|
58
|
-
A
|
|
59
|
-
NS
|
|
60
|
-
MD
|
|
61
|
-
MF
|
|
62
|
-
CNAME
|
|
63
|
-
SOA
|
|
64
|
-
MB
|
|
65
|
-
MG
|
|
66
|
-
MR
|
|
67
|
-
NULL
|
|
68
|
-
WKS
|
|
69
|
-
PTR
|
|
70
|
-
HINFO
|
|
71
|
-
MINFO
|
|
72
|
-
MX
|
|
73
|
-
TXT
|
|
74
|
-
AAAA
|
|
75
|
-
SRV
|
|
76
|
-
EDNS
|
|
77
|
-
SPF
|
|
78
|
-
AXFR
|
|
79
|
-
MAILB
|
|
80
|
-
MAILA
|
|
81
|
-
ANY
|
|
82
|
-
CAA
|
|
87
|
+
A : 0x01,
|
|
88
|
+
NS : 0x02,
|
|
89
|
+
MD : 0x03,
|
|
90
|
+
MF : 0x04,
|
|
91
|
+
CNAME : 0x05,
|
|
92
|
+
SOA : 0x06,
|
|
93
|
+
MB : 0x07,
|
|
94
|
+
MG : 0x08,
|
|
95
|
+
MR : 0x09,
|
|
96
|
+
NULL : 0x0A,
|
|
97
|
+
WKS : 0x0B,
|
|
98
|
+
PTR : 0x0C,
|
|
99
|
+
HINFO : 0x0D,
|
|
100
|
+
MINFO : 0x0E,
|
|
101
|
+
MX : 0x0F,
|
|
102
|
+
TXT : 0x10,
|
|
103
|
+
AAAA : 0x1C,
|
|
104
|
+
SRV : 0x21,
|
|
105
|
+
EDNS : 0x29,
|
|
106
|
+
SPF : 0x63,
|
|
107
|
+
AXFR : 0xFC,
|
|
108
|
+
MAILB : 0xFD,
|
|
109
|
+
MAILA : 0xFE,
|
|
110
|
+
ANY : 0xFF,
|
|
111
|
+
CAA : 0x101,
|
|
112
|
+
DNSKEY : 0x30,
|
|
83
113
|
};
|
|
84
114
|
/**
|
|
85
115
|
* [QUERY_CLASS description]
|
|
@@ -93,6 +123,19 @@ Packet.CLASS = {
|
|
|
93
123
|
HS : 0x04,
|
|
94
124
|
ANY : 0xFF,
|
|
95
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* DNS response codes
|
|
128
|
+
* @type {Object}
|
|
129
|
+
* @docs https://tools.ietf.org/html/rfc1035#section-4.1.1
|
|
130
|
+
*/
|
|
131
|
+
Packet.RCODE = {
|
|
132
|
+
NOERROR : 0,
|
|
133
|
+
FORMERR : 1,
|
|
134
|
+
SERVFAIL : 2,
|
|
135
|
+
NXDOMAIN : 3,
|
|
136
|
+
NOTIMP : 4,
|
|
137
|
+
REFUSED : 5,
|
|
138
|
+
};
|
|
96
139
|
/**
|
|
97
140
|
* [EDNS_OPTION_CODE description]
|
|
98
141
|
* @type {Object}
|
|
@@ -103,11 +146,13 @@ Packet.EDNS_OPTION_CODE = {
|
|
|
103
146
|
};
|
|
104
147
|
|
|
105
148
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
149
|
+
* Generate a cryptographically random 16-bit DNS transaction ID.
|
|
150
|
+
* RFC 5452 §3 — the full 16-bit space must be used from a CSPRNG to make
|
|
151
|
+
* response forgery / cache poisoning impractical.
|
|
152
|
+
* @return {number} integer in [0, 0xFFFF]
|
|
108
153
|
*/
|
|
109
154
|
Packet.uuid = function() {
|
|
110
|
-
return
|
|
155
|
+
return randomInt(0x10000);
|
|
111
156
|
};
|
|
112
157
|
|
|
113
158
|
/**
|
|
@@ -151,7 +196,6 @@ Object.defineProperty(Packet.prototype, 'recursive', {
|
|
|
151
196
|
},
|
|
152
197
|
set(yn) {
|
|
153
198
|
this.header.rd = +yn;
|
|
154
|
-
return this.header.rd;
|
|
155
199
|
},
|
|
156
200
|
});
|
|
157
201
|
|
|
@@ -358,9 +402,18 @@ Packet.Resource.encode = function(resource, writer) {
|
|
|
358
402
|
})[0];
|
|
359
403
|
if (encoder in Packet.Resource && Packet.Resource[encoder].encode) {
|
|
360
404
|
return Packet.Resource[encoder].encode(resource, writer);
|
|
361
|
-
} else {
|
|
362
|
-
debug('node-dns > unknown encoder %s(%j)', encoder, resource.type);
|
|
363
405
|
}
|
|
406
|
+
debug('node-dns > unknown encoder %s(%j)', encoder, resource.type);
|
|
407
|
+
// Fallback for unknown / decoder-only types: round-trip the raw RDATA the
|
|
408
|
+
// decoder preserved as `resource.data`. Without this, RDLENGTH and RDATA
|
|
409
|
+
// would be omitted entirely, truncating the wire format and corrupting any
|
|
410
|
+
// records that follow.
|
|
411
|
+
const data = Buffer.isBuffer(resource.data) ? resource.data : Buffer.alloc(0);
|
|
412
|
+
writer.write(data.length, 16);
|
|
413
|
+
for (const byte of data) {
|
|
414
|
+
writer.write(byte, 8);
|
|
415
|
+
}
|
|
416
|
+
return writer.toBuffer();
|
|
364
417
|
};
|
|
365
418
|
/**
|
|
366
419
|
* [parse description]
|
|
@@ -524,7 +577,7 @@ Packet.Resource.AAAA = {
|
|
|
524
577
|
},
|
|
525
578
|
encode: function(record, writer) {
|
|
526
579
|
writer = writer || new Packet.Writer();
|
|
527
|
-
const parts = record.address
|
|
580
|
+
const parts = fromIPv6(record.address);
|
|
528
581
|
writer.write(parts.length * 2, 16);
|
|
529
582
|
parts.forEach(function(part) {
|
|
530
583
|
writer.write(parseInt(part, 16), 16);
|
|
@@ -576,7 +629,7 @@ Packet.Resource.SPF =
|
|
|
576
629
|
Packet.Resource.TXT = {
|
|
577
630
|
decode: function(reader, length) {
|
|
578
631
|
const parts = [];
|
|
579
|
-
let bytesRead = 0; let chunkLength
|
|
632
|
+
let bytesRead = 0; let chunkLength;
|
|
580
633
|
|
|
581
634
|
while (bytesRead < length) {
|
|
582
635
|
chunkLength = reader.read(8); // text length
|
|
@@ -764,21 +817,30 @@ Packet.Resource.EDNS.ECS.decode = function(reader, length) {
|
|
|
764
817
|
rdata.scopePrefixLength = reader.read(8);
|
|
765
818
|
length -= 4;
|
|
766
819
|
|
|
767
|
-
if (rdata.family
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
820
|
+
if (rdata.family === 1) {
|
|
821
|
+
const ipv4Octets = [];
|
|
822
|
+
while (length--) {
|
|
823
|
+
const octet = reader.read(8);
|
|
824
|
+
ipv4Octets.push(octet);
|
|
825
|
+
}
|
|
826
|
+
while (ipv4Octets.length < 4) {
|
|
827
|
+
ipv4Octets.push(0);
|
|
828
|
+
}
|
|
829
|
+
rdata.ip = ipv4Octets.join('.');
|
|
771
830
|
}
|
|
772
831
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
832
|
+
if (rdata.family === 2) {
|
|
833
|
+
const ipv6Segments = [];
|
|
834
|
+
for (; length; length -= 2) {
|
|
835
|
+
const segment = reader.read(16).toString(16);
|
|
836
|
+
ipv6Segments.push(segment);
|
|
837
|
+
}
|
|
838
|
+
while (ipv6Segments.length < 8) {
|
|
839
|
+
ipv6Segments.push('0');
|
|
840
|
+
}
|
|
841
|
+
rdata.ip = ipv6Segments.join(':');
|
|
780
842
|
}
|
|
781
|
-
|
|
843
|
+
|
|
782
844
|
return rdata;
|
|
783
845
|
};
|
|
784
846
|
|
|
@@ -807,15 +869,135 @@ Packet.Resource.CAA = {
|
|
|
807
869
|
});
|
|
808
870
|
return writer.toBuffer();
|
|
809
871
|
},
|
|
872
|
+
decode: function(reader, length) {
|
|
873
|
+
this.flags = reader.read(8);
|
|
874
|
+
const tagLength = reader.read(8);
|
|
875
|
+
const bytes = [];
|
|
876
|
+
let remaining = length - 2;
|
|
877
|
+
while (remaining--) bytes.push(reader.read(8));
|
|
878
|
+
const buffer = Buffer.from(bytes);
|
|
879
|
+
this.tag = buffer.slice(0, tagLength).toString('utf8');
|
|
880
|
+
this.value = buffer.slice(tagLength).toString('utf8');
|
|
881
|
+
return this;
|
|
882
|
+
},
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* @type {{decode: (function(*, *): Packet.Resource.DNSKEY)}}
|
|
887
|
+
* @link https://tools.ietf.org/html/rfc4034
|
|
888
|
+
* @link https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#table-dns-sec-alg-numbers-1
|
|
889
|
+
*/
|
|
890
|
+
Packet.Resource.DNSKEY = {
|
|
891
|
+
decode: function(reader, length) {
|
|
892
|
+
const RData = [];
|
|
893
|
+
while (RData.length < length) {
|
|
894
|
+
RData.push(reader.read(8));
|
|
895
|
+
}
|
|
896
|
+
this.flags = RData[0] << 8 | RData[1];
|
|
897
|
+
this.protocol = RData[2];
|
|
898
|
+
this.algorithm = RData[3];
|
|
899
|
+
// for key tag
|
|
900
|
+
let ac = 0;
|
|
901
|
+
for (let i = 0; i < length; ++i) {
|
|
902
|
+
ac += (i & 1) ? RData[i] : RData[i] << 8;
|
|
903
|
+
}
|
|
904
|
+
ac += (ac >> 16) & 0xFFFF;
|
|
905
|
+
this.keyTag = ac & 0XFFFF;
|
|
906
|
+
|
|
907
|
+
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 = 16
|
|
908
|
+
// convert binary flags
|
|
909
|
+
let binFlags = this.flags.toString(2);
|
|
910
|
+
// add left padding until 16 chars
|
|
911
|
+
while (binFlags.length < 16) {
|
|
912
|
+
binFlags = '0' + binFlags;
|
|
913
|
+
}
|
|
914
|
+
this.zoneKey = binFlags[7] === '1';
|
|
915
|
+
this.zoneSep = binFlags[15] === '1';
|
|
916
|
+
this.key = Buffer.from(RData.slice(4)).toString('base64');
|
|
917
|
+
return this;
|
|
918
|
+
},
|
|
919
|
+
encode: function(record, writer) {
|
|
920
|
+
writer = writer || new Packet.Writer();
|
|
921
|
+
const buffer = Buffer.from(record.key, 'base64');
|
|
922
|
+
writer.write(4 + buffer.length, 16);
|
|
923
|
+
writer.write(record.flags, 16);
|
|
924
|
+
writer.write(record.protocol, 8);
|
|
925
|
+
writer.write(record.algorithm, 8);
|
|
926
|
+
buffer.forEach(function(c) {
|
|
927
|
+
writer.write(c, 8);
|
|
928
|
+
});
|
|
929
|
+
return writer.toBuffer();
|
|
930
|
+
},
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* RRSIG just support decode
|
|
935
|
+
* test with dns.resolveRRSIG('example.com')
|
|
936
|
+
*
|
|
937
|
+
* @type {{decode: (function(*, *): Packet.Resource.RRSIG)}}
|
|
938
|
+
*/
|
|
939
|
+
Packet.Resource.RRSIG = {
|
|
940
|
+
decode: function(reader, length) {
|
|
941
|
+
function dateForSig(date) {
|
|
942
|
+
// javascript date is from millisecond
|
|
943
|
+
date = new Date(date * 1000);
|
|
944
|
+
const definitions = {
|
|
945
|
+
month : (date.getUTCMonth() + 1),
|
|
946
|
+
date : date.getUTCDate(),
|
|
947
|
+
hour : date.getUTCHours(),
|
|
948
|
+
minutes : date.getUTCMinutes(),
|
|
949
|
+
seconds : date.getUTCSeconds(),
|
|
950
|
+
};
|
|
951
|
+
let i;
|
|
952
|
+
for (i in definitions) {
|
|
953
|
+
// if less than 10 > single
|
|
954
|
+
if (definitions[i] < 10) {
|
|
955
|
+
definitions[i] = '0' + '' + definitions[i];
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return date.getFullYear() + '' +
|
|
959
|
+
definitions.month + '' +
|
|
960
|
+
definitions.date + '' +
|
|
961
|
+
definitions.hour + '' +
|
|
962
|
+
definitions.minutes + '' +
|
|
963
|
+
definitions.seconds;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// calculate max-offset uint8
|
|
967
|
+
const maxOffset = reader.offset + (length * 8);
|
|
968
|
+
/*
|
|
969
|
+
* Stuff sign contains 18 octets
|
|
970
|
+
*/
|
|
971
|
+
this.sigType = reader.read(16); // 2
|
|
972
|
+
this.algorithm = reader.read(8); // 1
|
|
973
|
+
this.labels = reader.read(8); // 1
|
|
974
|
+
this.originalTtl = reader.read(32); // 4
|
|
975
|
+
this.expiration = dateForSig(reader.read(32)); // 4
|
|
976
|
+
this.inception = dateForSig(reader.read(32)); // 4
|
|
977
|
+
this.keyTag = reader.read(16); // 2
|
|
978
|
+
this.signer = Packet.Name.decode(reader);
|
|
979
|
+
const maxLength = (maxOffset - reader.offset) / 8;
|
|
980
|
+
const signature = [];
|
|
981
|
+
while (signature.length < maxLength) {
|
|
982
|
+
signature.push(reader.read(8));
|
|
983
|
+
}
|
|
984
|
+
this.signature = Buffer.from(signature).toString('base64');
|
|
985
|
+
return this;
|
|
986
|
+
},
|
|
810
987
|
};
|
|
811
988
|
|
|
812
989
|
Packet.Reader = BufferReader;
|
|
813
990
|
Packet.Writer = BufferWriter;
|
|
814
991
|
|
|
815
992
|
Packet.createResponseFromRequest = function(request) {
|
|
816
|
-
const response = new Packet(
|
|
817
|
-
response.header
|
|
818
|
-
|
|
993
|
+
const response = new Packet();
|
|
994
|
+
response.header = new Packet.Header({
|
|
995
|
+
id : request.header.id,
|
|
996
|
+
opcode : request.header.opcode,
|
|
997
|
+
rd : request.header.rd,
|
|
998
|
+
qr : 1,
|
|
999
|
+
});
|
|
1000
|
+
response.questions = request.questions.slice();
|
|
819
1001
|
return response;
|
|
820
1002
|
};
|
|
821
1003
|
|
|
@@ -874,3 +1056,4 @@ Packet.prototype.toBase64URL = function() {
|
|
|
874
1056
|
|
|
875
1057
|
module.exports = Packet;
|
|
876
1058
|
module.exports.toIPv6 = toIPv6;
|
|
1059
|
+
module.exports.fromIPv6 = fromIPv6;
|
package/server/dns.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const EventEmitter = require('events');
|
|
1
|
+
const EventEmitter = require('node:events');
|
|
2
|
+
const Packet = require('../packet');
|
|
2
3
|
const DOHServer = require('./doh');
|
|
3
4
|
const TCPServer = require('./tcp');
|
|
4
5
|
const UDPServer = require('./udp');
|
|
@@ -34,7 +35,23 @@ class DNSServer extends EventEmitter {
|
|
|
34
35
|
return addresses;
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
+
const maxConcurrent = options.maxConcurrent > 0 ? options.maxConcurrent : 0;
|
|
39
|
+
let active = 0;
|
|
40
|
+
|
|
41
|
+
const emitRequest = (request, send, client) => {
|
|
42
|
+
if (maxConcurrent && active >= maxConcurrent) {
|
|
43
|
+
const response = Packet.createResponseFromRequest(request);
|
|
44
|
+
response.header.rcode = Packet.RCODE.SERVFAIL;
|
|
45
|
+
send(response);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
active++;
|
|
49
|
+
const wrappedSend = (...args) => {
|
|
50
|
+
active--;
|
|
51
|
+
return send(...args);
|
|
52
|
+
};
|
|
53
|
+
this.emit('request', request, wrappedSend, client);
|
|
54
|
+
};
|
|
38
55
|
const emitRequestError = (error) => this.emit('requestError', error);
|
|
39
56
|
for (const server of servers) {
|
|
40
57
|
server.on('request', emitRequest);
|
package/server/doh.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const https = require('https');
|
|
3
|
-
const { URL } = require('url');
|
|
1
|
+
const http = require('node:http');
|
|
2
|
+
const https = require('node:https');
|
|
3
|
+
const { URL } = require('node:url');
|
|
4
4
|
const Packet = require('../packet');
|
|
5
|
-
const EventEmitter = require('events');
|
|
6
|
-
const { debuglog } = require('util');
|
|
5
|
+
const EventEmitter = require('node:events');
|
|
6
|
+
const { debuglog } = require('node:util');
|
|
7
7
|
|
|
8
8
|
const debug = debuglog('dns2-server');
|
|
9
9
|
|
|
@@ -20,11 +20,11 @@ const decodeBase64URL = str => {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const readStream = stream => new Promise((resolve, reject) => {
|
|
23
|
-
|
|
23
|
+
const chunks = [];
|
|
24
24
|
stream
|
|
25
25
|
.on('error', reject)
|
|
26
|
-
.on('data', chunk =>
|
|
27
|
-
.on('end', () => resolve(
|
|
26
|
+
.on('data', chunk => chunks.push(chunk))
|
|
27
|
+
.on('end', () => resolve(Buffer.concat(chunks)));
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
class Server extends EventEmitter {
|
|
@@ -139,6 +139,7 @@ class Server extends EventEmitter {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
close() {
|
|
142
|
+
this.server.closeIdleConnections();
|
|
142
143
|
return this.server.close();
|
|
143
144
|
}
|
|
144
145
|
}
|
package/server/tcp.js
CHANGED
package/server/udp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const udp = require('dgram');
|
|
1
|
+
const udp = require('node:dgram');
|
|
2
2
|
const Packet = require('../packet');
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -10,7 +10,7 @@ class Server extends udp.Socket {
|
|
|
10
10
|
constructor(options) {
|
|
11
11
|
let type = 'udp4';
|
|
12
12
|
if (typeof options === 'object') {
|
|
13
|
-
type = options.type;
|
|
13
|
+
type = options.type ?? type;
|
|
14
14
|
}
|
|
15
15
|
super(type);
|
|
16
16
|
if (typeof options === 'function') {
|