dns2 2.0.0 → 2.0.3

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/packet.js CHANGED
@@ -1,857 +1,873 @@
1
- const { debuglog } = require('util');
2
- const BufferReader = require('./lib/reader');
3
- const BufferWriter = require('./lib/writer');
4
-
5
- const debug = debuglog('dns2');
6
-
7
- /**
8
- * [Packet description]
9
- * @param {[type]} data [description]
10
- * @docs https://tools.ietf.org/html/rfc1034
11
- * @docs https://tools.ietf.org/html/rfc1035
12
- *
13
- * <Buffer 29 64 01 00 00 01 00 00 00 00 00 00
14
- * |-ID----------- HEADER ----------->|
15
- *
16
- * 03 77 77 77 01 7a 02 63 6e 00 00 01 00 01>
17
- * <-W--W--W-----Z-----C--N>|<----------->|
18
- */
19
- function Packet(data) {
20
- this.header = {};
21
- this.questions = [];
22
- this.answers = [];
23
- this.authorities = [];
24
- this.additionals = [];
25
- if(data instanceof Packet) {
26
- return data;
27
- } else if(data instanceof Packet.Header) {
28
- this.header = data;
29
- } else if(data instanceof Packet.Question) {
30
- this.questions.push(data);
31
- } else if(data instanceof Packet.Resource) {
32
- this.answers.push(data);
33
- } else if(typeof data === 'string') {
34
- this.questions.push(data);
35
- } else if(typeof data === 'object') {
36
- var type = ({}).toString.call(data).match(/\[object (\w+)\]/)[1];
37
- if(type === 'Array') {
38
- this.questions = data;
39
- }
40
- if(type === 'Object') {
41
- this.header = data;
42
- }
43
- }
44
- return this;
45
- };
46
-
47
- /**
48
- * [QUERY_TYPE description]
49
- * @type {Object}
50
- * @docs https://tools.ietf.org/html/rfc1035#section-3.2.2
51
- */
52
- Packet.TYPE = {
53
- A : 0x01,
54
- NS : 0x02,
55
- MD : 0x03,
56
- MF : 0x04,
57
- CNAME : 0x05,
58
- SOA : 0x06,
59
- MB : 0x07,
60
- MG : 0x08,
61
- MR : 0x09,
62
- NULL : 0x0A,
63
- WKS : 0x0B,
64
- PTR : 0x0C,
65
- HINFO : 0x0D,
66
- MINFO : 0x0E,
67
- MX : 0x0F,
68
- TXT : 0x10,
69
- AAAA : 0x1C,
70
- SRV : 0x21,
71
- EDNS : 0x29,
72
- SPF : 0x63,
73
- AXFR : 0xFC,
74
- MAILB : 0xFD,
75
- MAILA : 0xFE,
76
- ANY : 0xFF,
77
- CAA : 0x101,
78
- };
79
- /**
80
- * [QUERY_CLASS description]
81
- * @type {Object}
82
- * @docs https://tools.ietf.org/html/rfc1035#section-3.2.4
83
- */
84
- Packet.CLASS = {
85
- IN : 0x01,
86
- CS : 0x02,
87
- CH : 0x03,
88
- HS : 0x04,
89
- ANY: 0xFF
90
- };
91
- /**
92
- * [EDNS_OPTION_CODE description]
93
- * @type {Object}
94
- * @docs https://tools.ietf.org/html/rfc6891#section-6.1.2
95
- */
96
- Packet.EDNS_OPTION_CODE = {
97
- ECS: 0x08
98
- };
99
-
100
- /**
101
- * [uuid description]
102
- * @return {[type]} [description]
103
- */
104
- Packet.uuid = function() {
105
- return Math.floor(Math.random() * 1e5);
106
- };
107
-
108
- /**
109
- * [parse description]
110
- * @param {[type]} buffer [description]
111
- * @return {[type]} [description]
112
- */
113
- Packet.parse = function(buffer) {
114
- const packet = new Packet();
115
- const reader = new Packet.Reader(buffer);
116
- packet.header = Packet.Header.parse(reader);
117
- ([ // props parser count
118
- [ 'questions' , Packet.Question, packet.header.qdcount ],
119
- [ 'answers' , Packet.Resource, packet.header.ancount ],
120
- [ 'authorities' , Packet.Resource, packet.header.nscount ],
121
- [ 'additionals' , Packet.Resource, packet.header.arcount ]
122
- ]).forEach(function(def) {
123
- var section = def[0];
124
- var decoder = def[1];
125
- var count = def[2];
126
- while(count--) {
127
- try {
128
- packet[ section ] = packet[ section ] || [];
129
- packet[ section ].push( decoder.parse(reader) );
130
- } catch(e) {
131
- debug('node-dns > parse %s error:', section, e.message);
132
- }
133
- }
134
- });
135
- return packet;
136
- };
137
-
138
- /**
139
- * [toBuffer description]
140
- * @return {[type]} [description]
141
- */
142
- Packet.prototype.toBuffer = function(writer) {
143
- writer = writer || new Packet.Writer();
144
- this.header.qdcount = this.questions .length;
145
- this.header.ancount = this.answers .length;
146
- this.header.nscount = this.authorities.length;
147
- this.header.arcount = this.additionals.length;
148
- if(!(this instanceof Packet.Header))
149
- this.header = new Packet.Header(this.header);
150
- this.header.toBuffer(writer);
151
- ;([ // section encoder
152
- [ 'questions' , Packet.Question ],
153
- [ 'answers' , Packet.Resource ],
154
- [ 'authorities', Packet.Resource ],
155
- [ 'additionals', Packet.Resource ],
156
- ]).forEach(function(def) {
157
- const section = def[0];
158
- const Encoder = def[1];
159
- (this[ section ] || []).map(function(resource) {
160
- return Encoder.encode(resource, writer);
161
- });
162
- }.bind(this));
163
- return writer.toBuffer();
164
- };
165
-
166
- /**
167
- * [Header description]
168
- * @param {[type]} options [description]
169
- * @docs https://tools.ietf.org/html/rfc1035#section-4.1.1
170
- */
171
- Packet.Header = function(header) {
172
- this.id = 0;
173
- this.qr = 0;
174
- this.opcode = 0;
175
- this.aa = 0;
176
- this.tc = 0;
177
- this.rd = 0;
178
- this.ra = 0;
179
- this.z = 0;
180
- this.rcode = 0;
181
- this.qdcount = 0;
182
- this.nscount = 0;
183
- this.arcount = 0;
184
- for(var k in header) {
185
- this[ k ] = header[ k ];
186
- }
187
- return this;
188
- };
189
- /**
190
- * [parse description]
191
- * @param {[type]} buffer [description]
192
- * @return {[type]} [description]
193
- * @docs https://tools.ietf.org/html/rfc1035#section-4.1.1
194
- */
195
- Packet.Header.parse = function(reader) {
196
- var header = new Packet.Header();
197
- if(reader instanceof Buffer) {
198
- reader = new Packet.Reader(reader);
199
- }
200
- header.id = reader.read(16);
201
- header.qr = reader.read(1);
202
- header.opcode = reader.read(4);
203
- header.aa = reader.read(1);
204
- header.tc = reader.read(1);
205
- header.rd = reader.read(1);
206
- header.ra = reader.read(1);
207
- header.z = reader.read(3);
208
- header.rcode = reader.read(4);
209
- header.qdcount = reader.read(16);
210
- header.ancount = reader.read(16);
211
- header.nscount = reader.read(16);
212
- header.arcount = reader.read(16);
213
- return header;
214
- };
215
-
216
- /**
217
- * [toBuffer description]
218
- * @return {[type]} [description]
219
- */
220
- Packet.Header.prototype.toBuffer = function(writer) {
221
- writer = writer || new Packet.Writer();
222
- writer.write(this.id , 16)
223
- writer.write(this.qr , 1)
224
- writer.write(this.opcode , 4)
225
- writer.write(this.aa , 1)
226
- writer.write(this.tc , 1)
227
- writer.write(this.rd , 1)
228
- writer.write(this.ra , 1)
229
- writer.write(this.z , 3)
230
- writer.write(this.rcode , 4)
231
- writer.write(this.qdcount, 16)
232
- writer.write(this.ancount, 16)
233
- writer.write(this.nscount, 16)
234
- writer.write(this.arcount, 16)
235
- return writer.toBuffer();
236
- };
237
-
238
- /**
239
- * Question section format
240
- * @docs https://tools.ietf.org/html/rfc1035#section-4.1.2
241
- */
242
- Packet.Question = function(name, type, cls) {
243
- var defaults = {
244
- type : Packet.TYPE .ANY,
245
- class: Packet.CLASS.ANY,
246
- };
247
- if(typeof name === 'object') {
248
- for(var k in name)
249
- this[ k ] = name[k] || defaults[k];
250
- } else {
251
- this.name = name;
252
- this.type = type || defaults.type;
253
- this.class = cls || defaults.class;
254
- }
255
- return this;
256
- };
257
-
258
- /**
259
- * [toBuffer description]
260
- * @param {[type]} writer [description]
261
- * @return {[type]} [description]
262
- */
263
- Packet.Question.prototype.toBuffer = function(writer) {
264
- return Packet.Question.encode(this, writer);
265
- };
266
-
267
- /**
268
- * [parse description]
269
- * @param {[type]} reader [description]
270
- * @return {[type]} [description]
271
- */
272
- Packet.Question.parse =
273
- Packet.Question.decode = function(reader) {
274
- var question = new Packet.Question();
275
- if(reader instanceof Buffer) {
276
- reader = new Packet.Reader(reader);
277
- }
278
- question.name = Packet.Name.decode(reader);
279
- question.type = reader.read(16);
280
- question.class= reader.read(16);
281
- return question;
282
- };
283
-
284
- Packet.Question.encode = function(question, writer) {
285
- writer = writer || new Packet.Writer();
286
- Packet.Name.encode(question.name, writer);
287
- writer.write(question.type, 16);
288
- writer.write(question.class, 16);
289
- return writer.toBuffer();
290
- };
291
-
292
- /**
293
- * Resource record format
294
- * @docs https://tools.ietf.org/html/rfc1035#section-4.1.3
295
- */
296
- Packet.Resource = function(name, type, cls, ttl) {
297
- var defaults = {
298
- name : '',
299
- ttl : 300,
300
- type : Packet.TYPE .ANY,
301
- class: Packet.CLASS.ANY,
302
- };
303
- var input;
304
- if(typeof name === 'object') {
305
- input = name;
306
- } else {
307
- input = {
308
- name, type, class: cls, ttl
309
- };
310
- }
311
- Object.assign(this, defaults, input);
312
- return this;
313
- };
314
-
315
- /**
316
- * [toBuffer description]
317
- * @param {[type]} writer [description]
318
- * @return {[type]} [description]
319
- */
320
- Packet.Resource.prototype.toBuffer = function(writer) {
321
- return Packet.Resource.encode(this, writer);
322
- };
323
-
324
- /**
325
- * [encode description]
326
- * @param {[type]} resource [description]
327
- * @param {[type]} writer [description]
328
- * @return {[type]} [description]
329
- */
330
- Packet.Resource.encode = function(resource, writer) {
331
- writer = writer || new Packet.Writer();
332
- Packet.Name.encode(resource.name, writer);
333
- writer.write(resource.type, 16);
334
- writer.write(resource.class, 16);
335
- writer.write(resource.ttl, 32);
336
- var encoder = Object.keys(Packet.TYPE).filter(function(type) {
337
- return resource.type == Packet.TYPE[ type ];
338
- })[0];
339
- if(encoder in Packet.Resource && Packet.Resource[ encoder ].encode) {
340
- return Packet.Resource[ encoder ].encode(resource, writer);
341
- } else {
342
- debug('node-dns > unknown encoder %s(%j)', encoder, resource.type);
343
- }
344
- };
345
- /**
346
- * [parse description]
347
- * @param {[type]} reader [description]
348
- * @return {[type]} [description]
349
- */
350
- Packet.Resource.parse =
351
- Packet.Resource.decode = function(reader) {
352
- if(reader instanceof Buffer) {
353
- reader = new Packet.Reader(reader);
354
- }
355
- var resource = new Packet.Resource();
356
- resource.name = Packet.Name.decode(reader);
357
- resource.type = reader.read(16);
358
- resource.class = reader.read(16);
359
- resource.ttl = reader.read(32);
360
- const length = reader.read(16);
361
- const parser = Object.keys(Packet.TYPE).filter(function(type) {
362
- return resource.type === Packet.TYPE[ type ];
363
- })[0];
364
- if(parser in Packet.Resource) {
365
- resource = Packet.Resource[ parser ].decode.call(resource, reader, length);
366
- } else {
367
- debug('node-dns > unknown parser type: %s(%j)', parser, resource.type);
368
- const arr = [];
369
- while(length--) arr.push(reader.read(8));
370
- resource.data = Buffer.from(arr);
371
- }
372
- return resource;
373
- };
374
-
375
- /**
376
- * [encode_name description]
377
- * @param {[type]} domain [description]
378
- * @return {[type]} [description]
379
- */
380
- Packet.Name = {
381
- COPY: 0xc0,
382
- decode: function(reader) {
383
- if(reader instanceof Buffer) {
384
- reader = new Packet.Reader(reader);
385
- }
386
- var name = [], o, len = reader.read(8);
387
- while(len) {
388
- if((len & Packet.Name.COPY) === Packet.Name.COPY) {
389
- len -= Packet.Name.COPY;
390
- len = len << 8;
391
- var pos = len + reader.read(8);
392
- if(!o) o = reader.offset;
393
- reader.offset = pos * 8;
394
- len = reader.read(8);
395
- continue;
396
- } else {
397
- var part = '';
398
- while(len--) part += String.fromCharCode(reader.read(8));
399
- name.push(part);
400
- len = reader.read(8);
401
- }
402
- }
403
- if(o) reader.offset = o;
404
- return name.join('.');
405
- },
406
- encode: function(domain, writer) {
407
- writer = writer || new Packet.Writer();
408
- // TODO: domain name compress
409
- (domain || '').split('.').filter(function(part) {
410
- return !!part;
411
- }).map(function(part) {
412
- writer.write(part.length, 8);
413
- part.split('').map(function(c) {
414
- writer.write(c.charCodeAt(0), 8);
415
- return c.charCodeAt(0)
416
- });
417
- });
418
- writer.write(0, 8);
419
- return writer.toBuffer();
420
- }
421
- };
422
-
423
- /**
424
- * [A description]
425
- * @type {Object}
426
- * @docs https://tools.ietf.org/html/rfc1035#section-3.4.1
427
- */
428
- Packet.Resource.A = function(address) {
429
- this.type = Packet.TYPE.A;
430
- this.class = Packet.CLASS.IN;
431
- this.address = address;
432
- return this;
433
- };
434
-
435
- Packet.Resource.A.encode = function(record, writer) {
436
- writer = writer || new Packet.Writer();
437
- var parts = record.address.split('.');
438
- writer.write(parts.length, 16);
439
- parts.forEach(function(part) {
440
- writer.write(parseInt(part, 10), 8);
441
- });
442
- return writer.toBuffer();
443
- };
444
-
445
- Packet.Resource.A.decode = function(reader, length) {
446
- var parts = [];
447
- while(length--) parts.push(reader.read(8));
448
- this.address = parts.join('.');
449
- return this;
450
- };
451
-
452
- /**
453
- * [MX description]
454
- * @param {[type]} exchange [description]
455
- * @param {[type]} priority [description]
456
- * @docs https://tools.ietf.org/html/rfc1035#section-3.3.9
457
- */
458
- Packet.Resource.MX = function(exchange, priority) {
459
- this.type = Packet.TYPE.MX;
460
- this.class = Packet.CLASS.IN;
461
- this.exchange = exchange;
462
- this.priority = priority;
463
- return this;
464
- }
465
- /**
466
- * [encode description]
467
- * @param {[type]} record [description]
468
- * @param {[type]} writer [description]
469
- * @return {[type]} [description]
470
- */
471
- Packet.Resource.MX.encode = function(record, writer) {
472
- writer = writer || new Packet.Writer();
473
- var len = Packet.Name.encode(record.exchange).length;
474
- writer.write(len + 2, 16);
475
- writer.write(record.priority, 16);
476
- Packet.Name.encode(record.exchange, writer);
477
- return writer.toBuffer();
478
- }
479
- /**
480
- * [decode description]
481
- * @param {[type]} reader [description]
482
- * @param {[type]} length [description]
483
- * @return {[type]} [description]
484
- */
485
- Packet.Resource.MX.decode = function(reader, length) {
486
- this.priority = reader.read(16);
487
- this.exchange = Packet.Name.decode(reader);
488
- return this;
489
- };
490
- /**
491
- * [AAAA description]
492
- * @type {Object}
493
- * @docs https://en.wikipedia.org/wiki/IPv6
494
- */
495
- Packet.Resource.AAAA = {
496
- decode: function(reader, length) {
497
- var parts = [];
498
- while(length) {
499
- length-=2;
500
- parts.push(reader.read(16));
501
- };
502
- this.address = parts.map(function(part) {
503
- return part > 0 ? part.toString(16) : '';
504
- }).join(':');
505
- return this;
506
- },
507
- encode: function(record, writer) {
508
- writer = writer || new Packet.Writer();
509
- var parts = record.address.split(':');
510
- writer.write(parts.length * 2, 16);
511
- parts.forEach(function(part) {
512
- writer.write(parseInt(part, 16), 16);
513
- });
514
- return writer.toBuffer();
515
- }
516
- };
517
- /**
518
- * [NS description]
519
- * @type {Object}
520
- * @docs https://tools.ietf.org/html/rfc1035#section-3.3.11
521
- */
522
- Packet.Resource.NS = {
523
- decode: function(reader, length) {
524
- this.ns = Packet.Name.decode(reader);
525
- return this;
526
- },
527
- encode: function(record, writer) {
528
- writer = writer || new Packet.Writer();
529
- writer.write(Packet.Name.encode(record.ns).length, 16);
530
- Packet.Name.encode(record.ns, writer);
531
- return writer.toBuffer();
532
- }
533
- };
534
- /**
535
- * [CNAME description]
536
- * @type {Object}
537
- * @docs https://tools.ietf.org/html/rfc1035#section-3.3.1
538
- */
539
- Packet.Resource.PTR =
540
- Packet.Resource.CNAME = {
541
- decode: function(reader, length) {
542
- this.domain = Packet.Name.decode(reader);
543
- return this;
544
- },
545
- encode: function(record, writer) {
546
- writer = writer || new Packet.Writer();
547
- writer.write(Packet.Name.encode(record.domain).length, 16);
548
- Packet.Name.encode(record.domain, writer);
549
- return writer.toBuffer();
550
- }
551
- };
552
- /**
553
- * [SPF description]
554
- * @type {[type]}
555
- * @docs https://tools.ietf.org/html/rfc1035#section-3.3.14
556
- */
557
- Packet.Resource.SPF =
558
- Packet.Resource.TXT = {
559
- decode: function(reader, length) {
560
- var parts = [];
561
- var bytesRead = 0, chunkLength = 0;
562
-
563
- while(bytesRead < length) {
564
- chunkLength = reader.read(8); // text length
565
- bytesRead++;
566
-
567
- while(chunkLength--) {
568
- parts.push(reader.read(8));
569
- bytesRead++;
570
- }
571
- }
572
-
573
- this.data = Buffer.from(parts).toString('utf8');
574
- return this;
575
- },
576
- encode: function(record, writer) {
577
- writer = writer || new Packet.Writer();
578
-
579
- // make sure that resource data is a an array of strings
580
- var characterStrings = Array.isArray(record.data) ? record.data : [record.data];
581
- // convert array of strings to array of buffers
582
- var characterStringBuffers = characterStrings.map(function(characterString) {
583
- if(Buffer.isBuffer(characterString)) {
584
- return characterString;
585
- }
586
- if(typeof characterString === 'string') {
587
- return Buffer.from(characterString, 'utf8');
588
- }
589
- return false;
590
- }).filter(function(characterString) {
591
- // remove invalid values from the array
592
- return characterString;
593
- });
594
-
595
- // calculate byte length of resource strings
596
- var bufferLength = characterStringBuffers.reduce(function(sum, characterStringBuffer) {
597
- return sum + characterStringBuffer.length;
598
- }, 0);
599
-
600
- // write string length to output
601
- writer.write(bufferLength + characterStringBuffers.length, 16); // response length
602
-
603
- // write each string to output
604
- characterStringBuffers.forEach(function(buffer) {
605
- writer.write(buffer.length, 8); // text length
606
- buffer.forEach(function(c) {
607
- writer.write(c, 8);
608
- });
609
- });
610
-
611
- return writer.toBuffer();
612
- }
613
- };
614
- /**
615
- * [SOA description]
616
- * @type {Object}
617
- * @docs https://tools.ietf.org/html/rfc1035#section-3.3.13
618
- */
619
- Packet.Resource.SOA = {
620
- decode: function(reader, length) {
621
- this.primary = Packet.Name.decode(reader);
622
- this.admin = Packet.Name.decode(reader);
623
- this.serial = reader.read(32);
624
- this.refresh = reader.read(32);
625
- this.retry = reader.read(32);
626
- this.expiration = reader.read(32);
627
- this.minimum = reader.read(32);
628
- return this;
629
- },
630
- encode: function(record, writer) {
631
- writer = writer || new Packet.Writer();
632
- var len = 0;
633
- len += Packet.Name.encode(record.primary).length;
634
- len += Packet.Name.encode(record.admin).length;
635
- len += (32 * 5) / 8;
636
- writer.write(len, 16);
637
- Packet.Name.encode(record.primary, writer);
638
- Packet.Name.encode(record.admin, writer);
639
- writer.write(record.serial , 32);
640
- writer.write(record.refresh , 32);
641
- writer.write(record.retry , 32);
642
- writer.write(record.expiration, 32);
643
- writer.write(record.minimum , 32);
644
- return writer.toBuffer();
645
- }
646
- };
647
- /**
648
- * [SRV description]
649
- * @type {Object}
650
- * @docs https://tools.ietf.org/html/rfc2782
651
- */
652
- Packet.Resource.SRV = {
653
- decode: function(reader, length) {
654
- this.priority = reader.read(16);
655
- this.weight = reader.read(16);
656
- this.port = reader.read(16);
657
- this.target = Packet.Name.decode(reader);
658
- return this;
659
- },
660
- encode: function(record, writer) {
661
- writer = writer || new Packet.Writer();
662
- const { length } = Packet.Name.encode(record.target);
663
- writer.write(length + 6 , 16);
664
- writer.write(record.priority, 16);
665
- writer.write(record.weight , 16);
666
- writer.write(record.port , 16);
667
- Packet.Name.encode(record.target, writer);
668
- return writer.toBuffer();
669
- }
670
- };
671
-
672
- Packet.Resource.EDNS = function(rdata) {
673
- return {
674
- type: Packet.TYPE['EDNS'],
675
- class: 512, // Supported UDP Payload size
676
- ttl: 0, // Extended RCODE and flags
677
- rdata // Objects of type Packet.Resource.EDNS.*
678
- };
679
- };
680
-
681
- Packet.Resource.EDNS.decode = function(reader, length) {
682
- this.type = Packet.TYPE['EDNS'];
683
- this.class = 512;
684
- this.ttl = 0;
685
- this.rdata = [];
686
-
687
- while (length) {
688
- const optionCode = reader.read(16);
689
- const optionLength = reader.read(16); // In octet (https://tools.ietf.org/html/rfc6891#page-8)
690
-
691
- const decoder = Object.keys(Packet.EDNS_OPTION_CODE).filter(function(type) {
692
- return optionCode == Packet.EDNS_OPTION_CODE[ type ];
693
- })[0];
694
- if (decoder in Packet.Resource.EDNS && Packet.Resource.EDNS[ decoder ].decode) {
695
- const rdata = Packet.Resource.EDNS[ decoder ].decode(reader, optionLength);
696
- this.rdata.push(rdata);
697
- } else {
698
- reader.read(optionLength); // Ignore data that doesn't understand
699
- debug('node-dns > unknown EDNS rdata decoder %s(%j)', decoder, optionCode);
700
- }
701
-
702
- length = length - 4 - optionLength;
703
- }
704
- return this;
705
- };
706
-
707
- Packet.Resource.EDNS.encode = function(record, writer) {
708
- const rdataWriter = new Packet.Writer();
709
- for(let rdata of record.rdata) {
710
- var encoder = Object.keys(Packet.EDNS_OPTION_CODE).filter(function(type) {
711
- return rdata.ednsCode == Packet.EDNS_OPTION_CODE[ type ];
712
- })[0];
713
- if(encoder in Packet.Resource.EDNS && Packet.Resource.EDNS[ encoder ].encode) {
714
- const w = new Packet.Writer();
715
- Packet.Resource.EDNS[ encoder ].encode(rdata, w);
716
- rdataWriter.write(rdata.ednsCode, 16);
717
- rdataWriter.write(w.buffer.length / 8, 16);
718
- rdataWriter.writeBuffer(w)
719
- } else {
720
- debug('node-dns > unknown EDNS rdata encoder %s(%j)', encoder, rdata.ednsCode);
721
- }
722
- }
723
- writer = writer || new Packet.Writer();
724
- writer.write(rdataWriter.buffer.length / 8, 16);
725
- writer.writeBuffer(rdataWriter);
726
- return writer.toBuffer();
727
- };
728
-
729
- Packet.Resource.EDNS.ECS = function(clientIp) {
730
- const [ip, prefixLength] = clientIp.split('/');
731
- const numPrefixLength = parseInt(prefixLength) || 32;
732
- return {
733
- ednsCode: Packet.EDNS_OPTION_CODE.ECS,
734
- family: 1,
735
- sourcePrefixLength: numPrefixLength,
736
- scopePrefixLength: 0,
737
- ip
738
- };
739
- }
740
-
741
- Packet.Resource.EDNS.ECS.decode = function(reader, length) {
742
- const rdata = {};
743
- rdata.ednsCode = Packet.EDNS_OPTION_CODE.ECS;
744
- rdata.family = reader.read(16);
745
- rdata.sourcePrefixLength = reader.read(8);
746
- rdata.scopePrefixLength = reader.read(8);
747
- length -= 4;
748
-
749
- if (rdata.family !== 1) {
750
- debug('node-dns > unimplemented address family');
751
- reader.read(length * 8); // Ignore data that doesn't understand
752
- return rdata;
753
- }
754
-
755
- const ipv4Octets = [];
756
- while (length--) {
757
- const octet = reader.read(8);
758
- ipv4Octets.push(octet);
759
- }
760
- while (ipv4Octets.length < 4) {
761
- ipv4Octets.push(0);
762
- }
763
- rdata.ip = ipv4Octets.join('.');
764
- return rdata;
765
- }
766
-
767
- Packet.Resource.EDNS.ECS.encode = function(record, writer) {
768
- const ip = record.ip.split('.').map( s => parseInt(s));
769
- writer.write(record.family, 16);
770
- writer.write(record.sourcePrefixLength, 8);
771
- writer.write(record.scopePrefixLength, 8);
772
- writer.write(ip[0], 8);
773
- writer.write(ip[1], 8);
774
- writer.write(ip[2], 8);
775
- writer.write(ip[3], 8);
776
- }
777
-
778
- Packet.Resource.CAA = {
779
- encode: function(record, writer) {
780
- writer = writer || new Packet.Writer();
781
-
782
- const buffer = new Buffer(record.tag + record.value, "utf8");
783
- writer.write(2 + buffer.length, 16);
784
- writer.write(record.flags, 8);
785
- writer.write(record.tag.length, 8);
786
-
787
- buffer.forEach(function(c) {
788
- writer.write(c, 8);
789
- });
790
- return writer.toBuffer();
791
- }
792
- };
793
-
794
- Packet.Reader = BufferReader;
795
- Packet.Writer = BufferWriter;
796
-
797
- Packet.createResponseFromRequest = function(request) {
798
- const response = new Packet(request);
799
- response.header.qr = 1;
800
- response.additionals = [];
801
- return response;
802
- };
803
-
804
- Packet.createResourceFromQuestion = function(base, record) {
805
- const resource = new Packet.Resource(base);
806
- Object.assign(resource, record);
807
- return resource;
808
- }
809
-
810
- Packet.readStream = socket => {
811
- let chunks = [];
812
- let chunklen = 0;
813
- let received = false;
814
- let expected = false;
815
- return new Promise((resolve, reject) => {
816
- const processMessage = () => {
817
- if (received) return;
818
- received = true;
819
- const buffer = Buffer.concat(chunks, chunklen);
820
- resolve(buffer.slice(2));
821
- };
822
- socket.on('end', processMessage);
823
- socket.on('error', reject);
824
- socket.on('readable', () => {
825
- let chunk;
826
- while ((chunk = socket.read()) !== null) {
827
- chunks.push(chunk);
828
- chunklen += chunk.length;
829
- }
830
- if (!expected && chunklen >= 2) {
831
- if (chunks.length > 1) {
832
- chunks = [Buffer.concat(chunks, chunklen)];
833
- }
834
- expected = chunks[0].readUInt16BE(0);
835
- }
836
-
837
- if (chunklen >= 2 + expected) {
838
- processMessage();
839
- }
840
- });
841
- });
842
- };
843
-
844
- /**
845
- * DoH
846
- * @docs https://tools.ietf.org/html/rfc8484
847
- */
848
- Packet.prototype.toBase64URL = function() {
849
- const buffer = this.toBuffer();
850
- const base64 = buffer.toString('base64');
851
- return base64
852
- .replace(/=/g, "")
853
- .replace(/\+/g, "-")
854
- .replace(/\//g, "_");
855
- };
856
-
857
- module.exports = Packet;
1
+ const { debuglog } = require('util');
2
+ const BufferReader = require('./lib/reader');
3
+ const BufferWriter = require('./lib/writer');
4
+
5
+ const debug = debuglog('dns2');
6
+
7
+ /**
8
+ * [Packet description]
9
+ * @param {[type]} data [description]
10
+ * @docs https://tools.ietf.org/html/rfc1034
11
+ * @docs https://tools.ietf.org/html/rfc1035
12
+ *
13
+ * <Buffer 29 64 01 00 00 01 00 00 00 00 00 00
14
+ * |-ID----------- HEADER ----------->|
15
+ *
16
+ * 03 77 77 77 01 7a 02 63 6e 00 00 01 00 01>
17
+ * <-W--W--W-----Z-----C--N>|<----------->|
18
+ */
19
+ function Packet(data) {
20
+ this.header = {};
21
+ this.questions = [];
22
+ this.answers = [];
23
+ this.authorities = [];
24
+ this.additionals = [];
25
+ if (data instanceof Packet) {
26
+ return data;
27
+ } else if (data instanceof Packet.Header) {
28
+ this.header = data;
29
+ } else if (data instanceof Packet.Question) {
30
+ this.questions.push(data);
31
+ } else if (data instanceof Packet.Resource) {
32
+ this.answers.push(data);
33
+ } else if (typeof data === 'string') {
34
+ this.questions.push(data);
35
+ } else if (typeof data === 'object') {
36
+ const type = ({}).toString.call(data).match(/\[object (\w+)\]/)[1];
37
+ if (type === 'Array') {
38
+ this.questions = data;
39
+ }
40
+ if (type === 'Object') {
41
+ this.header = data;
42
+ }
43
+ }
44
+ return this;
45
+ }
46
+
47
+ /**
48
+ * [QUERY_TYPE description]
49
+ * @type {Object}
50
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.2.2
51
+ */
52
+ Packet.TYPE = {
53
+ A : 0x01,
54
+ NS : 0x02,
55
+ MD : 0x03,
56
+ MF : 0x04,
57
+ CNAME : 0x05,
58
+ SOA : 0x06,
59
+ MB : 0x07,
60
+ MG : 0x08,
61
+ MR : 0x09,
62
+ NULL : 0x0A,
63
+ WKS : 0x0B,
64
+ PTR : 0x0C,
65
+ HINFO : 0x0D,
66
+ MINFO : 0x0E,
67
+ MX : 0x0F,
68
+ TXT : 0x10,
69
+ AAAA : 0x1C,
70
+ SRV : 0x21,
71
+ EDNS : 0x29,
72
+ SPF : 0x63,
73
+ AXFR : 0xFC,
74
+ MAILB : 0xFD,
75
+ MAILA : 0xFE,
76
+ ANY : 0xFF,
77
+ CAA : 0x101,
78
+ };
79
+ /**
80
+ * [QUERY_CLASS description]
81
+ * @type {Object}
82
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.2.4
83
+ */
84
+ Packet.CLASS = {
85
+ IN : 0x01,
86
+ CS : 0x02,
87
+ CH : 0x03,
88
+ HS : 0x04,
89
+ ANY : 0xFF,
90
+ };
91
+ /**
92
+ * [EDNS_OPTION_CODE description]
93
+ * @type {Object}
94
+ * @docs https://tools.ietf.org/html/rfc6891#section-6.1.2
95
+ */
96
+ Packet.EDNS_OPTION_CODE = {
97
+ ECS: 0x08,
98
+ };
99
+
100
+ /**
101
+ * [uuid description]
102
+ * @return {[type]} [description]
103
+ */
104
+ Packet.uuid = function() {
105
+ return Math.floor(Math.random() * 1e5);
106
+ };
107
+
108
+ /**
109
+ * [parse description]
110
+ * @param {[type]} buffer [description]
111
+ * @return {[type]} [description]
112
+ */
113
+ Packet.parse = function(buffer) {
114
+ const packet = new Packet();
115
+ const reader = new Packet.Reader(buffer);
116
+ packet.header = Packet.Header.parse(reader);
117
+ ([ // props parser count
118
+ [ 'questions', Packet.Question, packet.header.qdcount ],
119
+ [ 'answers', Packet.Resource, packet.header.ancount ],
120
+ [ 'authorities', Packet.Resource, packet.header.nscount ],
121
+ [ 'additionals', Packet.Resource, packet.header.arcount ],
122
+ ]).forEach(function(def) {
123
+ const section = def[0];
124
+ const decoder = def[1];
125
+ let count = def[2];
126
+ while (count--) {
127
+ try {
128
+ packet[section] = packet[section] || [];
129
+ packet[section].push(decoder.parse(reader));
130
+ } catch (e) {
131
+ debug('node-dns > parse %s error:', section, e.message);
132
+ }
133
+ }
134
+ });
135
+ return packet;
136
+ };
137
+
138
+ /**
139
+ * recursive
140
+ */
141
+ Object.defineProperty(Packet.prototype, 'recursive', {
142
+ enumerable : true,
143
+ configurable : true,
144
+ get() {
145
+ return !!this.header.rd;
146
+ },
147
+ set(yn) {
148
+ this.header.rd = +yn;
149
+ return this.header.rd;
150
+ },
151
+ });
152
+
153
+ /**
154
+ * [toBuffer description]
155
+ * @return {[type]} [description]
156
+ */
157
+ Packet.prototype.toBuffer = function(writer) {
158
+ writer = writer || new Packet.Writer();
159
+ this.header.qdcount = this.questions.length;
160
+ this.header.ancount = this.answers.length;
161
+ this.header.nscount = this.authorities.length;
162
+ this.header.arcount = this.additionals.length;
163
+ if (!(this instanceof Packet.Header)) { this.header = new Packet.Header(this.header); }
164
+ this.header.toBuffer(writer);
165
+ ([ // section encoder
166
+ [ 'questions', Packet.Question ],
167
+ [ 'answers', Packet.Resource ],
168
+ [ 'authorities', Packet.Resource ],
169
+ [ 'additionals', Packet.Resource ],
170
+ ]).forEach(function(def) {
171
+ const section = def[0];
172
+ const Encoder = def[1];
173
+ (this[section] || []).map(function(resource) {
174
+ return Encoder.encode(resource, writer);
175
+ });
176
+ }.bind(this));
177
+ return writer.toBuffer();
178
+ };
179
+
180
+ /**
181
+ * [Header description]
182
+ * @param {[type]} options [description]
183
+ * @docs https://tools.ietf.org/html/rfc1035#section-4.1.1
184
+ */
185
+ Packet.Header = function(header) {
186
+ this.id = 0;
187
+ this.qr = 0;
188
+ this.opcode = 0;
189
+ this.aa = 0;
190
+ this.tc = 0;
191
+ this.rd = 0;
192
+ this.ra = 0;
193
+ this.z = 0;
194
+ this.rcode = 0;
195
+ this.qdcount = 0;
196
+ this.nscount = 0;
197
+ this.arcount = 0;
198
+ for (const k in header) {
199
+ this[k] = header[k];
200
+ }
201
+ return this;
202
+ };
203
+ /**
204
+ * [parse description]
205
+ * @param {[type]} buffer [description]
206
+ * @return {[type]} [description]
207
+ * @docs https://tools.ietf.org/html/rfc1035#section-4.1.1
208
+ */
209
+ Packet.Header.parse = function(reader) {
210
+ const header = new Packet.Header();
211
+ if (reader instanceof Buffer) {
212
+ reader = new Packet.Reader(reader);
213
+ }
214
+ header.id = reader.read(16);
215
+ header.qr = reader.read(1);
216
+ header.opcode = reader.read(4);
217
+ header.aa = reader.read(1);
218
+ header.tc = reader.read(1);
219
+ header.rd = reader.read(1);
220
+ header.ra = reader.read(1);
221
+ header.z = reader.read(3);
222
+ header.rcode = reader.read(4);
223
+ header.qdcount = reader.read(16);
224
+ header.ancount = reader.read(16);
225
+ header.nscount = reader.read(16);
226
+ header.arcount = reader.read(16);
227
+ return header;
228
+ };
229
+
230
+ /**
231
+ * [toBuffer description]
232
+ * @return {[type]} [description]
233
+ */
234
+ Packet.Header.prototype.toBuffer = function(writer) {
235
+ writer = writer || new Packet.Writer();
236
+ writer.write(this.id, 16);
237
+ writer.write(this.qr, 1);
238
+ writer.write(this.opcode, 4);
239
+ writer.write(this.aa, 1);
240
+ writer.write(this.tc, 1);
241
+ writer.write(this.rd, 1);
242
+ writer.write(this.ra, 1);
243
+ writer.write(this.z, 3);
244
+ writer.write(this.rcode, 4);
245
+ writer.write(this.qdcount, 16);
246
+ writer.write(this.ancount, 16);
247
+ writer.write(this.nscount, 16);
248
+ writer.write(this.arcount, 16);
249
+ return writer.toBuffer();
250
+ };
251
+
252
+ /**
253
+ * Question section format
254
+ * @docs https://tools.ietf.org/html/rfc1035#section-4.1.2
255
+ */
256
+ Packet.Question = function(name, type, cls) {
257
+ const defaults = {
258
+ type : Packet.TYPE.ANY,
259
+ class : Packet.CLASS.ANY,
260
+ };
261
+ if (typeof name === 'object') {
262
+ for (const k in name) {
263
+ this[k] = name[k] || defaults[k];
264
+ }
265
+ } else {
266
+ this.name = name;
267
+ this.type = type || defaults.type;
268
+ this.class = cls || defaults.class;
269
+ }
270
+ return this;
271
+ };
272
+
273
+ /**
274
+ * [toBuffer description]
275
+ * @param {[type]} writer [description]
276
+ * @return {[type]} [description]
277
+ */
278
+ Packet.Question.prototype.toBuffer = function(writer) {
279
+ return Packet.Question.encode(this, writer);
280
+ };
281
+
282
+ /**
283
+ * [parse description]
284
+ * @param {[type]} reader [description]
285
+ * @return {[type]} [description]
286
+ */
287
+ Packet.Question.parse =
288
+ Packet.Question.decode = function(reader) {
289
+ const question = new Packet.Question();
290
+ if (reader instanceof Buffer) {
291
+ reader = new Packet.Reader(reader);
292
+ }
293
+ question.name = Packet.Name.decode(reader);
294
+ question.type = reader.read(16);
295
+ question.class = reader.read(16);
296
+ return question;
297
+ };
298
+
299
+ Packet.Question.encode = function(question, writer) {
300
+ writer = writer || new Packet.Writer();
301
+ Packet.Name.encode(question.name, writer);
302
+ writer.write(question.type, 16);
303
+ writer.write(question.class, 16);
304
+ return writer.toBuffer();
305
+ };
306
+
307
+ /**
308
+ * Resource record format
309
+ * @docs https://tools.ietf.org/html/rfc1035#section-4.1.3
310
+ */
311
+ Packet.Resource = function(name, type, cls, ttl) {
312
+ const defaults = {
313
+ name : '',
314
+ ttl : 300,
315
+ type : Packet.TYPE.ANY,
316
+ class : Packet.CLASS.ANY,
317
+ };
318
+ let input;
319
+ if (typeof name === 'object') {
320
+ input = name;
321
+ } else {
322
+ input = {
323
+ name, type, class: cls, ttl,
324
+ };
325
+ }
326
+ Object.assign(this, defaults, input);
327
+ return this;
328
+ };
329
+
330
+ /**
331
+ * [toBuffer description]
332
+ * @param {[type]} writer [description]
333
+ * @return {[type]} [description]
334
+ */
335
+ Packet.Resource.prototype.toBuffer = function(writer) {
336
+ return Packet.Resource.encode(this, writer);
337
+ };
338
+
339
+ /**
340
+ * [encode description]
341
+ * @param {[type]} resource [description]
342
+ * @param {[type]} writer [description]
343
+ * @return {[type]} [description]
344
+ */
345
+ Packet.Resource.encode = function(resource, writer) {
346
+ writer = writer || new Packet.Writer();
347
+ Packet.Name.encode(resource.name, writer);
348
+ writer.write(resource.type, 16);
349
+ writer.write(resource.class, 16);
350
+ writer.write(resource.ttl, 32);
351
+ const encoder = Object.keys(Packet.TYPE).filter(function(type) {
352
+ return resource.type === Packet.TYPE[type];
353
+ })[0];
354
+ if (encoder in Packet.Resource && Packet.Resource[encoder].encode) {
355
+ return Packet.Resource[encoder].encode(resource, writer);
356
+ } else {
357
+ debug('node-dns > unknown encoder %s(%j)', encoder, resource.type);
358
+ }
359
+ };
360
+ /**
361
+ * [parse description]
362
+ * @param {[type]} reader [description]
363
+ * @return {[type]} [description]
364
+ */
365
+ Packet.Resource.parse =
366
+ Packet.Resource.decode = function(reader) {
367
+ if (reader instanceof Buffer) {
368
+ reader = new Packet.Reader(reader);
369
+ }
370
+ let resource = new Packet.Resource();
371
+ resource.name = Packet.Name.decode(reader);
372
+ resource.type = reader.read(16);
373
+ resource.class = reader.read(16);
374
+ resource.ttl = reader.read(32);
375
+ let length = reader.read(16);
376
+ const parser = Object.keys(Packet.TYPE).filter(function(type) {
377
+ return resource.type === Packet.TYPE[type];
378
+ })[0];
379
+ if (parser in Packet.Resource) {
380
+ resource = Packet.Resource[parser].decode.call(resource, reader, length);
381
+ } else {
382
+ debug('node-dns > unknown parser type: %s(%j)', parser, resource.type);
383
+ const arr = [];
384
+ while (length--) arr.push(reader.read(8));
385
+ resource.data = Buffer.from(arr);
386
+ }
387
+ return resource;
388
+ };
389
+
390
+ /**
391
+ * [encode_name description]
392
+ * @param {[type]} domain [description]
393
+ * @return {[type]} [description]
394
+ */
395
+ Packet.Name = {
396
+ COPY : 0xc0,
397
+ decode : function(reader) {
398
+ if (reader instanceof Buffer) {
399
+ reader = new Packet.Reader(reader);
400
+ }
401
+ const name = []; let o; let len = reader.read(8);
402
+ while (len) {
403
+ if ((len & Packet.Name.COPY) === Packet.Name.COPY) {
404
+ len -= Packet.Name.COPY;
405
+ len = len << 8;
406
+ const pos = len + reader.read(8);
407
+ if (!o) o = reader.offset;
408
+ reader.offset = pos * 8;
409
+ len = reader.read(8);
410
+ continue;
411
+ } else {
412
+ let part = '';
413
+ while (len--) part += String.fromCharCode(reader.read(8));
414
+ name.push(part);
415
+ len = reader.read(8);
416
+ }
417
+ }
418
+ if (o) reader.offset = o;
419
+ return name.join('.');
420
+ },
421
+ encode: function(domain, writer) {
422
+ writer = writer || new Packet.Writer();
423
+ // TODO: domain name compress
424
+ (domain || '').split('.').filter(function(part) {
425
+ return !!part;
426
+ }).forEach(function(part) {
427
+ writer.write(part.length, 8);
428
+ part.split('').map(function(c) {
429
+ writer.write(c.charCodeAt(0), 8);
430
+ return c.charCodeAt(0);
431
+ });
432
+ });
433
+ writer.write(0, 8);
434
+ return writer.toBuffer();
435
+ },
436
+ };
437
+
438
+ /**
439
+ * [A description]
440
+ * @type {Object}
441
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.4.1
442
+ */
443
+ Packet.Resource.A = function(address) {
444
+ this.type = Packet.TYPE.A;
445
+ this.class = Packet.CLASS.IN;
446
+ this.address = address;
447
+ return this;
448
+ };
449
+
450
+ Packet.Resource.A.encode = function(record, writer) {
451
+ writer = writer || new Packet.Writer();
452
+ const parts = record.address.split('.');
453
+ writer.write(parts.length, 16);
454
+ parts.forEach(function(part) {
455
+ writer.write(parseInt(part, 10), 8);
456
+ });
457
+ return writer.toBuffer();
458
+ };
459
+
460
+ Packet.Resource.A.decode = function(reader, length) {
461
+ const parts = [];
462
+ while (length--) parts.push(reader.read(8));
463
+ this.address = parts.join('.');
464
+ return this;
465
+ };
466
+
467
+ /**
468
+ * [MX description]
469
+ * @param {[type]} exchange [description]
470
+ * @param {[type]} priority [description]
471
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.3.9
472
+ */
473
+ Packet.Resource.MX = function(exchange, priority) {
474
+ this.type = Packet.TYPE.MX;
475
+ this.class = Packet.CLASS.IN;
476
+ this.exchange = exchange;
477
+ this.priority = priority;
478
+ return this;
479
+ };
480
+ /**
481
+ * [encode description]
482
+ * @param {[type]} record [description]
483
+ * @param {[type]} writer [description]
484
+ * @return {[type]} [description]
485
+ */
486
+ Packet.Resource.MX.encode = function(record, writer) {
487
+ writer = writer || new Packet.Writer();
488
+ const len = Packet.Name.encode(record.exchange).length;
489
+ writer.write(len + 2, 16);
490
+ writer.write(record.priority, 16);
491
+ Packet.Name.encode(record.exchange, writer);
492
+ return writer.toBuffer();
493
+ };
494
+ /**
495
+ * [decode description]
496
+ * @param {[type]} reader [description]
497
+ * @param {[type]} length [description]
498
+ * @return {[type]} [description]
499
+ */
500
+ Packet.Resource.MX.decode = function(reader, length) {
501
+ this.priority = reader.read(16);
502
+ this.exchange = Packet.Name.decode(reader);
503
+ return this;
504
+ };
505
+ /**
506
+ * [AAAA description]
507
+ * @type {Object}
508
+ * @docs https://en.wikipedia.org/wiki/IPv6
509
+ */
510
+ Packet.Resource.AAAA = {
511
+ decode: function(reader, length) {
512
+ const parts = [];
513
+ while (length) {
514
+ length -= 2;
515
+ parts.push(reader.read(16));
516
+ }
517
+ this.address = parts
518
+ .map(part => part > 0 ? part.toString(16) : '')
519
+ .join(':')
520
+ .replace('::::', '::');
521
+ return this;
522
+ },
523
+ encode: function(record, writer) {
524
+ writer = writer || new Packet.Writer();
525
+ const parts = record.address.split(':');
526
+ writer.write(parts.length * 2, 16);
527
+ parts.forEach(function(part) {
528
+ writer.write(parseInt(part, 16), 16);
529
+ });
530
+ return writer.toBuffer();
531
+ },
532
+ };
533
+ /**
534
+ * [NS description]
535
+ * @type {Object}
536
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.3.11
537
+ */
538
+ Packet.Resource.NS = {
539
+ decode: function(reader, length) {
540
+ this.ns = Packet.Name.decode(reader);
541
+ return this;
542
+ },
543
+ encode: function(record, writer) {
544
+ writer = writer || new Packet.Writer();
545
+ writer.write(Packet.Name.encode(record.ns).length, 16);
546
+ Packet.Name.encode(record.ns, writer);
547
+ return writer.toBuffer();
548
+ },
549
+ };
550
+ /**
551
+ * [CNAME description]
552
+ * @type {Object}
553
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.3.1
554
+ */
555
+ Packet.Resource.PTR =
556
+ Packet.Resource.CNAME = {
557
+ decode: function(reader, length) {
558
+ this.domain = Packet.Name.decode(reader);
559
+ return this;
560
+ },
561
+ encode: function(record, writer) {
562
+ writer = writer || new Packet.Writer();
563
+ writer.write(Packet.Name.encode(record.domain).length, 16);
564
+ Packet.Name.encode(record.domain, writer);
565
+ return writer.toBuffer();
566
+ },
567
+ };
568
+ /**
569
+ * [SPF description]
570
+ * @type {[type]}
571
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.3.14
572
+ */
573
+ Packet.Resource.SPF =
574
+ Packet.Resource.TXT = {
575
+ decode: function(reader, length) {
576
+ const parts = [];
577
+ let bytesRead = 0; let chunkLength = 0;
578
+
579
+ while (bytesRead < length) {
580
+ chunkLength = reader.read(8); // text length
581
+ bytesRead++;
582
+
583
+ while (chunkLength--) {
584
+ parts.push(reader.read(8));
585
+ bytesRead++;
586
+ }
587
+ }
588
+
589
+ this.data = Buffer.from(parts).toString('utf8');
590
+ return this;
591
+ },
592
+ encode: function(record, writer) {
593
+ writer = writer || new Packet.Writer();
594
+
595
+ // make sure that resource data is a an array of strings
596
+ const characterStrings = Array.isArray(record.data) ? record.data : [ record.data ];
597
+ // convert array of strings to array of buffers
598
+ const characterStringBuffers = characterStrings.map(function(characterString) {
599
+ if (Buffer.isBuffer(characterString)) {
600
+ return characterString;
601
+ }
602
+ if (typeof characterString === 'string') {
603
+ return Buffer.from(characterString, 'utf8');
604
+ }
605
+ return false;
606
+ }).filter(function(characterString) {
607
+ // remove invalid values from the array
608
+ return characterString;
609
+ });
610
+
611
+ // calculate byte length of resource strings
612
+ const bufferLength = characterStringBuffers.reduce(function(sum, characterStringBuffer) {
613
+ return sum + characterStringBuffer.length;
614
+ }, 0);
615
+
616
+ // write string length to output
617
+ writer.write(bufferLength + characterStringBuffers.length, 16); // response length
618
+
619
+ // write each string to output
620
+ characterStringBuffers.forEach(function(buffer) {
621
+ writer.write(buffer.length, 8); // text length
622
+ buffer.forEach(function(c) {
623
+ writer.write(c, 8);
624
+ });
625
+ });
626
+
627
+ return writer.toBuffer();
628
+ },
629
+ };
630
+ /**
631
+ * [SOA description]
632
+ * @type {Object}
633
+ * @docs https://tools.ietf.org/html/rfc1035#section-3.3.13
634
+ */
635
+ Packet.Resource.SOA = {
636
+ decode: function(reader, length) {
637
+ this.primary = Packet.Name.decode(reader);
638
+ this.admin = Packet.Name.decode(reader);
639
+ this.serial = reader.read(32);
640
+ this.refresh = reader.read(32);
641
+ this.retry = reader.read(32);
642
+ this.expiration = reader.read(32);
643
+ this.minimum = reader.read(32);
644
+ return this;
645
+ },
646
+ encode: function(record, writer) {
647
+ writer = writer || new Packet.Writer();
648
+ let len = 0;
649
+ len += Packet.Name.encode(record.primary).length;
650
+ len += Packet.Name.encode(record.admin).length;
651
+ len += (32 * 5) / 8;
652
+ writer.write(len, 16);
653
+ Packet.Name.encode(record.primary, writer);
654
+ Packet.Name.encode(record.admin, writer);
655
+ writer.write(record.serial, 32);
656
+ writer.write(record.refresh, 32);
657
+ writer.write(record.retry, 32);
658
+ writer.write(record.expiration, 32);
659
+ writer.write(record.minimum, 32);
660
+ return writer.toBuffer();
661
+ },
662
+ };
663
+ /**
664
+ * [SRV description]
665
+ * @type {Object}
666
+ * @docs https://tools.ietf.org/html/rfc2782
667
+ */
668
+ Packet.Resource.SRV = {
669
+ decode: function(reader, length) {
670
+ this.priority = reader.read(16);
671
+ this.weight = reader.read(16);
672
+ this.port = reader.read(16);
673
+ this.target = Packet.Name.decode(reader);
674
+ return this;
675
+ },
676
+ encode: function(record, writer) {
677
+ writer = writer || new Packet.Writer();
678
+ const { length } = Packet.Name.encode(record.target);
679
+ writer.write(length + 6, 16);
680
+ writer.write(record.priority, 16);
681
+ writer.write(record.weight, 16);
682
+ writer.write(record.port, 16);
683
+ Packet.Name.encode(record.target, writer);
684
+ return writer.toBuffer();
685
+ },
686
+ };
687
+
688
+ Packet.Resource.EDNS = function(rdata) {
689
+ return {
690
+ type : Packet.TYPE.EDNS,
691
+ class : 512, // Supported UDP Payload size
692
+ ttl : 0, // Extended RCODE and flags
693
+ rdata, // Objects of type Packet.Resource.EDNS.*
694
+ };
695
+ };
696
+
697
+ Packet.Resource.EDNS.decode = function(reader, length) {
698
+ this.type = Packet.TYPE.EDNS;
699
+ this.class = 512;
700
+ this.ttl = 0;
701
+ this.rdata = [];
702
+
703
+ while (length) {
704
+ const optionCode = reader.read(16);
705
+ const optionLength = reader.read(16); // In octet (https://tools.ietf.org/html/rfc6891#page-8)
706
+
707
+ const decoder = Object.keys(Packet.EDNS_OPTION_CODE).filter(function(type) {
708
+ return optionCode === Packet.EDNS_OPTION_CODE[type];
709
+ })[0];
710
+ if (decoder in Packet.Resource.EDNS && Packet.Resource.EDNS[decoder].decode) {
711
+ const rdata = Packet.Resource.EDNS[decoder].decode(reader, optionLength);
712
+ this.rdata.push(rdata);
713
+ } else {
714
+ reader.read(optionLength); // Ignore data that doesn't understand
715
+ debug('node-dns > unknown EDNS rdata decoder %s(%j)', decoder, optionCode);
716
+ }
717
+
718
+ length = length - 4 - optionLength;
719
+ }
720
+ return this;
721
+ };
722
+
723
+ Packet.Resource.EDNS.encode = function(record, writer) {
724
+ const rdataWriter = new Packet.Writer();
725
+ for (const rdata of record.rdata) {
726
+ const encoder = Object.keys(Packet.EDNS_OPTION_CODE).filter(function(type) {
727
+ return rdata.ednsCode === Packet.EDNS_OPTION_CODE[type];
728
+ })[0];
729
+ if (encoder in Packet.Resource.EDNS && Packet.Resource.EDNS[encoder].encode) {
730
+ const w = new Packet.Writer();
731
+ Packet.Resource.EDNS[encoder].encode(rdata, w);
732
+ rdataWriter.write(rdata.ednsCode, 16);
733
+ rdataWriter.write(w.buffer.length / 8, 16);
734
+ rdataWriter.writeBuffer(w);
735
+ } else {
736
+ debug('node-dns > unknown EDNS rdata encoder %s(%j)', encoder, rdata.ednsCode);
737
+ }
738
+ }
739
+ writer = writer || new Packet.Writer();
740
+ writer.write(rdataWriter.buffer.length / 8, 16);
741
+ writer.writeBuffer(rdataWriter);
742
+ return writer.toBuffer();
743
+ };
744
+
745
+ Packet.Resource.EDNS.ECS = function(clientIp) {
746
+ const [ ip, prefixLength ] = clientIp.split('/');
747
+ const numPrefixLength = parseInt(prefixLength) || 32;
748
+ return {
749
+ ednsCode : Packet.EDNS_OPTION_CODE.ECS,
750
+ family : 1,
751
+ sourcePrefixLength : numPrefixLength,
752
+ scopePrefixLength : 0,
753
+ ip,
754
+ };
755
+ };
756
+
757
+ Packet.Resource.EDNS.ECS.decode = function(reader, length) {
758
+ const rdata = {};
759
+ rdata.ednsCode = Packet.EDNS_OPTION_CODE.ECS;
760
+ rdata.family = reader.read(16);
761
+ rdata.sourcePrefixLength = reader.read(8);
762
+ rdata.scopePrefixLength = reader.read(8);
763
+ length -= 4;
764
+
765
+ if (rdata.family !== 1) {
766
+ debug('node-dns > unimplemented address family');
767
+ reader.read(length * 8); // Ignore data that doesn't understand
768
+ return rdata;
769
+ }
770
+
771
+ const ipv4Octets = [];
772
+ while (length--) {
773
+ const octet = reader.read(8);
774
+ ipv4Octets.push(octet);
775
+ }
776
+ while (ipv4Octets.length < 4) {
777
+ ipv4Octets.push(0);
778
+ }
779
+ rdata.ip = ipv4Octets.join('.');
780
+ return rdata;
781
+ };
782
+
783
+ Packet.Resource.EDNS.ECS.encode = function(record, writer) {
784
+ const ip = record.ip.split('.').map(s => parseInt(s));
785
+ writer.write(record.family, 16);
786
+ writer.write(record.sourcePrefixLength, 8);
787
+ writer.write(record.scopePrefixLength, 8);
788
+ writer.write(ip[0], 8);
789
+ writer.write(ip[1], 8);
790
+ writer.write(ip[2], 8);
791
+ writer.write(ip[3], 8);
792
+ };
793
+
794
+ Packet.Resource.CAA = {
795
+ encode: function(record, writer) {
796
+ writer = writer || new Packet.Writer();
797
+
798
+ const buffer = Buffer.from(record.tag + record.value, 'utf8');
799
+ writer.write(2 + buffer.length, 16);
800
+ writer.write(record.flags, 8);
801
+ writer.write(record.tag.length, 8);
802
+
803
+ buffer.forEach(function(c) {
804
+ writer.write(c, 8);
805
+ });
806
+ return writer.toBuffer();
807
+ },
808
+ };
809
+
810
+ Packet.Reader = BufferReader;
811
+ Packet.Writer = BufferWriter;
812
+
813
+ Packet.createResponseFromRequest = function(request) {
814
+ const response = new Packet(request);
815
+ response.header.qr = 1;
816
+ response.additionals = [];
817
+ return response;
818
+ };
819
+
820
+ Packet.createResourceFromQuestion = function(base, record) {
821
+ const resource = new Packet.Resource(base);
822
+ Object.assign(resource, record);
823
+ return resource;
824
+ };
825
+
826
+ Packet.readStream = socket => {
827
+ let chunks = [];
828
+ let chunklen = 0;
829
+ let received = false;
830
+ let expected = false;
831
+ return new Promise((resolve, reject) => {
832
+ const processMessage = () => {
833
+ if (received) return;
834
+ received = true;
835
+ const buffer = Buffer.concat(chunks, chunklen);
836
+ resolve(buffer.slice(2));
837
+ };
838
+ socket.on('end', processMessage);
839
+ socket.on('error', reject);
840
+ socket.on('readable', () => {
841
+ let chunk;
842
+ while ((chunk = socket.read()) !== null) {
843
+ chunks.push(chunk);
844
+ chunklen += chunk.length;
845
+ }
846
+ if (!expected && chunklen >= 2) {
847
+ if (chunks.length > 1) {
848
+ chunks = [ Buffer.concat(chunks, chunklen) ];
849
+ }
850
+ expected = chunks[0].readUInt16BE(0);
851
+ }
852
+
853
+ if (chunklen >= 2 + expected) {
854
+ processMessage();
855
+ }
856
+ });
857
+ });
858
+ };
859
+
860
+ /**
861
+ * DoH
862
+ * @docs https://tools.ietf.org/html/rfc8484
863
+ */
864
+ Packet.prototype.toBase64URL = function() {
865
+ const buffer = this.toBuffer();
866
+ const base64 = buffer.toString('base64');
867
+ return base64
868
+ .replace(/=/g, '')
869
+ .replace(/\+/g, '-')
870
+ .replace(/\//g, '_');
871
+ };
872
+
873
+ module.exports = Packet;