UNPKG

41 kBJavaScriptView Raw
1'use strict'
2
3const Buffer = require('buffer').Buffer
4const types = require('./types')
5const rcodes = require('./rcodes')
6const opcodes = require('./opcodes')
7const classes = require('./classes')
8const optioncodes = require('./optioncodes')
9const ip = require('@leichtgewicht/ip-codec')
10
11const QUERY_FLAG = 0
12const RESPONSE_FLAG = 1 << 15
13const FLUSH_MASK = 1 << 15
14const NOT_FLUSH_MASK = ~FLUSH_MASK
15const QU_MASK = 1 << 15
16const NOT_QU_MASK = ~QU_MASK
17
18const name = exports.name = {}
19
20name.encode = function (str, buf, offset) {
21 if (!buf) buf = Buffer.alloc(name.encodingLength(str))
22 if (!offset) offset = 0
23 const oldOffset = offset
24
25 // strip leading and trailing .
26 const n = str.replace(/^\.|\.$/gm, '')
27 if (n.length) {
28 const list = n.split('.')
29
30 for (let i = 0; i < list.length; i++) {
31 const len = buf.write(list[i], offset + 1)
32 buf[offset] = len
33 offset += len + 1
34 }
35 }
36
37 buf[offset++] = 0
38
39 name.encode.bytes = offset - oldOffset
40 return buf
41}
42
43name.encode.bytes = 0
44
45name.decode = function (buf, offset) {
46 if (!offset) offset = 0
47
48 const list = []
49 let oldOffset = offset
50 let totalLength = 0
51 let consumedBytes = 0
52 let jumped = false
53
54 while (true) {
55 if (offset >= buf.length) {
56 throw new Error('Cannot decode name (buffer overflow)')
57 }
58 const len = buf[offset++]
59 consumedBytes += jumped ? 0 : 1
60
61 if (len === 0) {
62 break
63 } else if ((len & 0xc0) === 0) {
64 if (offset + len > buf.length) {
65 throw new Error('Cannot decode name (buffer overflow)')
66 }
67 totalLength += len + 1
68 if (totalLength > 254) {
69 throw new Error('Cannot decode name (name too long)')
70 }
71 list.push(buf.toString('utf-8', offset, offset + len))
72 offset += len
73 consumedBytes += jumped ? 0 : len
74 } else if ((len & 0xc0) === 0xc0) {
75 if (offset + 1 > buf.length) {
76 throw new Error('Cannot decode name (buffer overflow)')
77 }
78 const jumpOffset = buf.readUInt16BE(offset - 1) - 0xc000
79 if (jumpOffset >= oldOffset) {
80 // Allow only pointers to prior data. RFC 1035, section 4.1.4 states:
81 // "[...] an entire domain name or a list of labels at the end of a domain name
82 // is replaced with a pointer to a prior occurance (sic) of the same name."
83 throw new Error('Cannot decode name (bad pointer)')
84 }
85 offset = jumpOffset
86 oldOffset = jumpOffset
87 consumedBytes += jumped ? 0 : 1
88 jumped = true
89 } else {
90 throw new Error('Cannot decode name (bad label)')
91 }
92 }
93
94 name.decode.bytes = consumedBytes
95 return list.length === 0 ? '.' : list.join('.')
96}
97
98name.decode.bytes = 0
99
100name.encodingLength = function (n) {
101 if (n === '.' || n === '..') return 1
102 return Buffer.byteLength(n.replace(/^\.|\.$/gm, '')) + 2
103}
104
105const string = {}
106
107string.encode = function (s, buf, offset) {
108 if (!buf) buf = Buffer.alloc(string.encodingLength(s))
109 if (!offset) offset = 0
110
111 const len = buf.write(s, offset + 1)
112 buf[offset] = len
113 string.encode.bytes = len + 1
114 return buf
115}
116
117string.encode.bytes = 0
118
119string.decode = function (buf, offset) {
120 if (!offset) offset = 0
121
122 const len = buf[offset]
123 const s = buf.toString('utf-8', offset + 1, offset + 1 + len)
124 string.decode.bytes = len + 1
125 return s
126}
127
128string.decode.bytes = 0
129
130string.encodingLength = function (s) {
131 return Buffer.byteLength(s) + 1
132}
133
134const header = {}
135
136header.encode = function (h, buf, offset) {
137 if (!buf) buf = header.encodingLength(h)
138 if (!offset) offset = 0
139
140 const flags = (h.flags || 0) & 32767
141 const type = h.type === 'response' ? RESPONSE_FLAG : QUERY_FLAG
142
143 buf.writeUInt16BE(h.id || 0, offset)
144 buf.writeUInt16BE(flags | type, offset + 2)
145 buf.writeUInt16BE(h.questions.length, offset + 4)
146 buf.writeUInt16BE(h.answers.length, offset + 6)
147 buf.writeUInt16BE(h.authorities.length, offset + 8)
148 buf.writeUInt16BE(h.additionals.length, offset + 10)
149
150 return buf
151}
152
153header.encode.bytes = 12
154
155header.decode = function (buf, offset) {
156 if (!offset) offset = 0
157 if (buf.length < 12) throw new Error('Header must be 12 bytes')
158 const flags = buf.readUInt16BE(offset + 2)
159
160 return {
161 id: buf.readUInt16BE(offset),
162 type: flags & RESPONSE_FLAG ? 'response' : 'query',
163 flags: flags & 32767,
164 flag_qr: ((flags >> 15) & 0x1) === 1,
165 opcode: opcodes.toString((flags >> 11) & 0xf),
166 flag_aa: ((flags >> 10) & 0x1) === 1,
167 flag_tc: ((flags >> 9) & 0x1) === 1,
168 flag_rd: ((flags >> 8) & 0x1) === 1,
169 flag_ra: ((flags >> 7) & 0x1) === 1,
170 flag_z: ((flags >> 6) & 0x1) === 1,
171 flag_ad: ((flags >> 5) & 0x1) === 1,
172 flag_cd: ((flags >> 4) & 0x1) === 1,
173 rcode: rcodes.toString(flags & 0xf),
174 questions: new Array(buf.readUInt16BE(offset + 4)),
175 answers: new Array(buf.readUInt16BE(offset + 6)),
176 authorities: new Array(buf.readUInt16BE(offset + 8)),
177 additionals: new Array(buf.readUInt16BE(offset + 10))
178 }
179}
180
181header.decode.bytes = 12
182
183header.encodingLength = function () {
184 return 12
185}
186
187const runknown = exports.unknown = {}
188
189runknown.encode = function (data, buf, offset) {
190 if (!buf) buf = Buffer.alloc(runknown.encodingLength(data))
191 if (!offset) offset = 0
192
193 buf.writeUInt16BE(data.length, offset)
194 data.copy(buf, offset + 2)
195
196 runknown.encode.bytes = data.length + 2
197 return buf
198}
199
200runknown.encode.bytes = 0
201
202runknown.decode = function (buf, offset) {
203 if (!offset) offset = 0
204
205 const len = buf.readUInt16BE(offset)
206 const data = buf.slice(offset + 2, offset + 2 + len)
207 runknown.decode.bytes = len + 2
208 return data
209}
210
211runknown.decode.bytes = 0
212
213runknown.encodingLength = function (data) {
214 return data.length + 2
215}
216
217const rns = exports.ns = {}
218
219rns.encode = function (data, buf, offset) {
220 if (!buf) buf = Buffer.alloc(rns.encodingLength(data))
221 if (!offset) offset = 0
222
223 name.encode(data, buf, offset + 2)
224 buf.writeUInt16BE(name.encode.bytes, offset)
225 rns.encode.bytes = name.encode.bytes + 2
226 return buf
227}
228
229rns.encode.bytes = 0
230
231rns.decode = function (buf, offset) {
232 if (!offset) offset = 0
233
234 const len = buf.readUInt16BE(offset)
235 const dd = name.decode(buf, offset + 2)
236
237 rns.decode.bytes = len + 2
238 return dd
239}
240
241rns.decode.bytes = 0
242
243rns.encodingLength = function (data) {
244 return name.encodingLength(data) + 2
245}
246
247const rsoa = exports.soa = {}
248
249rsoa.encode = function (data, buf, offset) {
250 if (!buf) buf = Buffer.alloc(rsoa.encodingLength(data))
251 if (!offset) offset = 0
252
253 const oldOffset = offset
254 offset += 2
255 name.encode(data.mname, buf, offset)
256 offset += name.encode.bytes
257 name.encode(data.rname, buf, offset)
258 offset += name.encode.bytes
259 buf.writeUInt32BE(data.serial || 0, offset)
260 offset += 4
261 buf.writeUInt32BE(data.refresh || 0, offset)
262 offset += 4
263 buf.writeUInt32BE(data.retry || 0, offset)
264 offset += 4
265 buf.writeUInt32BE(data.expire || 0, offset)
266 offset += 4
267 buf.writeUInt32BE(data.minimum || 0, offset)
268 offset += 4
269
270 buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
271 rsoa.encode.bytes = offset - oldOffset
272 return buf
273}
274
275rsoa.encode.bytes = 0
276
277rsoa.decode = function (buf, offset) {
278 if (!offset) offset = 0
279
280 const oldOffset = offset
281
282 const data = {}
283 offset += 2
284 data.mname = name.decode(buf, offset)
285 offset += name.decode.bytes
286 data.rname = name.decode(buf, offset)
287 offset += name.decode.bytes
288 data.serial = buf.readUInt32BE(offset)
289 offset += 4
290 data.refresh = buf.readUInt32BE(offset)
291 offset += 4
292 data.retry = buf.readUInt32BE(offset)
293 offset += 4
294 data.expire = buf.readUInt32BE(offset)
295 offset += 4
296 data.minimum = buf.readUInt32BE(offset)
297 offset += 4
298
299 rsoa.decode.bytes = offset - oldOffset
300 return data
301}
302
303rsoa.decode.bytes = 0
304
305rsoa.encodingLength = function (data) {
306 return 22 + name.encodingLength(data.mname) + name.encodingLength(data.rname)
307}
308
309const rtxt = exports.txt = {}
310
311rtxt.encode = function (data, buf, offset) {
312 if (!Array.isArray(data)) data = [data]
313 for (let i = 0; i < data.length; i++) {
314 if (typeof data[i] === 'string') {
315 data[i] = Buffer.from(data[i])
316 }
317 if (!Buffer.isBuffer(data[i])) {
318 throw new Error('Must be a Buffer')
319 }
320 }
321
322 if (!buf) buf = Buffer.alloc(rtxt.encodingLength(data))
323 if (!offset) offset = 0
324
325 const oldOffset = offset
326 offset += 2
327
328 data.forEach(function (d) {
329 buf[offset++] = d.length
330 d.copy(buf, offset, 0, d.length)
331 offset += d.length
332 })
333
334 buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
335 rtxt.encode.bytes = offset - oldOffset
336 return buf
337}
338
339rtxt.encode.bytes = 0
340
341rtxt.decode = function (buf, offset) {
342 if (!offset) offset = 0
343 const oldOffset = offset
344 let remaining = buf.readUInt16BE(offset)
345 offset += 2
346
347 let data = []
348 while (remaining > 0) {
349 const len = buf[offset++]
350 --remaining
351 if (remaining < len) {
352 throw new Error('Buffer overflow')
353 }
354 data.push(buf.slice(offset, offset + len))
355 offset += len
356 remaining -= len
357 }
358
359 rtxt.decode.bytes = offset - oldOffset
360 return data
361}
362
363rtxt.decode.bytes = 0
364
365rtxt.encodingLength = function (data) {
366 if (!Array.isArray(data)) data = [data]
367 let length = 2
368 data.forEach(function (buf) {
369 if (typeof buf === 'string') {
370 length += Buffer.byteLength(buf) + 1
371 } else {
372 length += buf.length + 1
373 }
374 })
375 return length
376}
377
378const rnull = exports.null = {}
379
380rnull.encode = function (data, buf, offset) {
381 if (!buf) buf = Buffer.alloc(rnull.encodingLength(data))
382 if (!offset) offset = 0
383
384 if (typeof data === 'string') data = Buffer.from(data)
385 if (!data) data = Buffer.alloc(0)
386
387 const oldOffset = offset
388 offset += 2
389
390 const len = data.length
391 data.copy(buf, offset, 0, len)
392 offset += len
393
394 buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
395 rnull.encode.bytes = offset - oldOffset
396 return buf
397}
398
399rnull.encode.bytes = 0
400
401rnull.decode = function (buf, offset) {
402 if (!offset) offset = 0
403 const oldOffset = offset
404 const len = buf.readUInt16BE(offset)
405
406 offset += 2
407
408 const data = buf.slice(offset, offset + len)
409 offset += len
410
411 rnull.decode.bytes = offset - oldOffset
412 return data
413}
414
415rnull.decode.bytes = 0
416
417rnull.encodingLength = function (data) {
418 if (!data) return 2
419 return (Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)) + 2
420}
421
422const rhinfo = exports.hinfo = {}
423
424rhinfo.encode = function (data, buf, offset) {
425 if (!buf) buf = Buffer.alloc(rhinfo.encodingLength(data))
426 if (!offset) offset = 0
427
428 const oldOffset = offset
429 offset += 2
430 string.encode(data.cpu, buf, offset)
431 offset += string.encode.bytes
432 string.encode(data.os, buf, offset)
433 offset += string.encode.bytes
434 buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
435 rhinfo.encode.bytes = offset - oldOffset
436 return buf
437}
438
439rhinfo.encode.bytes = 0
440
441rhinfo.decode = function (buf, offset) {
442 if (!offset) offset = 0
443
444 const oldOffset = offset
445
446 const data = {}
447 offset += 2
448 data.cpu = string.decode(buf, offset)
449 offset += string.decode.bytes
450 data.os = string.decode(buf, offset)
451 offset += string.decode.bytes
452 rhinfo.decode.bytes = offset - oldOffset
453 return data
454}
455
456rhinfo.decode.bytes = 0
457
458rhinfo.encodingLength = function (data) {
459 return string.encodingLength(data.cpu) + string.encodingLength(data.os) + 2
460}
461
462const rptr = exports.ptr = {}
463const rcname = exports.cname = rptr
464const rdname = exports.dname = rptr
465
466rptr.encode = function (data, buf, offset) {
467 if (!buf) buf = Buffer.alloc(rptr.encodingLength(data))
468 if (!offset) offset = 0
469
470 name.encode(data, buf, offset + 2)
471 buf.writeUInt16BE(name.encode.bytes, offset)
472 rptr.encode.bytes = name.encode.bytes + 2
473 return buf
474}
475
476rptr.encode.bytes = 0
477
478rptr.decode = function (buf, offset) {
479 if (!offset) offset = 0
480
481 const data = name.decode(buf, offset + 2)
482 rptr.decode.bytes = name.decode.bytes + 2
483 return data
484}
485
486rptr.decode.bytes = 0
487
488rptr.encodingLength = function (data) {
489 return name.encodingLength(data) + 2
490}
491
492const rsrv = exports.srv = {}
493
494rsrv.encode = function (data, buf, offset) {
495 if (!buf) buf = Buffer.alloc(rsrv.encodingLength(data))
496 if (!offset) offset = 0
497
498 buf.writeUInt16BE(data.priority || 0, offset + 2)
499 buf.writeUInt16BE(data.weight || 0, offset + 4)
500 buf.writeUInt16BE(data.port || 0, offset + 6)
501 name.encode(data.target, buf, offset + 8)
502
503 const len = name.encode.bytes + 6
504 buf.writeUInt16BE(len, offset)
505
506 rsrv.encode.bytes = len + 2
507 return buf
508}
509
510rsrv.encode.bytes = 0
511
512rsrv.decode = function (buf, offset) {
513 if (!offset) offset = 0
514
515 const len = buf.readUInt16BE(offset)
516
517 const data = {}
518 data.priority = buf.readUInt16BE(offset + 2)
519 data.weight = buf.readUInt16BE(offset + 4)
520 data.port = buf.readUInt16BE(offset + 6)
521 data.target = name.decode(buf, offset + 8)
522
523 rsrv.decode.bytes = len + 2
524 return data
525}
526
527rsrv.decode.bytes = 0
528
529rsrv.encodingLength = function (data) {
530 return 8 + name.encodingLength(data.target)
531}
532
533const rcaa = exports.caa = {}
534
535rcaa.ISSUER_CRITICAL = 1 << 7
536
537rcaa.encode = function (data, buf, offset) {
538 const len = rcaa.encodingLength(data)
539
540 if (!buf) buf = Buffer.alloc(rcaa.encodingLength(data))
541 if (!offset) offset = 0
542
543 if (data.issuerCritical) {
544 data.flags = rcaa.ISSUER_CRITICAL
545 }
546
547 buf.writeUInt16BE(len - 2, offset)
548 offset += 2
549 buf.writeUInt8(data.flags || 0, offset)
550 offset += 1
551 string.encode(data.tag, buf, offset)
552 offset += string.encode.bytes
553 buf.write(data.value, offset)
554 offset += Buffer.byteLength(data.value)
555
556 rcaa.encode.bytes = len
557 return buf
558}
559
560rcaa.encode.bytes = 0
561
562rcaa.decode = function (buf, offset) {
563 if (!offset) offset = 0
564
565 const len = buf.readUInt16BE(offset)
566 offset += 2
567
568 const oldOffset = offset
569 const data = {}
570 data.flags = buf.readUInt8(offset)
571 offset += 1
572 data.tag = string.decode(buf, offset)
573 offset += string.decode.bytes
574 data.value = buf.toString('utf-8', offset, oldOffset + len)
575
576 data.issuerCritical = !!(data.flags & rcaa.ISSUER_CRITICAL)
577
578 rcaa.decode.bytes = len + 2
579
580 return data
581}
582
583rcaa.decode.bytes = 0
584
585rcaa.encodingLength = function (data) {
586 return string.encodingLength(data.tag) + string.encodingLength(data.value) + 2
587}
588
589const rmx = exports.mx = {}
590
591rmx.encode = function (data, buf, offset) {
592 if (!buf) buf = Buffer.alloc(rmx.encodingLength(data))
593 if (!offset) offset = 0
594
595 const oldOffset = offset
596 offset += 2
597 buf.writeUInt16BE(data.preference || 0, offset)
598 offset += 2
599 name.encode(data.exchange, buf, offset)
600 offset += name.encode.bytes
601
602 buf.writeUInt16BE(offset - oldOffset - 2, oldOffset)
603 rmx.encode.bytes = offset - oldOffset
604 return buf
605}
606
607rmx.encode.bytes = 0
608
609rmx.decode = function (buf, offset) {
610 if (!offset) offset = 0
611
612 const oldOffset = offset
613
614 const data = {}
615 offset += 2
616 data.preference = buf.readUInt16BE(offset)
617 offset += 2
618 data.exchange = name.decode(buf, offset)
619 offset += name.decode.bytes
620
621 rmx.decode.bytes = offset - oldOffset
622 return data
623}
624
625rmx.encodingLength = function (data) {
626 return 4 + name.encodingLength(data.exchange)
627}
628
629const ra = exports.a = {}
630
631ra.encode = function (host, buf, offset) {
632 if (!buf) buf = Buffer.alloc(ra.encodingLength(host))
633 if (!offset) offset = 0
634
635 buf.writeUInt16BE(4, offset)
636 offset += 2
637 ip.v4.encode(host, buf, offset)
638 ra.encode.bytes = 6
639 return buf
640}
641
642ra.encode.bytes = 0
643
644ra.decode = function (buf, offset) {
645 if (!offset) offset = 0
646
647 offset += 2
648 const host = ip.v4.decode(buf, offset)
649 ra.decode.bytes = 6
650 return host
651}
652
653ra.decode.bytes = 0
654
655ra.encodingLength = function () {
656 return 6
657}
658
659const raaaa = exports.aaaa = {}
660
661raaaa.encode = function (host, buf, offset) {
662 if (!buf) buf = Buffer.alloc(raaaa.encodingLength(host))
663 if (!offset) offset = 0
664
665 buf.writeUInt16BE(16, offset)
666 offset += 2
667 ip.v6.encode(host, buf, offset)
668 raaaa.encode.bytes = 18
669 return buf
670}
671
672raaaa.encode.bytes = 0
673
674raaaa.decode = function (buf, offset) {
675 if (!offset) offset = 0
676
677 offset += 2
678 const host = ip.v6.decode(buf, offset)
679 raaaa.decode.bytes = 18
680 return host
681}
682
683raaaa.decode.bytes = 0
684
685raaaa.encodingLength = function () {
686 return 18
687}
688
689const roption = exports.option = {}
690
691roption.encode = function (option, buf, offset) {
692 if (!buf) buf = Buffer.alloc(roption.encodingLength(option))
693 if (!offset) offset = 0
694 const oldOffset = offset
695
696 const code = optioncodes.toCode(option.code)
697 buf.writeUInt16BE(code, offset)
698 offset += 2
699 if (option.data) {
700 buf.writeUInt16BE(option.data.length, offset)
701 offset += 2
702 option.data.copy(buf, offset)
703 offset += option.data.length
704 } else {
705 switch (code) {
706 // case 3: NSID. No encode makes sense.
707 // case 5,6,7: Not implementable
708 case 8: // ECS
709 // note: do IP math before calling
710 const spl = option.sourcePrefixLength || 0
711 const fam = option.family || ip.familyOf(option.ip)
712 const ipBuf = ip.encode(option.ip, Buffer.alloc)
713 const ipLen = Math.ceil(spl / 8)
714 buf.writeUInt16BE(ipLen + 4, offset)
715 offset += 2
716 buf.writeUInt16BE(fam, offset)
717 offset += 2
718 buf.writeUInt8(spl, offset++)
719 buf.writeUInt8(option.scopePrefixLength || 0, offset++)
720
721 ipBuf.copy(buf, offset, 0, ipLen)
722 offset += ipLen
723 break
724 // case 9: EXPIRE (experimental)
725 // case 10: COOKIE. No encode makes sense.
726 case 11: // KEEP-ALIVE
727 if (option.timeout) {
728 buf.writeUInt16BE(2, offset)
729 offset += 2
730 buf.writeUInt16BE(option.timeout, offset)
731 offset += 2
732 } else {
733 buf.writeUInt16BE(0, offset)
734 offset += 2
735 }
736 break
737 case 12: // PADDING
738 const len = option.length || 0
739 buf.writeUInt16BE(len, offset)
740 offset += 2
741 buf.fill(0, offset, offset + len)
742 offset += len
743 break
744 // case 13: CHAIN. Experimental.
745 case 14: // KEY-TAG
746 const tagsLen = option.tags.length * 2
747 buf.writeUInt16BE(tagsLen, offset)
748 offset += 2
749 for (const tag of option.tags) {
750 buf.writeUInt16BE(tag, offset)
751 offset += 2
752 }
753 break
754 default:
755 throw new Error(`Unknown roption code: ${option.code}`)
756 }
757 }
758
759 roption.encode.bytes = offset - oldOffset
760 return buf
761}
762
763roption.encode.bytes = 0
764
765roption.decode = function (buf, offset) {
766 if (!offset) offset = 0
767 const option = {}
768 option.code = buf.readUInt16BE(offset)
769 option.type = optioncodes.toString(option.code)
770 offset += 2
771 const len = buf.readUInt16BE(offset)
772 offset += 2
773 option.data = buf.slice(offset, offset + len)
774 switch (option.code) {
775 // case 3: NSID. No decode makes sense.
776 case 8: // ECS
777 option.family = buf.readUInt16BE(offset)
778 offset += 2
779 option.sourcePrefixLength = buf.readUInt8(offset++)
780 option.scopePrefixLength = buf.readUInt8(offset++)
781 const padded = Buffer.alloc((option.family === 1) ? 4 : 16)
782 buf.copy(padded, 0, offset, offset + len - 4)
783 option.ip = ip.decode(padded)
784 break
785 // case 12: Padding. No decode makes sense.
786 case 11: // KEEP-ALIVE
787 if (len > 0) {
788 option.timeout = buf.readUInt16BE(offset)
789 offset += 2
790 }
791 break
792 case 14:
793 option.tags = []
794 for (let i = 0; i < len; i += 2) {
795 option.tags.push(buf.readUInt16BE(offset))
796 offset += 2
797 }
798 // don't worry about default. caller will use data if desired
799 }
800
801 roption.decode.bytes = len + 4
802 return option
803}
804
805roption.decode.bytes = 0
806
807roption.encodingLength = function (option) {
808 if (option.data) {
809 return option.data.length + 4
810 }
811 const code = optioncodes.toCode(option.code)
812 switch (code) {
813 case 8: // ECS
814 const spl = option.sourcePrefixLength || 0
815 return Math.ceil(spl / 8) + 8
816 case 11: // KEEP-ALIVE
817 return (typeof option.timeout === 'number') ? 6 : 4
818 case 12: // PADDING
819 return option.length + 4
820 case 14: // KEY-TAG
821 return 4 + (option.tags.length * 2)
822 }
823 throw new Error(`Unknown roption code: ${option.code}`)
824}
825
826const ropt = exports.opt = {}
827
828ropt.encode = function (options, buf, offset) {
829 if (!buf) buf = Buffer.alloc(ropt.encodingLength(options))
830 if (!offset) offset = 0
831 const oldOffset = offset
832
833 const rdlen = encodingLengthList(options, roption)
834 buf.writeUInt16BE(rdlen, offset)
835 offset = encodeList(options, roption, buf, offset + 2)
836
837 ropt.encode.bytes = offset - oldOffset
838 return buf
839}
840
841ropt.encode.bytes = 0
842
843ropt.decode = function (buf, offset) {
844 if (!offset) offset = 0
845 const oldOffset = offset
846
847 const options = []
848 let rdlen = buf.readUInt16BE(offset)
849 offset += 2
850 let o = 0
851 while (rdlen > 0) {
852 options[o++] = roption.decode(buf, offset)
853 offset += roption.decode.bytes
854 rdlen -= roption.decode.bytes
855 }
856 ropt.decode.bytes = offset - oldOffset
857 return options
858}
859
860ropt.decode.bytes = 0
861
862ropt.encodingLength = function (options) {
863 return 2 + encodingLengthList(options || [], roption)
864}
865
866const rdnskey = exports.dnskey = {}
867
868rdnskey.PROTOCOL_DNSSEC = 3
869rdnskey.ZONE_KEY = 0x80
870rdnskey.SECURE_ENTRYPOINT = 0x8000
871
872rdnskey.encode = function (key, buf, offset) {
873 if (!buf) buf = Buffer.alloc(rdnskey.encodingLength(key))
874 if (!offset) offset = 0
875 const oldOffset = offset
876
877 const keydata = key.key
878 if (!Buffer.isBuffer(keydata)) {
879 throw new Error('Key must be a Buffer')
880 }
881
882 offset += 2 // Leave space for length
883 buf.writeUInt16BE(key.flags, offset)
884 offset += 2
885 buf.writeUInt8(rdnskey.PROTOCOL_DNSSEC, offset)
886 offset += 1
887 buf.writeUInt8(key.algorithm, offset)
888 offset += 1
889 keydata.copy(buf, offset, 0, keydata.length)
890 offset += keydata.length
891
892 rdnskey.encode.bytes = offset - oldOffset
893 buf.writeUInt16BE(rdnskey.encode.bytes - 2, oldOffset)
894 return buf
895}
896
897rdnskey.encode.bytes = 0
898
899rdnskey.decode = function (buf, offset) {
900 if (!offset) offset = 0
901 const oldOffset = offset
902
903 var key = {}
904 var length = buf.readUInt16BE(offset)
905 offset += 2
906 key.flags = buf.readUInt16BE(offset)
907 offset += 2
908 if (buf.readUInt8(offset) !== rdnskey.PROTOCOL_DNSSEC) {
909 throw new Error('Protocol must be 3')
910 }
911 offset += 1
912 key.algorithm = buf.readUInt8(offset)
913 offset += 1
914 key.key = buf.slice(offset, oldOffset + length + 2)
915 offset += key.key.length
916 rdnskey.decode.bytes = offset - oldOffset
917 return key
918}
919
920rdnskey.decode.bytes = 0
921
922rdnskey.encodingLength = function (key) {
923 return 6 + Buffer.byteLength(key.key)
924}
925
926const rrrsig = exports.rrsig = {}
927
928rrrsig.encode = function (sig, buf, offset) {
929 if (!buf) buf = Buffer.alloc(rrrsig.encodingLength(sig))
930 if (!offset) offset = 0
931 const oldOffset = offset
932
933 const signature = sig.signature
934 if (!Buffer.isBuffer(signature)) {
935 throw new Error('Signature must be a Buffer')
936 }
937
938 offset += 2 // Leave space for length
939 buf.writeUInt16BE(types.toType(sig.typeCovered), offset)
940 offset += 2
941 buf.writeUInt8(sig.algorithm, offset)
942 offset += 1
943 buf.writeUInt8(sig.labels, offset)
944 offset += 1
945 buf.writeUInt32BE(sig.originalTTL, offset)
946 offset += 4
947 buf.writeUInt32BE(sig.expiration, offset)
948 offset += 4
949 buf.writeUInt32BE(sig.inception, offset)
950 offset += 4
951 buf.writeUInt16BE(sig.keyTag, offset)
952 offset += 2
953 name.encode(sig.signersName, buf, offset)
954 offset += name.encode.bytes
955 signature.copy(buf, offset, 0, signature.length)
956 offset += signature.length
957
958 rrrsig.encode.bytes = offset - oldOffset
959 buf.writeUInt16BE(rrrsig.encode.bytes - 2, oldOffset)
960 return buf
961}
962
963rrrsig.encode.bytes = 0
964
965rrrsig.decode = function (buf, offset) {
966 if (!offset) offset = 0
967 const oldOffset = offset
968
969 var sig = {}
970 var length = buf.readUInt16BE(offset)
971 offset += 2
972 sig.typeCovered = types.toString(buf.readUInt16BE(offset))
973 offset += 2
974 sig.algorithm = buf.readUInt8(offset)
975 offset += 1
976 sig.labels = buf.readUInt8(offset)
977 offset += 1
978 sig.originalTTL = buf.readUInt32BE(offset)
979 offset += 4
980 sig.expiration = buf.readUInt32BE(offset)
981 offset += 4
982 sig.inception = buf.readUInt32BE(offset)
983 offset += 4
984 sig.keyTag = buf.readUInt16BE(offset)
985 offset += 2
986 sig.signersName = name.decode(buf, offset)
987 offset += name.decode.bytes
988 sig.signature = buf.slice(offset, oldOffset + length + 2)
989 offset += sig.signature.length
990 rrrsig.decode.bytes = offset - oldOffset
991 return sig
992}
993
994rrrsig.decode.bytes = 0
995
996rrrsig.encodingLength = function (sig) {
997 return 20 +
998 name.encodingLength(sig.signersName) +
999 Buffer.byteLength(sig.signature)
1000}
1001
1002const rrp = exports.rp = {}
1003
1004rrp.encode = function (data, buf, offset) {
1005 if (!buf) buf = Buffer.alloc(rrp.encodingLength(data))
1006 if (!offset) offset = 0
1007 const oldOffset = offset
1008
1009 offset += 2 // Leave space for length
1010 name.encode(data.mbox || '.', buf, offset)
1011 offset += name.encode.bytes
1012 name.encode(data.txt || '.', buf, offset)
1013 offset += name.encode.bytes
1014 rrp.encode.bytes = offset - oldOffset
1015 buf.writeUInt16BE(rrp.encode.bytes - 2, oldOffset)
1016 return buf
1017}
1018
1019rrp.encode.bytes = 0
1020
1021rrp.decode = function (buf, offset) {
1022 if (!offset) offset = 0
1023 const oldOffset = offset
1024
1025 const data = {}
1026 offset += 2
1027 data.mbox = name.decode(buf, offset) || '.'
1028 offset += name.decode.bytes
1029 data.txt = name.decode(buf, offset) || '.'
1030 offset += name.decode.bytes
1031 rrp.decode.bytes = offset - oldOffset
1032 return data
1033}
1034
1035rrp.decode.bytes = 0
1036
1037rrp.encodingLength = function (data) {
1038 return 2 + name.encodingLength(data.mbox || '.') + name.encodingLength(data.txt || '.')
1039}
1040
1041const typebitmap = {}
1042
1043typebitmap.encode = function (typelist, buf, offset) {
1044 if (!buf) buf = Buffer.alloc(typebitmap.encodingLength(typelist))
1045 if (!offset) offset = 0
1046 const oldOffset = offset
1047
1048 var typesByWindow = []
1049 for (var i = 0; i < typelist.length; i++) {
1050 var typeid = types.toType(typelist[i])
1051 if (typesByWindow[typeid >> 8] === undefined) {
1052 typesByWindow[typeid >> 8] = []
1053 }
1054 typesByWindow[typeid >> 8][(typeid >> 3) & 0x1F] |= 1 << (7 - (typeid & 0x7))
1055 }
1056
1057 for (i = 0; i < typesByWindow.length; i++) {
1058 if (typesByWindow[i] !== undefined) {
1059 var windowBuf = Buffer.from(typesByWindow[i])
1060 buf.writeUInt8(i, offset)
1061 offset += 1
1062 buf.writeUInt8(windowBuf.length, offset)
1063 offset += 1
1064 windowBuf.copy(buf, offset)
1065 offset += windowBuf.length
1066 }
1067 }
1068
1069 typebitmap.encode.bytes = offset - oldOffset
1070 return buf
1071}
1072
1073typebitmap.encode.bytes = 0
1074
1075typebitmap.decode = function (buf, offset, length) {
1076 if (!offset) offset = 0
1077 const oldOffset = offset
1078
1079 var typelist = []
1080 while (offset - oldOffset < length) {
1081 var window = buf.readUInt8(offset)
1082 offset += 1
1083 var windowLength = buf.readUInt8(offset)
1084 offset += 1
1085 for (var i = 0; i < windowLength; i++) {
1086 var b = buf.readUInt8(offset + i)
1087 for (var j = 0; j < 8; j++) {
1088 if (b & (1 << (7 - j))) {
1089 var typeid = types.toString((window << 8) | (i << 3) | j)
1090 typelist.push(typeid)
1091 }
1092 }
1093 }
1094 offset += windowLength
1095 }
1096
1097 typebitmap.decode.bytes = offset - oldOffset
1098 return typelist
1099}
1100
1101typebitmap.decode.bytes = 0
1102
1103typebitmap.encodingLength = function (typelist) {
1104 var extents = []
1105 for (var i = 0; i < typelist.length; i++) {
1106 var typeid = types.toType(typelist[i])
1107 extents[typeid >> 8] = Math.max(extents[typeid >> 8] || 0, typeid & 0xFF)
1108 }
1109
1110 var len = 0
1111 for (i = 0; i < extents.length; i++) {
1112 if (extents[i] !== undefined) {
1113 len += 2 + Math.ceil((extents[i] + 1) / 8)
1114 }
1115 }
1116
1117 return len
1118}
1119
1120const rnsec = exports.nsec = {}
1121
1122rnsec.encode = function (record, buf, offset) {
1123 if (!buf) buf = Buffer.alloc(rnsec.encodingLength(record))
1124 if (!offset) offset = 0
1125 const oldOffset = offset
1126
1127 offset += 2 // Leave space for length
1128 name.encode(record.nextDomain, buf, offset)
1129 offset += name.encode.bytes
1130 typebitmap.encode(record.rrtypes, buf, offset)
1131 offset += typebitmap.encode.bytes
1132
1133 rnsec.encode.bytes = offset - oldOffset
1134 buf.writeUInt16BE(rnsec.encode.bytes - 2, oldOffset)
1135 return buf
1136}
1137
1138rnsec.encode.bytes = 0
1139
1140rnsec.decode = function (buf, offset) {
1141 if (!offset) offset = 0
1142 const oldOffset = offset
1143
1144 var record = {}
1145 var length = buf.readUInt16BE(offset)
1146 offset += 2
1147 record.nextDomain = name.decode(buf, offset)
1148 offset += name.decode.bytes
1149 record.rrtypes = typebitmap.decode(buf, offset, length - (offset - oldOffset))
1150 offset += typebitmap.decode.bytes
1151
1152 rnsec.decode.bytes = offset - oldOffset
1153 return record
1154}
1155
1156rnsec.decode.bytes = 0
1157
1158rnsec.encodingLength = function (record) {
1159 return 2 +
1160 name.encodingLength(record.nextDomain) +
1161 typebitmap.encodingLength(record.rrtypes)
1162}
1163
1164const rnsec3 = exports.nsec3 = {}
1165
1166rnsec3.encode = function (record, buf, offset) {
1167 if (!buf) buf = Buffer.alloc(rnsec3.encodingLength(record))
1168 if (!offset) offset = 0
1169 const oldOffset = offset
1170
1171 const salt = record.salt
1172 if (!Buffer.isBuffer(salt)) {
1173 throw new Error('salt must be a Buffer')
1174 }
1175
1176 const nextDomain = record.nextDomain
1177 if (!Buffer.isBuffer(nextDomain)) {
1178 throw new Error('nextDomain must be a Buffer')
1179 }
1180
1181 offset += 2 // Leave space for length
1182 buf.writeUInt8(record.algorithm, offset)
1183 offset += 1
1184 buf.writeUInt8(record.flags, offset)
1185 offset += 1
1186 buf.writeUInt16BE(record.iterations, offset)
1187 offset += 2
1188 buf.writeUInt8(salt.length, offset)
1189 offset += 1
1190 salt.copy(buf, offset, 0, salt.length)
1191 offset += salt.length
1192 buf.writeUInt8(nextDomain.length, offset)
1193 offset += 1
1194 nextDomain.copy(buf, offset, 0, nextDomain.length)
1195 offset += nextDomain.length
1196 typebitmap.encode(record.rrtypes, buf, offset)
1197 offset += typebitmap.encode.bytes
1198
1199 rnsec3.encode.bytes = offset - oldOffset
1200 buf.writeUInt16BE(rnsec3.encode.bytes - 2, oldOffset)
1201 return buf
1202}
1203
1204rnsec3.encode.bytes = 0
1205
1206rnsec3.decode = function (buf, offset) {
1207 if (!offset) offset = 0
1208 const oldOffset = offset
1209
1210 var record = {}
1211 var length = buf.readUInt16BE(offset)
1212 offset += 2
1213 record.algorithm = buf.readUInt8(offset)
1214 offset += 1
1215 record.flags = buf.readUInt8(offset)
1216 offset += 1
1217 record.iterations = buf.readUInt16BE(offset)
1218 offset += 2
1219 const saltLength = buf.readUInt8(offset)
1220 offset += 1
1221 record.salt = buf.slice(offset, offset + saltLength)
1222 offset += saltLength
1223 const hashLength = buf.readUInt8(offset)
1224 offset += 1
1225 record.nextDomain = buf.slice(offset, offset + hashLength)
1226 offset += hashLength
1227 record.rrtypes = typebitmap.decode(buf, offset, length - (offset - oldOffset))
1228 offset += typebitmap.decode.bytes
1229
1230 rnsec3.decode.bytes = offset - oldOffset
1231 return record
1232}
1233
1234rnsec3.decode.bytes = 0
1235
1236rnsec3.encodingLength = function (record) {
1237 return 8 +
1238 record.salt.length +
1239 record.nextDomain.length +
1240 typebitmap.encodingLength(record.rrtypes)
1241}
1242
1243const rds = exports.ds = {}
1244
1245rds.encode = function (digest, buf, offset) {
1246 if (!buf) buf = Buffer.alloc(rds.encodingLength(digest))
1247 if (!offset) offset = 0
1248 const oldOffset = offset
1249
1250 const digestdata = digest.digest
1251 if (!Buffer.isBuffer(digestdata)) {
1252 throw new Error('Digest must be a Buffer')
1253 }
1254
1255 offset += 2 // Leave space for length
1256 buf.writeUInt16BE(digest.keyTag, offset)
1257 offset += 2
1258 buf.writeUInt8(digest.algorithm, offset)
1259 offset += 1
1260 buf.writeUInt8(digest.digestType, offset)
1261 offset += 1
1262 digestdata.copy(buf, offset, 0, digestdata.length)
1263 offset += digestdata.length
1264
1265 rds.encode.bytes = offset - oldOffset
1266 buf.writeUInt16BE(rds.encode.bytes - 2, oldOffset)
1267 return buf
1268}
1269
1270rds.encode.bytes = 0
1271
1272rds.decode = function (buf, offset) {
1273 if (!offset) offset = 0
1274 const oldOffset = offset
1275
1276 var digest = {}
1277 var length = buf.readUInt16BE(offset)
1278 offset += 2
1279 digest.keyTag = buf.readUInt16BE(offset)
1280 offset += 2
1281 digest.algorithm = buf.readUInt8(offset)
1282 offset += 1
1283 digest.digestType = buf.readUInt8(offset)
1284 offset += 1
1285 digest.digest = buf.slice(offset, oldOffset + length + 2)
1286 offset += digest.digest.length
1287 rds.decode.bytes = offset - oldOffset
1288 return digest
1289}
1290
1291rds.decode.bytes = 0
1292
1293rds.encodingLength = function (digest) {
1294 return 6 + Buffer.byteLength(digest.digest)
1295}
1296
1297const rsshfp = exports.sshfp = {}
1298
1299rsshfp.getFingerprintLengthForHashType = function getFingerprintLengthForHashType (hashType) {
1300 switch (hashType) {
1301 case 1: return 20
1302 case 2: return 32
1303 }
1304}
1305
1306rsshfp.encode = function encode (record, buf, offset) {
1307 if (!buf) buf = Buffer.alloc(rsshfp.encodingLength(record))
1308 if (!offset) offset = 0
1309 const oldOffset = offset
1310
1311 offset += 2 // The function call starts with the offset pointer at the RDLENGTH field, not the RDATA one
1312 buf[offset] = record.algorithm
1313 offset += 1
1314 buf[offset] = record.hash
1315 offset += 1
1316
1317 const fingerprintBuf = Buffer.from(record.fingerprint.toUpperCase(), 'hex')
1318 if (fingerprintBuf.length !== rsshfp.getFingerprintLengthForHashType(record.hash)) {
1319 throw new Error('Invalid fingerprint length')
1320 }
1321 fingerprintBuf.copy(buf, offset)
1322 offset += fingerprintBuf.byteLength
1323
1324 rsshfp.encode.bytes = offset - oldOffset
1325 buf.writeUInt16BE(rsshfp.encode.bytes - 2, oldOffset)
1326
1327 return buf
1328}
1329
1330rsshfp.encode.bytes = 0
1331
1332rsshfp.decode = function decode (buf, offset) {
1333 if (!offset) offset = 0
1334 const oldOffset = offset
1335
1336 const record = {}
1337 offset += 2 // Account for the RDLENGTH field
1338 record.algorithm = buf[offset]
1339 offset += 1
1340 record.hash = buf[offset]
1341 offset += 1
1342
1343 const fingerprintLength = rsshfp.getFingerprintLengthForHashType(record.hash)
1344 record.fingerprint = buf.slice(offset, offset + fingerprintLength).toString('hex').toUpperCase()
1345 offset += fingerprintLength
1346 rsshfp.decode.bytes = offset - oldOffset
1347 return record
1348}
1349
1350rsshfp.decode.bytes = 0
1351
1352rsshfp.encodingLength = function (record) {
1353 return 4 + Buffer.from(record.fingerprint, 'hex').byteLength
1354}
1355
1356const renc = exports.record = function (type) {
1357 switch (type.toUpperCase()) {
1358 case 'A': return ra
1359 case 'PTR': return rptr
1360 case 'CNAME': return rcname
1361 case 'DNAME': return rdname
1362 case 'TXT': return rtxt
1363 case 'NULL': return rnull
1364 case 'AAAA': return raaaa
1365 case 'SRV': return rsrv
1366 case 'HINFO': return rhinfo
1367 case 'CAA': return rcaa
1368 case 'NS': return rns
1369 case 'SOA': return rsoa
1370 case 'MX': return rmx
1371 case 'OPT': return ropt
1372 case 'DNSKEY': return rdnskey
1373 case 'RRSIG': return rrrsig
1374 case 'RP': return rrp
1375 case 'NSEC': return rnsec
1376 case 'NSEC3': return rnsec3
1377 case 'SSHFP': return rsshfp
1378 case 'DS': return rds
1379 }
1380 return runknown
1381}
1382
1383const answer = exports.answer = {}
1384
1385answer.encode = function (a, buf, offset) {
1386 if (!buf) buf = Buffer.alloc(answer.encodingLength(a))
1387 if (!offset) offset = 0
1388
1389 const oldOffset = offset
1390
1391 name.encode(a.name, buf, offset)
1392 offset += name.encode.bytes
1393
1394 buf.writeUInt16BE(types.toType(a.type), offset)
1395
1396 if (a.type.toUpperCase() === 'OPT') {
1397 if (a.name !== '.') {
1398 throw new Error('OPT name must be root.')
1399 }
1400 buf.writeUInt16BE(a.udpPayloadSize || 4096, offset + 2)
1401 buf.writeUInt8(a.extendedRcode || 0, offset + 4)
1402 buf.writeUInt8(a.ednsVersion || 0, offset + 5)
1403 buf.writeUInt16BE(a.flags || 0, offset + 6)
1404
1405 offset += 8
1406 ropt.encode(a.options || [], buf, offset)
1407 offset += ropt.encode.bytes
1408 } else {
1409 let klass = classes.toClass(a.class === undefined ? 'IN' : a.class)
1410 if (a.flush) klass |= FLUSH_MASK // the 1st bit of the class is the flush bit
1411 buf.writeUInt16BE(klass, offset + 2)
1412 buf.writeUInt32BE(a.ttl || 0, offset + 4)
1413
1414 offset += 8
1415 const enc = renc(a.type)
1416 enc.encode(a.data, buf, offset)
1417 offset += enc.encode.bytes
1418 }
1419
1420 answer.encode.bytes = offset - oldOffset
1421 return buf
1422}
1423
1424answer.encode.bytes = 0
1425
1426answer.decode = function (buf, offset) {
1427 if (!offset) offset = 0
1428
1429 const a = {}
1430 const oldOffset = offset
1431
1432 a.name = name.decode(buf, offset)
1433 offset += name.decode.bytes
1434 a.type = types.toString(buf.readUInt16BE(offset))
1435 if (a.type === 'OPT') {
1436 a.udpPayloadSize = buf.readUInt16BE(offset + 2)
1437 a.extendedRcode = buf.readUInt8(offset + 4)
1438 a.ednsVersion = buf.readUInt8(offset + 5)
1439 a.flags = buf.readUInt16BE(offset + 6)
1440 a.flag_do = ((a.flags >> 15) & 0x1) === 1
1441 a.options = ropt.decode(buf, offset + 8)
1442 offset += 8 + ropt.decode.bytes
1443 } else {
1444 const klass = buf.readUInt16BE(offset + 2)
1445 a.ttl = buf.readUInt32BE(offset + 4)
1446
1447 a.class = classes.toString(klass & NOT_FLUSH_MASK)
1448 a.flush = !!(klass & FLUSH_MASK)
1449
1450 const enc = renc(a.type)
1451 a.data = enc.decode(buf, offset + 8)
1452 offset += 8 + enc.decode.bytes
1453 }
1454
1455 answer.decode.bytes = offset - oldOffset
1456 return a
1457}
1458
1459answer.decode.bytes = 0
1460
1461answer.encodingLength = function (a) {
1462 const data = (a.data !== null && a.data !== undefined) ? a.data : a.options
1463 return name.encodingLength(a.name) + 8 + renc(a.type).encodingLength(data)
1464}
1465
1466const question = exports.question = {}
1467
1468question.encode = function (q, buf, offset) {
1469 if (!buf) buf = Buffer.alloc(question.encodingLength(q))
1470 if (!offset) offset = 0
1471
1472 const oldOffset = offset
1473
1474 name.encode(q.name, buf, offset)
1475 offset += name.encode.bytes
1476
1477 buf.writeUInt16BE(types.toType(q.type), offset)
1478 offset += 2
1479
1480 buf.writeUInt16BE(classes.toClass(q.class === undefined ? 'IN' : q.class), offset)
1481 offset += 2
1482
1483 question.encode.bytes = offset - oldOffset
1484 return q
1485}
1486
1487question.encode.bytes = 0
1488
1489question.decode = function (buf, offset) {
1490 if (!offset) offset = 0
1491
1492 const oldOffset = offset
1493 const q = {}
1494
1495 q.name = name.decode(buf, offset)
1496 offset += name.decode.bytes
1497
1498 q.type = types.toString(buf.readUInt16BE(offset))
1499 offset += 2
1500
1501 q.class = classes.toString(buf.readUInt16BE(offset))
1502 offset += 2
1503
1504 const qu = !!(q.class & QU_MASK)
1505 if (qu) q.class &= NOT_QU_MASK
1506
1507 question.decode.bytes = offset - oldOffset
1508 return q
1509}
1510
1511question.decode.bytes = 0
1512
1513question.encodingLength = function (q) {
1514 return name.encodingLength(q.name) + 4
1515}
1516
1517exports.AUTHORITATIVE_ANSWER = 1 << 10
1518exports.TRUNCATED_RESPONSE = 1 << 9
1519exports.RECURSION_DESIRED = 1 << 8
1520exports.RECURSION_AVAILABLE = 1 << 7
1521exports.AUTHENTIC_DATA = 1 << 5
1522exports.CHECKING_DISABLED = 1 << 4
1523exports.DNSSEC_OK = 1 << 15
1524
1525exports.encode = function (result, buf, offset) {
1526 const allocing = !buf
1527
1528 if (allocing) buf = Buffer.alloc(exports.encodingLength(result))
1529 if (!offset) offset = 0
1530
1531 const oldOffset = offset
1532
1533 if (!result.questions) result.questions = []
1534 if (!result.answers) result.answers = []
1535 if (!result.authorities) result.authorities = []
1536 if (!result.additionals) result.additionals = []
1537
1538 header.encode(result, buf, offset)
1539 offset += header.encode.bytes
1540
1541 offset = encodeList(result.questions, question, buf, offset)
1542 offset = encodeList(result.answers, answer, buf, offset)
1543 offset = encodeList(result.authorities, answer, buf, offset)
1544 offset = encodeList(result.additionals, answer, buf, offset)
1545
1546 exports.encode.bytes = offset - oldOffset
1547
1548 // just a quick sanity check
1549 if (allocing && exports.encode.bytes !== buf.length) {
1550 return buf.slice(0, exports.encode.bytes)
1551 }
1552
1553 return buf
1554}
1555
1556exports.encode.bytes = 0
1557
1558exports.decode = function (buf, offset) {
1559 if (!offset) offset = 0
1560
1561 const oldOffset = offset
1562 const result = header.decode(buf, offset)
1563 offset += header.decode.bytes
1564
1565 offset = decodeList(result.questions, question, buf, offset)
1566 offset = decodeList(result.answers, answer, buf, offset)
1567 offset = decodeList(result.authorities, answer, buf, offset)
1568 offset = decodeList(result.additionals, answer, buf, offset)
1569
1570 exports.decode.bytes = offset - oldOffset
1571
1572 return result
1573}
1574
1575exports.decode.bytes = 0
1576
1577exports.encodingLength = function (result) {
1578 return header.encodingLength(result) +
1579 encodingLengthList(result.questions || [], question) +
1580 encodingLengthList(result.answers || [], answer) +
1581 encodingLengthList(result.authorities || [], answer) +
1582 encodingLengthList(result.additionals || [], answer)
1583}
1584
1585exports.streamEncode = function (result) {
1586 const buf = exports.encode(result)
1587 const sbuf = Buffer.alloc(2)
1588 sbuf.writeUInt16BE(buf.byteLength)
1589 const combine = Buffer.concat([sbuf, buf])
1590 exports.streamEncode.bytes = combine.byteLength
1591 return combine
1592}
1593
1594exports.streamEncode.bytes = 0
1595
1596exports.streamDecode = function (sbuf) {
1597 const len = sbuf.readUInt16BE(0)
1598 if (sbuf.byteLength < len + 2) {
1599 // not enough data
1600 return null
1601 }
1602 const result = exports.decode(sbuf.slice(2))
1603 exports.streamDecode.bytes = exports.decode.bytes
1604 return result
1605}
1606
1607exports.streamDecode.bytes = 0
1608
1609function encodingLengthList (list, enc) {
1610 let len = 0
1611 for (let i = 0; i < list.length; i++) len += enc.encodingLength(list[i])
1612 return len
1613}
1614
1615function encodeList (list, enc, buf, offset) {
1616 for (let i = 0; i < list.length; i++) {
1617 enc.encode(list[i], buf, offset)
1618 offset += enc.encode.bytes
1619 }
1620 return offset
1621}
1622
1623function decodeList (list, enc, buf, offset) {
1624 for (let i = 0; i < list.length; i++) {
1625 list[i] = enc.decode(buf, offset)
1626 offset += enc.decode.bytes
1627 }
1628 return offset
1629}