forked from mafintosh/dns-packet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
answer.ts
118 lines (86 loc) · 2.92 KB
/
answer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/// import
import { Buffer } from "node:buffer";
/// util
import { FLUSH_MASK, NOT_FLUSH_MASK } from "./utility/constants.ts";
import { Name } from "./name.ts";
import { OPT } from "./records/opt.ts";
import { Record } from "./record.ts";
import * as classes from "./utility/classes.ts";
import * as types from "./utility/types.ts";
/// export
export class Answer {
decodeBytes = 0;
encodeBytes = 0;
decode(buf, offset?) {
if (!offset)
offset = 0;
const a: { [key: string]: unknown; } = {};
const name = new Name();
const oldOffset = offset;
const opt = new OPT();
a.name = name.decode(buf, offset);
offset += name.decodeBytes;
a.type = types.toString(buf.readUInt16BE(offset));
if (a.type === "OPT") {
a.udpPayloadSize = buf.readUInt16BE(offset + 2);
a.extendedRcode = buf.readUInt8(offset + 4);
a.ednsVersion = buf.readUInt8(offset + 5);
a.flags = buf.readUInt16BE(offset + 6);
a.flag_do = ((Number(a.flags) >> 15) & 0x1) === 1;
a.options = opt.decode(buf, offset + 8);
offset += 8 + opt.decodeBytes;
} else {
const klass = buf.readUInt16BE(offset + 2);
a.ttl = buf.readUInt32BE(offset + 4);
a.class = classes.toString(klass & NOT_FLUSH_MASK);
a.flush = !!(klass & FLUSH_MASK);
const enc = Record(a.type);
a.data = enc.decode(buf, offset + 8);
offset += 8 + enc.decodeBytes;
}
this.decodeBytes = offset - oldOffset;
return a;
}
encode(a, buf?, offset?) {
if (!buf)
buf = Buffer.alloc(this.encodingLength(a));
if (!offset)
offset = 0;
const name = new Name();
const oldOffset = offset;
const opt = new OPT();
name.encode(a.name, buf, offset);
offset += name.encodeBytes;
buf.writeUInt16BE(types.toType(a.type), offset);
if (a.type.toUpperCase() === "OPT") {
if (a.name !== ".")
throw new Error("OPT name must be root.");
buf.writeUInt16BE(a.udpPayloadSize || 4096, offset + 2);
buf.writeUInt8(a.extendedRcode || 0, offset + 4);
buf.writeUInt8(a.ednsVersion || 0, offset + 5);
buf.writeUInt16BE(a.flags || 0, offset + 6);
offset += 8;
opt.encode(a.options || [], buf, offset);
offset += opt.encodeBytes;
} else {
let klass = classes.toClass(a.class === undefined ? "IN" : a.class);
if (a.flush)
klass |= FLUSH_MASK; // the 1st bit of the class is the flush bit
buf.writeUInt16BE(klass, offset + 2);
buf.writeUInt32BE(a.ttl || 0, offset + 4);
offset += 8;
const enc = Record(a.type);
enc.encode(a.data, buf, offset);
offset += enc.encodeBytes;
}
this.encodeBytes = offset - oldOffset;
return buf;
}
encodingLength(a) {
const data = (a.data !== null && a.data !== undefined) ?
a.data :
a.options;
const name = new Name();
return name.encodingLength(a.name) + 8 + Record(a.type).encodingLength(data);
}
}