dns2 2.1.0 → 2.3.0
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/proxy-protocol.js +153 -0
- package/lib/reader.js +4 -2
- package/lib/writer.js +0 -1
- package/package.json +26 -12
- package/packet.js +314 -65
- package/server/dns.js +19 -2
- package/server/doh.js +9 -8
- package/server/tcp.js +72 -1
- package/server/udp.js +28 -4
- 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/server/udp.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
const udp = require('dgram');
|
|
1
|
+
const udp = require('node:dgram');
|
|
2
2
|
const Packet = require('../packet');
|
|
3
|
+
const proxyProtocol = require('../lib/proxy-protocol');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* [Server description]
|
|
@@ -9,10 +10,13 @@ const Packet = require('../packet');
|
|
|
9
10
|
class Server extends udp.Socket {
|
|
10
11
|
constructor(options) {
|
|
11
12
|
let type = 'udp4';
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
let proxyProtocolEnabled = false;
|
|
14
|
+
if (typeof options === 'object' && options !== null) {
|
|
15
|
+
type = options.type ?? type;
|
|
16
|
+
proxyProtocolEnabled = options.proxyProtocol ?? false;
|
|
14
17
|
}
|
|
15
18
|
super(type);
|
|
19
|
+
this.proxyProtocol = proxyProtocolEnabled;
|
|
16
20
|
if (typeof options === 'function') {
|
|
17
21
|
this.on('request', options);
|
|
18
22
|
}
|
|
@@ -21,8 +25,28 @@ class Server extends udp.Socket {
|
|
|
21
25
|
|
|
22
26
|
handle(data, rinfo) {
|
|
23
27
|
try {
|
|
28
|
+
// Response is always sent back to the immediate sender (the proxy when
|
|
29
|
+
// proxyProtocol is enabled); the parsed client info is exposed to the
|
|
30
|
+
// request handler so it can log/authorize against the real peer.
|
|
31
|
+
const responder = rinfo;
|
|
32
|
+
let clientInfo = rinfo;
|
|
33
|
+
if (this.proxyProtocol) {
|
|
34
|
+
const parsed = proxyProtocol.parse(data);
|
|
35
|
+
if (!parsed) throw new Error('PROXY protocol: incomplete header');
|
|
36
|
+
if (parsed.header.command === 'PROXY') {
|
|
37
|
+
clientInfo = {
|
|
38
|
+
...rinfo,
|
|
39
|
+
address : parsed.header.sourceAddress,
|
|
40
|
+
port : parsed.header.sourcePort,
|
|
41
|
+
proxy : parsed.header,
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
clientInfo = { ...rinfo, proxy: parsed.header };
|
|
45
|
+
}
|
|
46
|
+
data = data.slice(parsed.headerLength);
|
|
47
|
+
}
|
|
24
48
|
const message = Packet.parse(data);
|
|
25
|
-
this.emit('request', message, this.response.bind(this,
|
|
49
|
+
this.emit('request', message, this.response.bind(this, responder), clientInfo);
|
|
26
50
|
} catch (e) {
|
|
27
51
|
this.emit('requestError', e);
|
|
28
52
|
}
|
package/ts/index.d.ts
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
import * as dgram from 'node:dgram';
|
|
4
|
+
import { EventEmitter } from 'node:events';
|
|
5
|
+
import * as http from 'node:http';
|
|
6
|
+
import * as net from 'node:net';
|
|
7
|
+
|
|
8
|
+
// ─── Main DNS class ───────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
declare class DNS extends EventEmitter {
|
|
11
|
+
constructor(options?: Partial<DNS.ClientOptions>);
|
|
12
|
+
|
|
13
|
+
resolve(
|
|
14
|
+
domain: string,
|
|
15
|
+
type?: string,
|
|
16
|
+
cls?: number,
|
|
17
|
+
options?: DNS.ResolveOptions,
|
|
18
|
+
): Promise<DNS.Packet>;
|
|
19
|
+
|
|
20
|
+
resolveA(domain: string, clientIp?: string): Promise<DNS.Packet>;
|
|
21
|
+
resolveAAAA(domain: string): Promise<DNS.Packet>;
|
|
22
|
+
resolveMX(domain: string): Promise<DNS.Packet>;
|
|
23
|
+
resolveCNAME(domain: string): Promise<DNS.Packet>;
|
|
24
|
+
resolvePTR(domain: string): Promise<DNS.Packet>;
|
|
25
|
+
resolveDNSKEY(domain: string): Promise<DNS.Packet>;
|
|
26
|
+
resolveRRSIG(domain: string): Promise<DNS.Packet>;
|
|
27
|
+
resolveSOA(domain: string): Promise<DNS.Packet>;
|
|
28
|
+
|
|
29
|
+
static createServer(options: DNS.CreateServerOptions): DNS.DnsServer;
|
|
30
|
+
static createUDPServer(options?: DNS.UdpServerOptions | DNS.DnsHandler): DNS.UDPServer;
|
|
31
|
+
static createTCPServer(options?: DNS.DnsHandler): DNS.TCPServer;
|
|
32
|
+
static createDOHServer(options?: DNS.DohServerOptions): DNS.DOHServer;
|
|
33
|
+
|
|
34
|
+
static UDPClient(options?: DNS.UdpClientOptions): DNS.DnsResolver;
|
|
35
|
+
static TCPClient(options?: DNS.TcpClientOptions): DNS.DnsResolver;
|
|
36
|
+
static DOHClient(options?: DNS.DohClientOptions): DNS.DnsResolver;
|
|
37
|
+
static GoogleClient(): DNS.DnsResolver;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ─── Namespace (all exported sub-types live here) ─────────────────────────────
|
|
41
|
+
|
|
42
|
+
declare namespace DNS {
|
|
43
|
+
|
|
44
|
+
// ── Packet ──────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
class Packet {
|
|
47
|
+
header: Packet.Header;
|
|
48
|
+
questions: Packet.Question[];
|
|
49
|
+
answers: Packet.Resource[];
|
|
50
|
+
authorities: Packet.Resource[];
|
|
51
|
+
additionals: Packet.Resource[];
|
|
52
|
+
recursive: boolean;
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
data?: Packet | Packet.Header | Packet.Question | Packet.Resource | string | any[],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
toBuffer(): Buffer;
|
|
59
|
+
toBase64URL(): string;
|
|
60
|
+
|
|
61
|
+
// ── Static constants ────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
static TYPE: {
|
|
64
|
+
A : 0x01;
|
|
65
|
+
NS : 0x02;
|
|
66
|
+
MD : 0x03;
|
|
67
|
+
MF : 0x04;
|
|
68
|
+
CNAME : 0x05;
|
|
69
|
+
SOA : 0x06;
|
|
70
|
+
MB : 0x07;
|
|
71
|
+
MG : 0x08;
|
|
72
|
+
MR : 0x09;
|
|
73
|
+
NULL : 0x0a;
|
|
74
|
+
WKS : 0x0b;
|
|
75
|
+
PTR : 0x0c;
|
|
76
|
+
HINFO : 0x0d;
|
|
77
|
+
MINFO : 0x0e;
|
|
78
|
+
MX : 0x0f;
|
|
79
|
+
TXT : 0x10;
|
|
80
|
+
AAAA : 0x1c;
|
|
81
|
+
SRV : 0x21;
|
|
82
|
+
EDNS : 0x29;
|
|
83
|
+
SPF : 0x63;
|
|
84
|
+
AXFR : 0xfc;
|
|
85
|
+
MAILB : 0xfd;
|
|
86
|
+
MAILA : 0xfe;
|
|
87
|
+
ANY : 0xff;
|
|
88
|
+
CAA : 0x101;
|
|
89
|
+
DNSKEY : 0x30;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
static CLASS: {
|
|
93
|
+
IN : 0x01;
|
|
94
|
+
CS : 0x02;
|
|
95
|
+
CH : 0x03;
|
|
96
|
+
HS : 0x04;
|
|
97
|
+
ANY : 0xff;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
static EDNS_OPTION_CODE: {
|
|
101
|
+
ECS: 0x08;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// ── Static helpers ──────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
static parse(buffer: Buffer): Packet;
|
|
107
|
+
static createResponseFromRequest(request: Packet): Packet;
|
|
108
|
+
static createResourceFromQuestion(
|
|
109
|
+
base: Packet.Question,
|
|
110
|
+
record: Partial<Packet.Resource>,
|
|
111
|
+
): Packet.Resource;
|
|
112
|
+
static readStream(socket: NodeJS.ReadableStream): Promise<Buffer>;
|
|
113
|
+
static toIPv6(parts: number[]): string;
|
|
114
|
+
static fromIPv6(address: string): string[];
|
|
115
|
+
static uuid(): number;
|
|
116
|
+
|
|
117
|
+
// ── Sub-constructors ────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
static Header: {
|
|
120
|
+
new(header?: Partial<Packet.Header>): Packet.Header;
|
|
121
|
+
parse(reader: Buffer | Packet.Reader): Packet.Header;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
static Question: {
|
|
125
|
+
new(
|
|
126
|
+
name?: string | Partial<Packet.Question>,
|
|
127
|
+
type?: number,
|
|
128
|
+
cls?: number,
|
|
129
|
+
): Packet.Question;
|
|
130
|
+
parse(reader: Buffer | Packet.Reader): Packet.Question;
|
|
131
|
+
decode(reader: Buffer | Packet.Reader): Packet.Question;
|
|
132
|
+
encode(question: Packet.Question, writer?: Packet.Writer): Buffer;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
static Resource: {
|
|
136
|
+
new(
|
|
137
|
+
name?: string | Partial<Packet.Resource>,
|
|
138
|
+
type?: number,
|
|
139
|
+
cls?: number,
|
|
140
|
+
ttl?: number,
|
|
141
|
+
): Packet.Resource;
|
|
142
|
+
parse(reader: Buffer | Packet.Reader): Packet.Resource;
|
|
143
|
+
decode(reader: Buffer | Packet.Reader): Packet.Resource;
|
|
144
|
+
encode(resource: Packet.Resource, writer?: Packet.Writer): Buffer;
|
|
145
|
+
EDNS(rdata: object[]): Packet.Resource;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
static Name: {
|
|
149
|
+
COPY: 0xc0;
|
|
150
|
+
encode(domain: string, writer?: Packet.Writer): Buffer;
|
|
151
|
+
decode(reader: Buffer | Packet.Reader): string;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
static Reader: new(buffer: Buffer, offset?: number) => Packet.Reader;
|
|
155
|
+
static Writer: new() => Packet.Writer;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
namespace Packet {
|
|
159
|
+
interface Header {
|
|
160
|
+
id: number;
|
|
161
|
+
qr: 0 | 1;
|
|
162
|
+
opcode: number;
|
|
163
|
+
aa: 0 | 1;
|
|
164
|
+
tc: 0 | 1;
|
|
165
|
+
rd: 0 | 1;
|
|
166
|
+
ra: 0 | 1;
|
|
167
|
+
z: number;
|
|
168
|
+
rcode: number;
|
|
169
|
+
qdcount: number;
|
|
170
|
+
ancount: number;
|
|
171
|
+
nscount: number;
|
|
172
|
+
arcount: number;
|
|
173
|
+
toBuffer(writer?: Writer): Buffer;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
interface Question {
|
|
177
|
+
name: string;
|
|
178
|
+
type: number;
|
|
179
|
+
class: number;
|
|
180
|
+
toBuffer(writer?: Writer): Buffer;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Union of all possible DNS resource record shapes. */
|
|
184
|
+
interface Resource {
|
|
185
|
+
name: string;
|
|
186
|
+
type: number;
|
|
187
|
+
class: number;
|
|
188
|
+
ttl: number;
|
|
189
|
+
// A / AAAA
|
|
190
|
+
address?: string;
|
|
191
|
+
// MX
|
|
192
|
+
exchange?: string;
|
|
193
|
+
priority?: number;
|
|
194
|
+
// CNAME / PTR / NS
|
|
195
|
+
domain?: string;
|
|
196
|
+
ns?: string;
|
|
197
|
+
// TXT / SPF
|
|
198
|
+
data?: string | string[];
|
|
199
|
+
// SOA
|
|
200
|
+
primary?: string;
|
|
201
|
+
admin?: string;
|
|
202
|
+
serial?: number;
|
|
203
|
+
refresh?: number;
|
|
204
|
+
retry?: number;
|
|
205
|
+
expiration?: number;
|
|
206
|
+
minimum?: number;
|
|
207
|
+
// SRV
|
|
208
|
+
weight?: number;
|
|
209
|
+
port?: number;
|
|
210
|
+
target?: string;
|
|
211
|
+
// CAA
|
|
212
|
+
flags?: number;
|
|
213
|
+
tag?: string;
|
|
214
|
+
value?: string;
|
|
215
|
+
// DNSKEY
|
|
216
|
+
algorithm?: number;
|
|
217
|
+
keyTag?: number;
|
|
218
|
+
publicKey?: string;
|
|
219
|
+
toBuffer(writer?: Writer): Buffer;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
interface Reader {
|
|
223
|
+
offset: number;
|
|
224
|
+
read(bits: number): number;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
interface Writer {
|
|
228
|
+
buffer: number[];
|
|
229
|
+
write(value: number, bits: number): void;
|
|
230
|
+
writeBuffer(writer: Writer): void;
|
|
231
|
+
toBuffer(): Buffer;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ── Servers ─────────────────────────────────────────────────────────────────
|
|
236
|
+
|
|
237
|
+
class UDPServer extends dgram.Socket {
|
|
238
|
+
constructor(options?: UdpServerOptions | DnsHandler);
|
|
239
|
+
handle(data: Buffer, rinfo: dgram.RemoteInfo): void;
|
|
240
|
+
response(rinfo: dgram.RemoteInfo, message: Packet | Buffer): Promise<Buffer>;
|
|
241
|
+
listen(port?: number, address?: string): Promise<void>;
|
|
242
|
+
on(event: 'request', listener: DnsHandler): this;
|
|
243
|
+
on(event: 'requestError', listener: (error: Error) => void): this;
|
|
244
|
+
on(event: 'listening', listener: () => void): this;
|
|
245
|
+
on(event: 'close', listener: () => void): this;
|
|
246
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
class TCPServer extends net.Server {
|
|
250
|
+
constructor(options?: DnsHandler);
|
|
251
|
+
on(event: 'request', listener: DnsHandler): this;
|
|
252
|
+
on(event: 'requestError', listener: (error: Error) => void): this;
|
|
253
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
class DOHServer extends EventEmitter {
|
|
257
|
+
constructor(options?: DohServerOptions);
|
|
258
|
+
listen(port?: number, address?: string): void;
|
|
259
|
+
address(): net.AddressInfo | null;
|
|
260
|
+
close(): void;
|
|
261
|
+
on(event: 'request', listener: DnsHandler): this;
|
|
262
|
+
on(event: 'requestError', listener: (error: Error) => void): this;
|
|
263
|
+
on(event: 'listening', listener: (address: net.AddressInfo) => void): this;
|
|
264
|
+
on(event: 'close', listener: () => void): this;
|
|
265
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
class DnsServer extends EventEmitter {
|
|
269
|
+
constructor(options: CreateServerOptions);
|
|
270
|
+
addresses(): ServerAddresses;
|
|
271
|
+
listen(options?: DnsServerListenOptions): Promise<ServerAddresses>;
|
|
272
|
+
close(): Promise<void>;
|
|
273
|
+
on(event: 'request', listener: DnsHandler): this;
|
|
274
|
+
on(event: 'requestError', listener: (error: Error) => void): this;
|
|
275
|
+
on(event: 'listening', listener: (addresses: ServerAddresses) => void): this;
|
|
276
|
+
on(event: 'close', listener: () => void): this;
|
|
277
|
+
on(event: 'error', listener: (error: Error, transport: 'udp' | 'tcp' | 'doh') => void): this;
|
|
278
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ── Handler & resolver callable types ────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
type DnsHandler = (
|
|
284
|
+
request: Packet,
|
|
285
|
+
send: (response: Packet | Buffer) => Promise<Buffer>,
|
|
286
|
+
client: dgram.RemoteInfo | net.Socket | http.IncomingMessage,
|
|
287
|
+
) => void;
|
|
288
|
+
|
|
289
|
+
type DnsResolver = (
|
|
290
|
+
name: string,
|
|
291
|
+
type?: string,
|
|
292
|
+
cls?: number,
|
|
293
|
+
options?: ResolveOptions,
|
|
294
|
+
) => Promise<Packet>;
|
|
295
|
+
|
|
296
|
+
// ── Options ──────────────────────────────────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
interface ClientOptions {
|
|
299
|
+
port: number;
|
|
300
|
+
retries: number;
|
|
301
|
+
timeout: number;
|
|
302
|
+
recursive: boolean;
|
|
303
|
+
/** When using UDP and the TC (truncated) bit is set, automatically retry over TCP. Default: `true`. */
|
|
304
|
+
retryOverTCP: boolean;
|
|
305
|
+
resolverProtocol: 'UDP' | 'TCP' | 'DOH' | 'Google';
|
|
306
|
+
/** Shorthand alias for `nameServers`. A single IP string or an array. */
|
|
307
|
+
dns?: string | string[];
|
|
308
|
+
nameServers: string[];
|
|
309
|
+
rootServers: string[];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
interface ResolveOptions {
|
|
313
|
+
recursive?: boolean;
|
|
314
|
+
/** EDNS ECS client subnet in CIDR notation, e.g. `"1.2.3.4/24"` */
|
|
315
|
+
clientIp?: string;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface UdpClientOptions {
|
|
319
|
+
dns?: string;
|
|
320
|
+
port?: number;
|
|
321
|
+
socketType?: dgram.SocketType;
|
|
322
|
+
timeout?: number;
|
|
323
|
+
/** When the TC (truncated) bit is set, automatically retry over TCP. Default: `true`. */
|
|
324
|
+
retryOverTCP?: boolean;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface TcpClientOptions {
|
|
328
|
+
dns: string;
|
|
329
|
+
protocol?: 'tcp:' | 'tls:';
|
|
330
|
+
port?: number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
interface DohClientOptions {
|
|
334
|
+
dns: string;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface UdpServerOptions {
|
|
338
|
+
type?: 'udp4' | 'udp6';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
interface DohServerOptions {
|
|
342
|
+
port?: number;
|
|
343
|
+
ssl?: boolean;
|
|
344
|
+
cors?: boolean | string | ((origin: string) => boolean);
|
|
345
|
+
[key: string]: any;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
type ListenOptions = number | { port?: number; address?: string };
|
|
349
|
+
|
|
350
|
+
interface DnsServerListenOptions {
|
|
351
|
+
udp?: ListenOptions;
|
|
352
|
+
tcp?: ListenOptions;
|
|
353
|
+
doh?: ListenOptions;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
interface CreateServerOptions {
|
|
357
|
+
udp?: boolean | UdpServerOptions;
|
|
358
|
+
tcp?: boolean;
|
|
359
|
+
doh?: boolean | DohServerOptions;
|
|
360
|
+
handle?: DnsHandler;
|
|
361
|
+
maxConcurrent?: number;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
interface ServerAddresses {
|
|
365
|
+
udp?: net.AddressInfo;
|
|
366
|
+
tcp?: net.AddressInfo;
|
|
367
|
+
doh?: net.AddressInfo;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export = DNS;
|
package/ts/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"ignoreDeprecations": "6.0",
|
|
10
|
+
"typeRoots": ["../node_modules/@types"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["typings-check.ts"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-check smoke test for index.d.ts.
|
|
3
|
+
*
|
|
4
|
+
* This file is NOT executed at runtime. It exists solely so that `tsc` can
|
|
5
|
+
* verify that index.d.ts accurately describes the package's public API.
|
|
6
|
+
* CI runs `tsc --project tsconfig.json` and fails if there are type errors.
|
|
7
|
+
*
|
|
8
|
+
* Add a line here whenever a new public API surface is added to index.js.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import DNS = require('./index');
|
|
12
|
+
import type { AddressInfo } from 'node:net';
|
|
13
|
+
|
|
14
|
+
const { Packet } = DNS;
|
|
15
|
+
|
|
16
|
+
// ── DNS instance (high-level resolver) ────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const dns = new DNS({ nameServers: ['8.8.8.8'], port: 53, recursive: true });
|
|
19
|
+
|
|
20
|
+
void dns.resolve('example.com', 'A');
|
|
21
|
+
void dns.resolveA('example.com');
|
|
22
|
+
void dns.resolveA('example.com', '1.2.3.4');
|
|
23
|
+
void dns.resolveAAAA('example.com');
|
|
24
|
+
void dns.resolveMX('example.com');
|
|
25
|
+
void dns.resolveCNAME('www.example.com');
|
|
26
|
+
void dns.resolvePTR('1.0.0.127.in-addr.arpa');
|
|
27
|
+
void dns.resolveDNSKEY('example.com');
|
|
28
|
+
void dns.resolveRRSIG('example.com');
|
|
29
|
+
void dns.resolveSOA('example.com');
|
|
30
|
+
|
|
31
|
+
dns.resolve('example.com').then((packet: DNS.Packet) => {
|
|
32
|
+
const hdr: DNS.Packet.Header = packet.header;
|
|
33
|
+
const _id: number = hdr.id;
|
|
34
|
+
const _rc: number = hdr.rcode;
|
|
35
|
+
const answer: DNS.Packet.Resource = packet.answers[0];
|
|
36
|
+
const _addr: string | undefined = answer.address;
|
|
37
|
+
const _ttl: number = answer.ttl;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ── Packet static constants ───────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
const _typeA: number = Packet.TYPE.A;
|
|
43
|
+
const _typeAAAA: number = Packet.TYPE.AAAA;
|
|
44
|
+
const _typeMX: number = Packet.TYPE.MX;
|
|
45
|
+
const _typeDNSKEY: number = Packet.TYPE.DNSKEY;
|
|
46
|
+
const _classIN: number = Packet.CLASS.IN;
|
|
47
|
+
const _ecsCode: number = Packet.EDNS_OPTION_CODE.ECS;
|
|
48
|
+
|
|
49
|
+
// ── Packet static helpers ─────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
const buf = Buffer.alloc(12);
|
|
52
|
+
const parsed: DNS.Packet = Packet.parse(buf);
|
|
53
|
+
const response: DNS.Packet = Packet.createResponseFromRequest(parsed);
|
|
54
|
+
response.header.rcode = 3; // NXDOMAIN
|
|
55
|
+
|
|
56
|
+
const q: DNS.Packet.Question = parsed.questions[0];
|
|
57
|
+
if (q) {
|
|
58
|
+
Packet.createResourceFromQuestion(q, { address: '1.2.3.4', ttl: 60 });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Packet encode / round-trip ────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
const pkt = new Packet();
|
|
64
|
+
pkt.header.qr = 1;
|
|
65
|
+
const encoded: Buffer = pkt.toBuffer();
|
|
66
|
+
Packet.parse(encoded);
|
|
67
|
+
|
|
68
|
+
// ── Multi-server (DnsServer) ──────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
const server: DNS.DnsServer = DNS.createServer({
|
|
71
|
+
udp: true,
|
|
72
|
+
tcp: true,
|
|
73
|
+
maxConcurrent: 100,
|
|
74
|
+
handle: (request, send, _client) => {
|
|
75
|
+
const res = Packet.createResponseFromRequest(request);
|
|
76
|
+
res.header.rcode = 5; // REFUSED
|
|
77
|
+
void send(res);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
server.listen({ udp: { port: 53 }, tcp: 5353 }).then((addrs: DNS.ServerAddresses) => {
|
|
82
|
+
const _udp: AddressInfo | undefined = addrs.udp;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
server.on('request', (req, send, _client) => {
|
|
86
|
+
void send(Packet.createResponseFromRequest(req));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
server.on('error', (err: Error, transport: 'udp' | 'tcp' | 'doh') => {
|
|
90
|
+
void err;
|
|
91
|
+
void transport;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
void server.close();
|
|
95
|
+
|
|
96
|
+
// ── Individual server factories ───────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
const udpServer: DNS.UDPServer = DNS.createUDPServer({ type: 'udp4' });
|
|
99
|
+
udpServer.on('request', (req, send) => { void send(req); });
|
|
100
|
+
|
|
101
|
+
const tcpServer: DNS.TCPServer = DNS.createTCPServer();
|
|
102
|
+
tcpServer.on('request', (req, send) => { void send(req); });
|
|
103
|
+
|
|
104
|
+
const dohServer: DNS.DOHServer = DNS.createDOHServer({ ssl: false, cors: true });
|
|
105
|
+
dohServer.on('request', (req, send) => { void send(req); });
|
|
106
|
+
|
|
107
|
+
// ── Client factories ──────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
const udpClient: DNS.DnsResolver = DNS.UDPClient({ dns: '8.8.8.8', port: 53 });
|
|
110
|
+
const tcpClient: DNS.DnsResolver = DNS.TCPClient({ dns: '8.8.8.8', protocol: 'tcp:' });
|
|
111
|
+
const dohClient: DNS.DnsResolver = DNS.DOHClient({ dns: 'https://cloudflare-dns.com/dns-query' });
|
|
112
|
+
const googleClient: DNS.DnsResolver = DNS.GoogleClient();
|
|
113
|
+
|
|
114
|
+
void udpClient('example.com', 'A');
|
|
115
|
+
void tcpClient('example.com', 'MX');
|
|
116
|
+
void dohClient('example.com', 'AAAA');
|
|
117
|
+
void googleClient('example.com');
|
|
118
|
+
|
|
119
|
+
// ── Sub-class type assignability ──────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
const _dnsServer: DNS.DnsServer = DNS.createServer({ udp: true });
|
|
122
|
+
const _udp: DNS.UDPServer = DNS.createUDPServer();
|
|
123
|
+
const _tcp: DNS.TCPServer = DNS.createTCPServer();
|
|
124
|
+
const _doh: DNS.DOHServer = DNS.createDOHServer();
|
package/.eslintrc
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "semistandard",
|
|
3
|
-
"rules": {
|
|
4
|
-
"space-before-function-paren": ["error", "never"],
|
|
5
|
-
"no-multi-spaces": ["error"],
|
|
6
|
-
"array-bracket-spacing": ["error", "always"],
|
|
7
|
-
"key-spacing": ["error", {
|
|
8
|
-
"align": {
|
|
9
|
-
"beforeColon": true,
|
|
10
|
-
"afterColon": true,
|
|
11
|
-
"on": "colon"
|
|
12
|
-
}
|
|
13
|
-
}],
|
|
14
|
-
"comma-dangle": ["error", "always-multiline"]
|
|
15
|
-
}
|
|
16
|
-
}
|
package/.github/FUNDING.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# These are supported funding model platforms
|
|
2
|
-
|
|
3
|
-
github: song940
|
|
4
|
-
patreon: song940
|
|
5
|
-
open_collective: song940
|
|
6
|
-
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
-
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
8
|
-
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
-
liberapay: # Replace with a single Liberapay username
|
|
10
|
-
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
-
otechie: # Replace with a single Otechie username
|
|
12
|
-
custom: https://git.io/fjRcB
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
3
|
-
|
|
4
|
-
name: Linting
|
|
5
|
-
|
|
6
|
-
on: [push, pull_request]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v2
|
|
13
|
-
- uses: actions/setup-node@v1
|
|
14
|
-
with:
|
|
15
|
-
node-version: 16
|
|
16
|
-
- run: npm i
|
|
17
|
-
- run: npm run lint
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
3
|
-
|
|
4
|
-
name: Node.js CI
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
push:
|
|
8
|
-
branches: [ master ]
|
|
9
|
-
pull_request:
|
|
10
|
-
branches: [ master ]
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
build:
|
|
14
|
-
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
|
|
17
|
-
strategy:
|
|
18
|
-
matrix:
|
|
19
|
-
node-version: [10.x, 12.x, 14.x, 16.x]
|
|
20
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
21
|
-
|
|
22
|
-
steps:
|
|
23
|
-
- uses: actions/checkout@v2
|
|
24
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
25
|
-
uses: actions/setup-node@v1
|
|
26
|
-
with:
|
|
27
|
-
node-version: ${{ matrix.node-version }}
|
|
28
|
-
- run: npm ci
|
|
29
|
-
- run: npm test
|
package/SECURITY.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Security Policy
|
|
2
|
-
|
|
3
|
-
## Supported Versions
|
|
4
|
-
|
|
5
|
-
Use this section to tell people about which versions of your project are
|
|
6
|
-
currently being supported with security updates.
|
|
7
|
-
|
|
8
|
-
| Version | Supported |
|
|
9
|
-
| ------- | ------------------ |
|
|
10
|
-
| 5.1.x | :white_check_mark: |
|
|
11
|
-
| 5.0.x | :x: |
|
|
12
|
-
| 4.0.x | :white_check_mark: |
|
|
13
|
-
| < 4.0 | :x: |
|
|
14
|
-
|
|
15
|
-
## Reporting a Vulnerability
|
|
16
|
-
|
|
17
|
-
Use this section to tell people how to report a vulnerability.
|
|
18
|
-
|
|
19
|
-
Tell them where to go, how often they can expect to get an update on a
|
|
20
|
-
reported vulnerability, what to expect if the vulnerability is accepted or
|
|
21
|
-
declined, etc.
|