dns2 2.1.0 → 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 +26 -12
- package/packet.js +209 -48
- 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 -413
- package/test/test.js +0 -34
package/package.json
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dns2",
|
|
3
|
-
"version": "2.1
|
|
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,7 +25,8 @@
|
|
|
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"
|
|
@@ -22,21 +35,22 @@
|
|
|
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
|
|
|
@@ -19,6 +20,13 @@ const fromIPv6 = (address) => {
|
|
|
19
20
|
if (digits[digits.length - 1] === '') {
|
|
20
21
|
digits.pop();
|
|
21
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
|
+
|
|
22
30
|
// CAVEAT we have to take into account
|
|
23
31
|
// the extra space used by the empty string
|
|
24
32
|
const missingFields = 8 - digits.length + 1;
|
|
@@ -76,31 +84,32 @@ function Packet(data) {
|
|
|
76
84
|
* @docs https://tools.ietf.org/html/rfc1035#section-3.2.2
|
|
77
85
|
*/
|
|
78
86
|
Packet.TYPE = {
|
|
79
|
-
A
|
|
80
|
-
NS
|
|
81
|
-
MD
|
|
82
|
-
MF
|
|
83
|
-
CNAME
|
|
84
|
-
SOA
|
|
85
|
-
MB
|
|
86
|
-
MG
|
|
87
|
-
MR
|
|
88
|
-
NULL
|
|
89
|
-
WKS
|
|
90
|
-
PTR
|
|
91
|
-
HINFO
|
|
92
|
-
MINFO
|
|
93
|
-
MX
|
|
94
|
-
TXT
|
|
95
|
-
AAAA
|
|
96
|
-
SRV
|
|
97
|
-
EDNS
|
|
98
|
-
SPF
|
|
99
|
-
AXFR
|
|
100
|
-
MAILB
|
|
101
|
-
MAILA
|
|
102
|
-
ANY
|
|
103
|
-
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,
|
|
104
113
|
};
|
|
105
114
|
/**
|
|
106
115
|
* [QUERY_CLASS description]
|
|
@@ -114,6 +123,19 @@ Packet.CLASS = {
|
|
|
114
123
|
HS : 0x04,
|
|
115
124
|
ANY : 0xFF,
|
|
116
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
|
+
};
|
|
117
139
|
/**
|
|
118
140
|
* [EDNS_OPTION_CODE description]
|
|
119
141
|
* @type {Object}
|
|
@@ -124,11 +146,13 @@ Packet.EDNS_OPTION_CODE = {
|
|
|
124
146
|
};
|
|
125
147
|
|
|
126
148
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
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]
|
|
129
153
|
*/
|
|
130
154
|
Packet.uuid = function() {
|
|
131
|
-
return
|
|
155
|
+
return randomInt(0x10000);
|
|
132
156
|
};
|
|
133
157
|
|
|
134
158
|
/**
|
|
@@ -172,7 +196,6 @@ Object.defineProperty(Packet.prototype, 'recursive', {
|
|
|
172
196
|
},
|
|
173
197
|
set(yn) {
|
|
174
198
|
this.header.rd = +yn;
|
|
175
|
-
return this.header.rd;
|
|
176
199
|
},
|
|
177
200
|
});
|
|
178
201
|
|
|
@@ -379,9 +402,18 @@ Packet.Resource.encode = function(resource, writer) {
|
|
|
379
402
|
})[0];
|
|
380
403
|
if (encoder in Packet.Resource && Packet.Resource[encoder].encode) {
|
|
381
404
|
return Packet.Resource[encoder].encode(resource, writer);
|
|
382
|
-
} else {
|
|
383
|
-
debug('node-dns > unknown encoder %s(%j)', encoder, resource.type);
|
|
384
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();
|
|
385
417
|
};
|
|
386
418
|
/**
|
|
387
419
|
* [parse description]
|
|
@@ -597,7 +629,7 @@ Packet.Resource.SPF =
|
|
|
597
629
|
Packet.Resource.TXT = {
|
|
598
630
|
decode: function(reader, length) {
|
|
599
631
|
const parts = [];
|
|
600
|
-
let bytesRead = 0; let chunkLength
|
|
632
|
+
let bytesRead = 0; let chunkLength;
|
|
601
633
|
|
|
602
634
|
while (bytesRead < length) {
|
|
603
635
|
chunkLength = reader.read(8); // text length
|
|
@@ -785,21 +817,30 @@ Packet.Resource.EDNS.ECS.decode = function(reader, length) {
|
|
|
785
817
|
rdata.scopePrefixLength = reader.read(8);
|
|
786
818
|
length -= 4;
|
|
787
819
|
|
|
788
|
-
if (rdata.family
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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('.');
|
|
792
830
|
}
|
|
793
831
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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(':');
|
|
801
842
|
}
|
|
802
|
-
|
|
843
|
+
|
|
803
844
|
return rdata;
|
|
804
845
|
};
|
|
805
846
|
|
|
@@ -828,15 +869,135 @@ Packet.Resource.CAA = {
|
|
|
828
869
|
});
|
|
829
870
|
return writer.toBuffer();
|
|
830
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
|
+
},
|
|
831
987
|
};
|
|
832
988
|
|
|
833
989
|
Packet.Reader = BufferReader;
|
|
834
990
|
Packet.Writer = BufferWriter;
|
|
835
991
|
|
|
836
992
|
Packet.createResponseFromRequest = function(request) {
|
|
837
|
-
const response = new Packet(
|
|
838
|
-
response.header
|
|
839
|
-
|
|
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();
|
|
840
1001
|
return response;
|
|
841
1002
|
};
|
|
842
1003
|
|
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') {
|