universal-doh 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +22 -0
- package/dist/universal-doh.d.ts +5 -0
- package/dist/universal-doh.js +312 -0
- package/dist/universal-doh.js.map +1 -0
- package/dist/universal-doh.umd.cjs +1 -0
- package/dist/universal-doh.umd.cjs.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Wojciech Malinowski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# universal-doh
|
|
2
|
+
|
|
3
|
+
This project is a work in progress.
|
|
4
|
+
|
|
5
|
+
## Current Status
|
|
6
|
+
|
|
7
|
+
As of now, a very simple implementation of the `resolve()` function is available.
|
|
8
|
+
It currently return a string, and this will definitely change in the (near) future.
|
|
9
|
+
|
|
10
|
+
The resolver uses DoH POST method and handles IDN domains and EDNS0 message padding
|
|
11
|
+
already. Currently it uses Cloudflare DNS server, but this will be configurable
|
|
12
|
+
in the future.
|
|
13
|
+
|
|
14
|
+
## Getting Started
|
|
15
|
+
|
|
16
|
+
To get started with the current state of this project, follow these steps:
|
|
17
|
+
|
|
18
|
+
1. Clone the repository
|
|
19
|
+
2. Install the dependencies using `npm install`
|
|
20
|
+
3. Run the project using `npm dev` to play around with the resolver in your browser
|
|
21
|
+
|
|
22
|
+
It is not available as a package yet, as it is still in a very early stage.
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
function b(t) {
|
|
2
|
+
return t.map((n) => String.fromCharCode(...n)).join(".");
|
|
3
|
+
}
|
|
4
|
+
function M(t) {
|
|
5
|
+
const n = t.split(".").filter((i) => i.length > 0), r = [];
|
|
6
|
+
for (const i of n) {
|
|
7
|
+
if (i.length < 1 || i.length > 63)
|
|
8
|
+
throw new Error(
|
|
9
|
+
`Label "${i}" must be between 1 and 63 characters long`
|
|
10
|
+
);
|
|
11
|
+
if (i.startsWith("-") || i.endsWith("-"))
|
|
12
|
+
throw new Error(`Label "${i}" cannot start or end with a hyphen`);
|
|
13
|
+
const e = [];
|
|
14
|
+
for (const a of i) {
|
|
15
|
+
const c = a.charCodeAt(0);
|
|
16
|
+
if (c >= 48 && c <= 57 || // '0'-'9'
|
|
17
|
+
c >= 97 && c <= 122 || // 'a'-'z'
|
|
18
|
+
c === 45)
|
|
19
|
+
e.push(c);
|
|
20
|
+
else
|
|
21
|
+
throw new Error(`Invalid character '${a}' in label "${i}"`);
|
|
22
|
+
}
|
|
23
|
+
r.push(e);
|
|
24
|
+
}
|
|
25
|
+
return r;
|
|
26
|
+
}
|
|
27
|
+
function z() {
|
|
28
|
+
return {
|
|
29
|
+
id: 0,
|
|
30
|
+
qr: 0,
|
|
31
|
+
opcode: 0,
|
|
32
|
+
aa: 0,
|
|
33
|
+
tc: 0,
|
|
34
|
+
rd: 0,
|
|
35
|
+
ra: 0,
|
|
36
|
+
z: 0,
|
|
37
|
+
rcode: 0,
|
|
38
|
+
qdcount: 0,
|
|
39
|
+
ancount: 0,
|
|
40
|
+
nscount: 0,
|
|
41
|
+
arcount: 0,
|
|
42
|
+
questions: [],
|
|
43
|
+
answers: [],
|
|
44
|
+
authorityRecords: [],
|
|
45
|
+
additionalRecords: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function S(t) {
|
|
49
|
+
const n = z();
|
|
50
|
+
return n.rd = 1, n.qdcount += t.length, n.questions.push(...t), n.arcount += 1, n.additionalRecords.push({
|
|
51
|
+
name: [],
|
|
52
|
+
type: 41,
|
|
53
|
+
class: 65535,
|
|
54
|
+
// max supported payload size
|
|
55
|
+
ttl: 0,
|
|
56
|
+
rdlength: 0,
|
|
57
|
+
rdata: []
|
|
58
|
+
}), n;
|
|
59
|
+
}
|
|
60
|
+
function T(t) {
|
|
61
|
+
const n = new ArrayBuffer(1024), r = new DataView(n);
|
|
62
|
+
let i = 0;
|
|
63
|
+
i = j(r, i, t);
|
|
64
|
+
for (const e of t.questions)
|
|
65
|
+
i = x(r, i, e);
|
|
66
|
+
if (t.answers.length > 0 || t.authorityRecords.length > 0)
|
|
67
|
+
throw new Error("Cannot serialize answers or authority records for query");
|
|
68
|
+
for (const e of t.additionalRecords)
|
|
69
|
+
i = $(r, i, e);
|
|
70
|
+
return i = v(r, i), n.slice(0, i);
|
|
71
|
+
}
|
|
72
|
+
function N(t, n, r) {
|
|
73
|
+
for (const i of r) {
|
|
74
|
+
t.setUint8(n++, i.length);
|
|
75
|
+
for (const e of i)
|
|
76
|
+
t.setUint8(n++, e);
|
|
77
|
+
}
|
|
78
|
+
return t.setUint8(n++, 0), n;
|
|
79
|
+
}
|
|
80
|
+
function $(t, n, r) {
|
|
81
|
+
n = N(t, n, r.name), t.setUint16(n, r.type), n += 2, t.setUint16(n, r.class), n += 2, t.setUint32(n, r.ttl), n += 4, t.setUint16(n, r.rdlength), n += 2;
|
|
82
|
+
for (const i of r.rdata)
|
|
83
|
+
t.setUint8(n++, i);
|
|
84
|
+
return n;
|
|
85
|
+
}
|
|
86
|
+
function v(t, n) {
|
|
87
|
+
const r = n + 4, i = Math.ceil(r / 128) * 128 - r;
|
|
88
|
+
t.setUint16(n, 12), n += 2, t.setUint16(n, i), n += 2;
|
|
89
|
+
for (let e = 0; e < i; e++)
|
|
90
|
+
t.setUint8(n++, Math.floor(Math.random() * 255));
|
|
91
|
+
return n;
|
|
92
|
+
}
|
|
93
|
+
function x(t, n, r) {
|
|
94
|
+
return n = N(t, n, r.qname), t.setUint16(n, r.qtype), n += 2, t.setUint16(n, r.qclass), n += 2, n;
|
|
95
|
+
}
|
|
96
|
+
function j(t, n, r) {
|
|
97
|
+
return t.setUint16(n, r.id), n += 2, t.setUint16(
|
|
98
|
+
n,
|
|
99
|
+
(r.qr & 1) << 15 | (r.opcode & 15) << 11 | (r.aa & 1) << 10 | (r.tc & 1) << 9 | (r.rd & 1) << 8 | (r.ra & 1) << 7 | (r.z & 7) << 4 | r.rcode & 15
|
|
100
|
+
), n += 2, t.setUint16(4, r.qdcount), n += 2, t.setUint16(6, r.ancount), n += 2, t.setUint16(8, r.nscount), n += 2, t.setUint16(10, r.arcount), n += 2, n;
|
|
101
|
+
}
|
|
102
|
+
function k(t, n = 0) {
|
|
103
|
+
const r = new DataView(t), i = z();
|
|
104
|
+
return n = I(r, n, i), n = F(r, n, i.qdcount, i.questions), n = q(
|
|
105
|
+
r,
|
|
106
|
+
n,
|
|
107
|
+
i.ancount,
|
|
108
|
+
i.answers
|
|
109
|
+
), n = q(
|
|
110
|
+
r,
|
|
111
|
+
n,
|
|
112
|
+
i.nscount,
|
|
113
|
+
i.authorityRecords
|
|
114
|
+
), n = q(
|
|
115
|
+
r,
|
|
116
|
+
n,
|
|
117
|
+
i.arcount,
|
|
118
|
+
i.additionalRecords
|
|
119
|
+
), n !== t.byteLength && console.warn(
|
|
120
|
+
`Unexpected end of message (offset: ${n}, length: ${t.byteLength})`
|
|
121
|
+
), i;
|
|
122
|
+
}
|
|
123
|
+
function F(t, n, r, i) {
|
|
124
|
+
for (let e = 0; e < r; e++) {
|
|
125
|
+
const a = [];
|
|
126
|
+
n = E(t, n, a, 0);
|
|
127
|
+
const c = t.getUint16(n);
|
|
128
|
+
n += 2;
|
|
129
|
+
const o = t.getUint16(n);
|
|
130
|
+
n += 2, i.push({ qname: a, qtype: c, qclass: o });
|
|
131
|
+
}
|
|
132
|
+
return n;
|
|
133
|
+
}
|
|
134
|
+
function q(t, n, r, i) {
|
|
135
|
+
for (let e = 0; e < r; e++) {
|
|
136
|
+
const a = [];
|
|
137
|
+
n = E(t, n, a, 0);
|
|
138
|
+
const c = t.getUint16(n);
|
|
139
|
+
n += 2;
|
|
140
|
+
const o = t.getUint16(n);
|
|
141
|
+
n += 2;
|
|
142
|
+
const u = t.getUint32(n);
|
|
143
|
+
n += 4;
|
|
144
|
+
const p = t.getUint16(n);
|
|
145
|
+
n += 2;
|
|
146
|
+
const g = [];
|
|
147
|
+
for (let s = 0; s < p; s++)
|
|
148
|
+
g.push(t.getUint8(n++));
|
|
149
|
+
i.push({ name: a, type: c, class: o, ttl: u, rdlength: p, rdata: g });
|
|
150
|
+
}
|
|
151
|
+
return n;
|
|
152
|
+
}
|
|
153
|
+
function E(t, n, r, i = 0) {
|
|
154
|
+
if (i > 20)
|
|
155
|
+
throw new Error("Too many nested labels");
|
|
156
|
+
let e = t.getUint8(n++);
|
|
157
|
+
for (; e !== 0; ) {
|
|
158
|
+
const a = e >> 6;
|
|
159
|
+
if (a === 0) {
|
|
160
|
+
const c = [];
|
|
161
|
+
for (let o = 0; o < e; o++)
|
|
162
|
+
c.push(t.getUint8(n++));
|
|
163
|
+
r.push(c), e = t.getUint8(n++);
|
|
164
|
+
} else if (a === 3) {
|
|
165
|
+
const c = (e & 63) << 8 | t.getUint8(n++);
|
|
166
|
+
E(t, c, r, i + 1);
|
|
167
|
+
break;
|
|
168
|
+
} else
|
|
169
|
+
throw new Error(`Invalid label type: ${a.toString(2)}`);
|
|
170
|
+
}
|
|
171
|
+
return n;
|
|
172
|
+
}
|
|
173
|
+
function I(t, n, r) {
|
|
174
|
+
r.id = t.getUint16(n), n += 2;
|
|
175
|
+
const i = t.getUint16(n);
|
|
176
|
+
return n += 2, r.qr = (i & 32768) >> 15, r.opcode = (i & 30720) >> 11, r.aa = (i & 1024) >> 10, r.tc = (i & 512) >> 9, r.rd = (i & 256) >> 8, r.ra = (i & 128) >> 7, r.z = (i & 112) >> 4, r.rcode = i & 15, r.qdcount = t.getUint16(n), n += 2, r.ancount = t.getUint16(n), n += 2, r.nscount = t.getUint16(n), n += 2, r.arcount = t.getUint16(n), n += 2, n;
|
|
177
|
+
}
|
|
178
|
+
function P(t) {
|
|
179
|
+
return _(t).split(".").map((e) => O(e) ? e : "xn--" + W(e)).join(".").toLowerCase();
|
|
180
|
+
}
|
|
181
|
+
function _(t) {
|
|
182
|
+
return t.replace(/[.。。]/gu, ".").replace(/ẞ/gu, "ß").normalize("NFKC").toLowerCase().replace(/[\uFE00-\uFE0F]/gu, "");
|
|
183
|
+
}
|
|
184
|
+
function O(t) {
|
|
185
|
+
return Array.from(t).every(D);
|
|
186
|
+
}
|
|
187
|
+
function D(t) {
|
|
188
|
+
return t.charCodeAt(0) < 128;
|
|
189
|
+
}
|
|
190
|
+
const y = 36, w = 1, C = 26, Q = 38, B = 700, H = 72, K = 128;
|
|
191
|
+
function W(t) {
|
|
192
|
+
let n = K, r = 0, i = H;
|
|
193
|
+
const e = [], a = Array.from(t), c = a.filter(D), o = c.length;
|
|
194
|
+
let u = o;
|
|
195
|
+
e.push(...c), o > 0 && e.push("-");
|
|
196
|
+
const p = a.map((s) => s.codePointAt(0)), g = p.length;
|
|
197
|
+
for (; u < g; ) {
|
|
198
|
+
let s = Number.MAX_SAFE_INTEGER;
|
|
199
|
+
for (const h of p)
|
|
200
|
+
h >= n && h < s && (s = h);
|
|
201
|
+
r += (s - n) * (u + 1), n = s;
|
|
202
|
+
for (const h of p)
|
|
203
|
+
if (h < n)
|
|
204
|
+
r++;
|
|
205
|
+
else if (h === n) {
|
|
206
|
+
let U = r, m = y;
|
|
207
|
+
for (; ; ) {
|
|
208
|
+
let l;
|
|
209
|
+
if (m <= i ? l = w : m >= i + C ? l = C : l = m - i, U < l) break;
|
|
210
|
+
const L = l + (U - l) % (y - l);
|
|
211
|
+
e.push(A(L)), U = d(U - l, y - l), m += y;
|
|
212
|
+
}
|
|
213
|
+
e.push(A(U)), i = G(
|
|
214
|
+
r,
|
|
215
|
+
u + 1,
|
|
216
|
+
u === o
|
|
217
|
+
), r = 0, u++;
|
|
218
|
+
}
|
|
219
|
+
r++, n++;
|
|
220
|
+
}
|
|
221
|
+
return e.join("");
|
|
222
|
+
}
|
|
223
|
+
function A(t) {
|
|
224
|
+
return String.fromCharCode(t + 22 + 75 * +(t < 26));
|
|
225
|
+
}
|
|
226
|
+
function d(t, n) {
|
|
227
|
+
return Math.floor(t / n);
|
|
228
|
+
}
|
|
229
|
+
function G(t, n, r) {
|
|
230
|
+
r ? t = d(t, B) : t = d(t, 2), t += d(t, n);
|
|
231
|
+
let i = 0;
|
|
232
|
+
for (; t > d((y - w) * C, 2); )
|
|
233
|
+
t = d(t, y - w), i += 36;
|
|
234
|
+
return i + d(36 * t, t + Q);
|
|
235
|
+
}
|
|
236
|
+
const X = "0.0.1";
|
|
237
|
+
function Y(t, n) {
|
|
238
|
+
const r = P(t), i = S([
|
|
239
|
+
{
|
|
240
|
+
qname: M(r),
|
|
241
|
+
qtype: parseInt(n, 10),
|
|
242
|
+
qclass: 1
|
|
243
|
+
// INTERNET
|
|
244
|
+
}
|
|
245
|
+
]), e = T(i), a = new URL("https://1.1.1.1/dns-query");
|
|
246
|
+
return fetch(a, {
|
|
247
|
+
method: "POST",
|
|
248
|
+
mode: "cors",
|
|
249
|
+
headers: {
|
|
250
|
+
Accept: "application/dns-message",
|
|
251
|
+
"Content-Type": "application/dns-message"
|
|
252
|
+
},
|
|
253
|
+
body: e
|
|
254
|
+
}).then((c) => {
|
|
255
|
+
if (!c.ok)
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Failed to fetch: ${c.status} ${c.statusText}`
|
|
258
|
+
);
|
|
259
|
+
return c.arrayBuffer();
|
|
260
|
+
}).then((c) => {
|
|
261
|
+
const o = k(c);
|
|
262
|
+
return J(o);
|
|
263
|
+
}).catch((c) => {
|
|
264
|
+
throw console.error(c), c;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function J(t) {
|
|
268
|
+
const n = {
|
|
269
|
+
id: t.id,
|
|
270
|
+
authoritativeAnswer: t.aa === 1,
|
|
271
|
+
truncated: t.tc === 1,
|
|
272
|
+
recursionAvailable: t.ra === 1,
|
|
273
|
+
responseCode: t.rcode === 0 ? "OK" : "ERROR",
|
|
274
|
+
questions: t.questions.map((r) => ({
|
|
275
|
+
name: b(r.qname),
|
|
276
|
+
type: r.qtype
|
|
277
|
+
})),
|
|
278
|
+
answers: t.answers.map((r) => ({
|
|
279
|
+
name: b(r.name),
|
|
280
|
+
type: r.type,
|
|
281
|
+
ttl: r.ttl,
|
|
282
|
+
value: R(r.type, r.rdata)
|
|
283
|
+
})),
|
|
284
|
+
authorityRecords: t.authorityRecords.map((r) => ({
|
|
285
|
+
name: b(r.name),
|
|
286
|
+
type: r.type,
|
|
287
|
+
ttl: r.ttl,
|
|
288
|
+
value: R(r.type, r.rdata)
|
|
289
|
+
})),
|
|
290
|
+
additionalRecords: t.additionalRecords.map((r) => ({
|
|
291
|
+
name: b(r.name),
|
|
292
|
+
type: r.type,
|
|
293
|
+
ttl: r.ttl,
|
|
294
|
+
value: R(r.type, r.rdata)
|
|
295
|
+
}))
|
|
296
|
+
};
|
|
297
|
+
return JSON.stringify(n, null, 2);
|
|
298
|
+
}
|
|
299
|
+
function R(t, n) {
|
|
300
|
+
switch (t) {
|
|
301
|
+
case 1:
|
|
302
|
+
return n.join(".");
|
|
303
|
+
case 28:
|
|
304
|
+
return n.map((r) => r.toString(16)).join(":");
|
|
305
|
+
default:
|
|
306
|
+
return n;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
export {
|
|
310
|
+
Y as resolve,
|
|
311
|
+
X as version
|
|
312
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal-doh.js","sources":["../lib/dns-message.ts","../lib/punycode.ts","../lib/index.ts"],"sourcesContent":["type RawDnsMessage = ArrayBuffer;\n\ninterface DnsMessage {\n id: number;\n // query (0), response (1)\n qr: BinaryFlag;\n /*\n 0 a standard query (QUERY)\n 1 an inverse query (IQUERY)\n 2 a server status request (STATUS)\n 3-15 reserved for future use\n */\n opcode: FourBitNumber;\n // Authoritative Answer\n aa: BinaryFlag;\n // TrunCation\n tc: BinaryFlag;\n // Recursion Desired\n rd: BinaryFlag;\n // Recursion Available\n ra: BinaryFlag;\n // reserved for future use - must be 0\n z: ThreeBitNumber;\n /*\n Response code\n 0 No error condition\n 1 Format error\n 2 Server failure\n 3 Name Error\n 4 Not Implemented\n 5 Refused\n 6-15 Reserved for future use.\n */\n rcode: FourBitNumber;\n // number of entries in the question section (0-65535)\n qdcount: number;\n // number of resource records in the answer section (0-65535)\n ancount: number;\n // number of name server resource records in the authority records section (0-65535)\n nscount: number;\n // number of resource records in the additional records section (0-65535)\n arcount: number;\n\n questions: DnsQuestion[];\n answers: DnsResourceRecord[];\n authorityRecords: DnsResourceRecord[];\n additionalRecords: DnsResourceRecord[];\n}\n\ntype Bytes = number[];\ntype Label = Bytes;\ntype DNSName = Label[];\n\ninterface DnsQuestion {\n qname: DNSName;\n // 16 bit unsigned integer\n qtype: number;\n // 16 bit unsigned integer\n qclass: number;\n}\n\ninterface DnsResourceRecord {\n name: DNSName;\n // 16 bit unsigned integer\n type: number;\n // 16 bit unsigned integer\n class: number;\n // 32 bit unsigned integer\n ttl: number;\n // 16 bit unsigned integer\n rdlength: number;\n rdata: Bytes;\n}\n\ntype BinaryFlag = 0 | 1;\ntype ThreeBitNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;\ntype FourBitNumber =\n | 0\n | 1\n | 2\n | 3\n | 4\n | 5\n | 6\n | 7\n | 8\n | 9\n | 10\n | 11\n | 12\n | 13\n | 14\n | 15;\n\nexport function dnsNameToString(name: DNSName): string {\n return name.map((label) => String.fromCharCode(...label)).join(\".\");\n}\n\nexport function stringToDNSName(name: string): DNSName {\n // we can assume string is ascii but it may not be a valid domain name\n const labels = name.split(\".\").filter((label) => label.length > 0);\n const dnsName: DNSName = [];\n for (const label of labels) {\n if (label.length < 1 || label.length > 63) {\n throw new Error(\n `Label \"${label}\" must be between 1 and 63 characters long`,\n );\n }\n\n if (label.startsWith(\"-\") || label.endsWith(\"-\")) {\n throw new Error(`Label \"${label}\" cannot start or end with a hyphen`);\n }\n\n const bytes: Bytes = [];\n\n for (const char of label) {\n const code = char.charCodeAt(0);\n if (\n (code >= 48 && code <= 57) || // '0'-'9'\n (code >= 97 && code <= 122) || // 'a'-'z'\n code === 45 // '-'\n ) {\n bytes.push(code);\n } else {\n throw new Error(`Invalid character '${char}' in label \"${label}\"`);\n }\n }\n dnsName.push(bytes);\n }\n return dnsName;\n}\n\nfunction createDnsMessage() {\n return {\n id: 0,\n qr: 0,\n opcode: 0,\n aa: 0,\n tc: 0,\n rd: 0,\n ra: 0,\n z: 0,\n rcode: 0,\n qdcount: 0,\n ancount: 0,\n nscount: 0,\n arcount: 0,\n questions: [],\n answers: [],\n authorityRecords: [],\n additionalRecords: [],\n } as DnsMessage;\n}\n\nexport function createDnsQuery(questions: DnsQuestion[]): DnsMessage {\n const message = createDnsMessage();\n message.rd = 1;\n message.qdcount += questions.length;\n message.questions.push(...questions);\n\n // notify the server that we support EDNS0 by adding an OPT record\n message.arcount += 1;\n message.additionalRecords.push({\n name: [],\n type: 41,\n class: 0xffff, // max supported payload size\n ttl: 0,\n rdlength: 0,\n rdata: [],\n });\n\n return message;\n}\n\nexport function serializeDnsQuery(query: DnsMessage): RawDnsMessage {\n const buffer = new ArrayBuffer(1024);\n const message = new DataView(buffer);\n\n let offset = 0;\n offset = serializeHeader(message, offset, query);\n\n for (const question of query.questions) {\n offset = serializeQuestion(message, offset, question);\n }\n\n // we ignore the answers and authority records for queries,\n // but we include the additional records for EDNS0 support\n if (query.answers.length > 0 || query.authorityRecords.length > 0) {\n throw new Error(\"Cannot serialize answers or authority records for query\");\n }\n\n for (const record of query.additionalRecords) {\n offset = serializeResourceRecord(message, offset, record);\n }\n\n // add padding to the message for privacy\n offset = serializeEDNS0Padding(message, offset);\n\n return buffer.slice(0, offset);\n}\n\nfunction serializeName(message: DataView, offset: number, name: DNSName) {\n // TODO: consider implementing compression\n for (const label of name) {\n message.setUint8(offset++, label.length);\n for (const byte of label) {\n message.setUint8(offset++, byte);\n }\n }\n\n // empty label to terminate the domain name\n message.setUint8(offset++, 0);\n\n return offset;\n}\n\nfunction serializeResourceRecord(\n message: DataView,\n offset: number,\n record: DnsResourceRecord,\n) {\n offset = serializeName(message, offset, record.name);\n message.setUint16(offset, record.type);\n offset += 2;\n message.setUint16(offset, record.class);\n offset += 2;\n message.setUint32(offset, record.ttl);\n offset += 4;\n message.setUint16(offset, record.rdlength);\n offset += 2;\n for (const byte of record.rdata) {\n message.setUint8(offset++, byte);\n }\n\n return offset;\n}\n\nfunction serializeEDNS0Padding(message: DataView, offset: number) {\n // RFC 8467 - Recommended Strategy: Block-Length Padding\n\n // padding header of 4 bytes must be included\n const length = offset + 4;\n const padding = Math.ceil(length / 128) * 128 - length;\n\n // RFC 7830\n message.setUint16(offset, 12); // OPTION-CODE for EDNS0 padding\n offset += 2;\n message.setUint16(offset, padding); // OPTION-CODE for EDNS0 padding\n offset += 2;\n for (let i = 0; i < padding; i++) {\n // we do not need to generate cryptographically secure random numbers\n // simple random numbers are enough to obfuscate the message\n message.setUint8(offset++, Math.floor(Math.random() * 0xff));\n }\n\n return offset;\n}\n\nfunction serializeQuestion(\n message: DataView,\n offset: number,\n question: DnsQuestion,\n) {\n offset = serializeName(message, offset, question.qname);\n\n message.setUint16(offset, question.qtype);\n offset += 2;\n message.setUint16(offset, question.qclass);\n offset += 2;\n\n return offset;\n}\n\nfunction serializeHeader(\n message: DataView,\n offset: number,\n header: DnsMessage,\n) {\n // message id\n message.setUint16(offset, header.id);\n offset += 2;\n\n // flags\n message.setUint16(\n offset,\n ((header.qr & 0b1) << 15) |\n ((header.opcode & 0b1111) << 11) |\n ((header.aa & 0b1) << 10) |\n ((header.tc & 0b1) << 9) |\n ((header.rd & 0b1) << 8) |\n ((header.ra & 0b1) << 7) |\n ((header.z & 0b111) << 4) |\n (header.rcode & 0b1111),\n );\n offset += 2;\n\n // question records count\n message.setUint16(4, header.qdcount);\n offset += 2;\n\n // answer records count\n message.setUint16(6, header.ancount);\n offset += 2;\n\n // authority records count\n message.setUint16(8, header.nscount);\n offset += 2;\n\n // additional records count\n message.setUint16(10, header.arcount);\n offset += 2;\n\n return offset;\n}\n\nexport function parseDnsMessage(\n raw: RawDnsMessage,\n offset: number = 0,\n): DnsMessage {\n const rawView = new DataView(raw);\n const message = createDnsMessage();\n\n offset = parseHeader(rawView, offset, message);\n\n offset = parseQuestion(rawView, offset, message.qdcount, message.questions);\n\n offset = parseResourceRecords(\n rawView,\n offset,\n message.ancount,\n message.answers,\n );\n offset = parseResourceRecords(\n rawView,\n offset,\n message.nscount,\n message.authorityRecords,\n );\n offset = parseResourceRecords(\n rawView,\n offset,\n message.arcount,\n message.additionalRecords,\n );\n\n if (offset !== raw.byteLength) {\n // TODO: implement support for parsing padding and replace the warning with error\n console.warn(\n `Unexpected end of message (offset: ${offset}, length: ${raw.byteLength})`,\n );\n }\n\n return message;\n}\n\nfunction parseQuestion(\n rawView: DataView,\n offset: number,\n number: number,\n records: DnsQuestion[],\n) {\n for (let i = 0; i < number; i++) {\n const qname: DNSName = [];\n offset = parseName(rawView, offset, qname, 0);\n\n const qtype = rawView.getUint16(offset);\n offset += 2;\n const qclass = rawView.getUint16(offset);\n offset += 2;\n\n records.push({ qname, qtype, qclass });\n }\n return offset;\n}\n\nfunction parseResourceRecords(\n rawView: DataView,\n offset: number,\n number: number,\n records: DnsResourceRecord[],\n) {\n for (let i = 0; i < number; i++) {\n const name: DNSName = [];\n offset = parseName(rawView, offset, name, 0);\n\n const type = rawView.getUint16(offset);\n offset += 2;\n const class_ = rawView.getUint16(offset);\n offset += 2;\n const ttl = rawView.getUint32(offset);\n offset += 4;\n const rdlength = rawView.getUint16(offset);\n offset += 2;\n const rdata = [];\n for (let j = 0; j < rdlength; j++) {\n rdata.push(rawView.getUint8(offset++));\n }\n\n records.push({ name, type, class: class_, ttl, rdlength, rdata });\n }\n\n return offset;\n}\n\nfunction parseName(\n view: DataView,\n offset: number,\n output: DNSName,\n recursionDepth = 0,\n) {\n if (recursionDepth > 20) {\n throw new Error(\"Too many nested labels\");\n }\n\n let length = view.getUint8(offset++);\n while (length !== 0) {\n const labelType = length >> 6;\n if (labelType === 0b00) {\n // standard label\n const label = [];\n for (let i = 0; i < length; i++) {\n label.push(view.getUint8(offset++));\n }\n output.push(label);\n length = view.getUint8(offset++);\n } else if (labelType === 0b11) {\n // compressed label\n const pointer = ((length & 0b00111111) << 8) | view.getUint8(offset++);\n // ignore the offset as we returning from a \"jump\"\n parseName(view, pointer, output, recursionDepth + 1);\n break;\n } else {\n // we do not (yet) support extended label types (RFC2671)\n throw new Error(`Invalid label type: ${labelType.toString(2)}`);\n }\n }\n return offset;\n}\n\nfunction parseHeader(raw: DataView, offset: number, output: DnsMessage) {\n output.id = raw.getUint16(offset);\n offset += 2;\n\n const flags = raw.getUint16(offset);\n offset += 2;\n\n output.qr = ((flags & 0b1000000000000000) >> 15) as BinaryFlag;\n output.opcode = ((flags & 0b0111100000000000) >> 11) as FourBitNumber;\n output.aa = ((flags & 0b0000010000000000) >> 10) as BinaryFlag;\n output.tc = ((flags & 0b0000001000000000) >> 9) as BinaryFlag;\n output.rd = ((flags & 0b0000000100000000) >> 8) as BinaryFlag;\n output.ra = ((flags & 0b0000000010000000) >> 7) as BinaryFlag;\n output.z = ((flags & 0b0000000001110000) >> 4) as ThreeBitNumber;\n output.rcode = (flags & 0b0000000000001111) as FourBitNumber;\n\n output.qdcount = raw.getUint16(offset);\n offset += 2;\n\n output.ancount = raw.getUint16(offset);\n offset += 2;\n\n output.nscount = raw.getUint16(offset);\n offset += 2;\n\n output.arcount = raw.getUint16(offset);\n offset += 2;\n\n return offset;\n}\n","export function domainToAscii(domain: string) {\n const preprocessed = preprocessDomain(domain);\n const labels = preprocessed.split(\".\");\n\n const asciiLabels = labels.map((label) => {\n if (stringIsAscii(label)) {\n return label;\n } else {\n return \"xn--\" + punycodeEncode(label);\n }\n });\n\n return asciiLabels.join(\".\").toLowerCase();\n}\n\nfunction preprocessDomain(domain: string) {\n // https://unicode.org/reports/tr46/#TableDerivationStep1\n const exceptionalMapped = domain\n .replace(/[.。。]/gu, \".\")\n .replace(/ẞ/gu, \"ß\");\n\n // we normalize the input to Unicode Normalization Form KC\n const normalized = exceptionalMapped.normalize(\"NFKC\");\n\n // TODO: we deviate from the spec here to simplify the implementation\n // this may need to be revisited in the future\n\n // we should perform case folding here (NFKC_Casefold)\n // but we simplify this step to just lowercase the input instead\n const lowercased = normalized.toLowerCase();\n\n // remove all code points in the range U+FE00 to U+FE0F\n // (Unicode variation selectors) from the input\n // as they break emoji domains handling\n const filtered = lowercased.replace(/[\\uFE00-\\uFE0F]/gu, \"\");\n\n return filtered;\n}\n\nfunction stringIsAscii(str: string): boolean {\n return Array.from(str).every(charIsAscii);\n}\n\nfunction charIsAscii(char: string): boolean {\n return char.charCodeAt(0) < 128;\n}\n\nconst base = 36;\nconst tmin = 1;\nconst tmax = 26;\nconst skew = 38;\nconst damp = 700;\nconst initial_bias = 72;\nconst initial_n = 0x80;\n\nexport function punycodeEncode(str: string) {\n let n = initial_n;\n let delta = 0;\n let bias = initial_bias;\n const output: string[] = [];\n\n const inputChars = Array.from(str);\n\n // copy ascii chars to output\n const asciiChars = inputChars.filter(charIsAscii);\n const basicCodePoints = asciiChars.length;\n let handledCodePoints = basicCodePoints;\n output.push(...asciiChars);\n\n // append delimiter if we consumed any ascii chars\n if (basicCodePoints > 0) {\n output.push(\"-\");\n }\n\n const inputCodePoints = inputChars.map((char) => char.codePointAt(0)!);\n const inputLength = inputCodePoints.length;\n\n while (handledCodePoints < inputLength) {\n // Find the minimum code point >= n\n let m = Number.MAX_SAFE_INTEGER;\n for (const c of inputCodePoints) {\n if (c >= n && c < m) {\n m = c;\n }\n }\n\n delta += (m - n) * (handledCodePoints + 1);\n n = m;\n\n for (const c of inputCodePoints) {\n if (c < n) {\n delta++;\n } else if (c === n) {\n let q = delta;\n let k = base;\n\n while (true) {\n let t: number;\n if (k <= bias) {\n t = tmin;\n } else if (k >= bias + tmax) {\n t = tmax;\n } else {\n t = k - bias;\n }\n if (q < t) break;\n const code = t + ((q - t) % (base - t));\n output.push(encodeDigit(code));\n q = div(q - t, base - t);\n k += base;\n }\n\n output.push(encodeDigit(q));\n bias = adaptBias(\n delta,\n handledCodePoints + 1,\n handledCodePoints === basicCodePoints,\n );\n delta = 0;\n handledCodePoints++;\n }\n }\n\n delta++;\n n++;\n }\n\n return output.join(\"\");\n}\n\nfunction encodeDigit(d: number): string {\n return String.fromCharCode(d + 22 + 75 * Number(d < 26));\n}\n\nfunction div(n: number, d: number) {\n return Math.floor(n / d);\n}\n\nfunction adaptBias(delta: number, numPoints: number, firstTime: boolean) {\n if (firstTime) {\n delta = div(delta, damp);\n } else {\n delta = div(delta, 2);\n }\n\n delta += div(delta, numPoints);\n\n let k = 0;\n while (delta > div((base - tmin) * tmax, 2)) {\n delta = div(delta, base - tmin);\n\n k += 36;\n }\n\n return k + div((36 - 1 + 1) * delta, delta + skew);\n}\n","export const version = __LIB_VERSION__;\nimport {\n serializeDnsQuery,\n createDnsQuery,\n parseDnsMessage,\n stringToDNSName,\n dnsNameToString,\n} from \"./dns-message\";\nimport { domainToAscii } from \"./punycode\";\n\nexport function resolve(name: string, type: string) {\n const qualifiedName = domainToAscii(name);\n\n const query = createDnsQuery([\n {\n qname: stringToDNSName(qualifiedName),\n qtype: parseInt(type, 10),\n qclass: 1, // INTERNET\n },\n ]);\n\n const buffer = serializeDnsQuery(query);\n\n const url = new URL(\"https://1.1.1.1/dns-query\");\n return fetch(url, {\n method: \"POST\",\n mode: \"cors\",\n headers: {\n Accept: \"application/dns-message\",\n \"Content-Type\": \"application/dns-message\",\n },\n body: buffer,\n })\n .then((response) => {\n if (!response.ok) {\n throw new Error(\n `Failed to fetch: ${response.status} ${response.statusText}`,\n );\n }\n return response.arrayBuffer();\n })\n .then((buffer) => {\n const message = parseDnsMessage(buffer);\n return formatDnsMessage(message);\n })\n .catch((error) => {\n console.error(error);\n throw error;\n });\n}\n\nfunction formatDnsMessage(message: ReturnType<typeof parseDnsMessage>) {\n const formatted = {\n id: message.id,\n authoritativeAnswer: message.aa === 1,\n truncated: message.tc === 1,\n recursionAvailable: message.ra === 1,\n responseCode: message.rcode === 0 ? \"OK\" : \"ERROR\",\n questions: message.questions.map((question) => ({\n name: dnsNameToString(question.qname),\n type: question.qtype,\n })),\n answers: message.answers.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n authorityRecords: message.authorityRecords.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n additionalRecords: message.additionalRecords.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n };\n return JSON.stringify(formatted, null, 2);\n}\n\nfunction formatRData(recordType: number, rdata: number[]) {\n // TODO: this has to be implemented in the parser as the data\n // may include dns names and labels like for CNAMEs\n // or TXT (where there are labels but merged into a single string)\n switch (recordType) {\n case 1:\n return rdata.join(\".\");\n case 28:\n return rdata.map((c) => c.toString(16)).join(\":\");\n default:\n return rdata;\n }\n}\n"],"names":["dnsNameToString","name","label","stringToDNSName","labels","dnsName","bytes","char","code","createDnsMessage","createDnsQuery","questions","message","serializeDnsQuery","query","buffer","offset","serializeHeader","question","serializeQuestion","record","serializeResourceRecord","serializeEDNS0Padding","serializeName","byte","length","padding","i","header","parseDnsMessage","raw","rawView","parseHeader","parseQuestion","parseResourceRecords","number","records","qname","parseName","qtype","qclass","type","class_","ttl","rdlength","rdata","j","view","output","recursionDepth","labelType","pointer","flags","domainToAscii","domain","preprocessDomain","stringIsAscii","punycodeEncode","str","charIsAscii","base","tmin","tmax","skew","damp","initial_bias","initial_n","delta","bias","inputChars","asciiChars","basicCodePoints","handledCodePoints","inputCodePoints","inputLength","m","c","q","k","t","encodeDigit","div","adaptBias","d","n","numPoints","firstTime","version","resolve","qualifiedName","url","response","formatDnsMessage","error","formatted","formatRData","recordType"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(d,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(d=typeof globalThis<"u"?globalThis:d||self,u(d["universal-doh"]={}))})(this,function(d){"use strict";function u(t){return t.map(n=>String.fromCharCode(...n)).join(".")}function v(t){const n=t.split(".").filter(i=>i.length>0),e=[];for(const i of n){if(i.length<1||i.length>63)throw new Error(`Label "${i}" must be between 1 and 63 characters long`);if(i.startsWith("-")||i.endsWith("-"))throw new Error(`Label "${i}" cannot start or end with a hyphen`);const r=[];for(const o of i){const c=o.charCodeAt(0);if(c>=48&&c<=57||c>=97&&c<=122||c===45)r.push(c);else throw new Error(`Invalid character '${o}' in label "${i}"`)}e.push(r)}return e}function z(){return{id:0,qr:0,opcode:0,aa:0,tc:0,rd:0,ra:0,z:0,rcode:0,qdcount:0,ancount:0,nscount:0,arcount:0,questions:[],answers:[],authorityRecords:[],additionalRecords:[]}}function D(t){const n=z();return n.rd=1,n.qdcount+=t.length,n.questions.push(...t),n.arcount+=1,n.additionalRecords.push({name:[],type:41,class:65535,ttl:0,rdlength:0,rdata:[]}),n}function M(t){const n=new ArrayBuffer(1024),e=new DataView(n);let i=0;i=x(e,i,t);for(const r of t.questions)i=j(e,i,r);if(t.answers.length>0||t.authorityRecords.length>0)throw new Error("Cannot serialize answers or authority records for query");for(const r of t.additionalRecords)i=L(e,i,r);return i=$(e,i),n.slice(0,i)}function N(t,n,e){for(const i of e){t.setUint8(n++,i.length);for(const r of i)t.setUint8(n++,r)}return t.setUint8(n++,0),n}function L(t,n,e){n=N(t,n,e.name),t.setUint16(n,e.type),n+=2,t.setUint16(n,e.class),n+=2,t.setUint32(n,e.ttl),n+=4,t.setUint16(n,e.rdlength),n+=2;for(const i of e.rdata)t.setUint8(n++,i);return n}function $(t,n){const e=n+4,i=Math.ceil(e/128)*128-e;t.setUint16(n,12),n+=2,t.setUint16(n,i),n+=2;for(let r=0;r<i;r++)t.setUint8(n++,Math.floor(Math.random()*255));return n}function j(t,n,e){return n=N(t,n,e.qname),t.setUint16(n,e.qtype),n+=2,t.setUint16(n,e.qclass),n+=2,n}function x(t,n,e){return t.setUint16(n,e.id),n+=2,t.setUint16(n,(e.qr&1)<<15|(e.opcode&15)<<11|(e.aa&1)<<10|(e.tc&1)<<9|(e.rd&1)<<8|(e.ra&1)<<7|(e.z&7)<<4|e.rcode&15),n+=2,t.setUint16(4,e.qdcount),n+=2,t.setUint16(6,e.ancount),n+=2,t.setUint16(8,e.nscount),n+=2,t.setUint16(10,e.arcount),n+=2,n}function P(t,n=0){const e=new DataView(t),i=z();return n=F(e,n,i),n=k(e,n,i.qdcount,i.questions),n=R(e,n,i.ancount,i.answers),n=R(e,n,i.nscount,i.authorityRecords),n=R(e,n,i.arcount,i.additionalRecords),n!==t.byteLength&&console.warn(`Unexpected end of message (offset: ${n}, length: ${t.byteLength})`),i}function k(t,n,e,i){for(let r=0;r<e;r++){const o=[];n=w(t,n,o,0);const c=t.getUint16(n);n+=2;const a=t.getUint16(n);n+=2,i.push({qname:o,qtype:c,qclass:a})}return n}function R(t,n,e,i){for(let r=0;r<e;r++){const o=[];n=w(t,n,o,0);const c=t.getUint16(n);n+=2;const a=t.getUint16(n);n+=2;const h=t.getUint32(n);n+=4;const g=t.getUint16(n);n+=2;const b=[];for(let s=0;s<g;s++)b.push(t.getUint8(n++));i.push({name:o,type:c,class:a,ttl:h,rdlength:g,rdata:b})}return n}function w(t,n,e,i=0){if(i>20)throw new Error("Too many nested labels");let r=t.getUint8(n++);for(;r!==0;){const o=r>>6;if(o===0){const c=[];for(let a=0;a<r;a++)c.push(t.getUint8(n++));e.push(c),r=t.getUint8(n++)}else if(o===3){const c=(r&63)<<8|t.getUint8(n++);w(t,c,e,i+1);break}else throw new Error(`Invalid label type: ${o.toString(2)}`)}return n}function F(t,n,e){e.id=t.getUint16(n),n+=2;const i=t.getUint16(n);return n+=2,e.qr=(i&32768)>>15,e.opcode=(i&30720)>>11,e.aa=(i&1024)>>10,e.tc=(i&512)>>9,e.rd=(i&256)>>8,e.ra=(i&128)>>7,e.z=(i&112)>>4,e.rcode=i&15,e.qdcount=t.getUint16(n),n+=2,e.ancount=t.getUint16(n),n+=2,e.nscount=t.getUint16(n),n+=2,e.arcount=t.getUint16(n),n+=2,n}function I(t){return O(t).split(".").map(r=>_(r)?r:"xn--"+W(r)).join(".").toLowerCase()}function O(t){return t.replace(/[.。。]/gu,".").replace(/ẞ/gu,"ß").normalize("NFKC").toLowerCase().replace(/[\uFE00-\uFE0F]/gu,"")}function _(t){return Array.from(t).every(S)}function S(t){return t.charCodeAt(0)<128}const y=36,C=1,E=26,Q=38,B=700,H=72,K=128;function W(t){let n=K,e=0,i=H;const r=[],o=Array.from(t),c=o.filter(S),a=c.length;let h=a;r.push(...c),a>0&&r.push("-");const g=o.map(s=>s.codePointAt(0)),b=g.length;for(;h<b;){let s=Number.MAX_SAFE_INTEGER;for(const U of g)U>=n&&U<s&&(s=U);e+=(s-n)*(h+1),n=s;for(const U of g)if(U<n)e++;else if(U===n){let m=e,q=y;for(;;){let l;if(q<=i?l=C:q>=i+E?l=E:l=q-i,m<l)break;const Z=l+(m-l)%(y-l);r.push(T(Z)),m=p(m-l,y-l),q+=y}r.push(T(m)),i=G(e,h+1,h===a),e=0,h++}e++,n++}return r.join("")}function T(t){return String.fromCharCode(t+22+75*+(t<26))}function p(t,n){return Math.floor(t/n)}function G(t,n,e){e?t=p(t,B):t=p(t,2),t+=p(t,n);let i=0;for(;t>p((y-C)*E,2);)t=p(t,y-C),i+=36;return i+p(36*t,t+Q)}const J="0.0.1";function X(t,n){const e=I(t),i=D([{qname:v(e),qtype:parseInt(n,10),qclass:1}]),r=M(i),o=new URL("https://1.1.1.1/dns-query");return fetch(o,{method:"POST",mode:"cors",headers:{Accept:"application/dns-message","Content-Type":"application/dns-message"},body:r}).then(c=>{if(!c.ok)throw new Error(`Failed to fetch: ${c.status} ${c.statusText}`);return c.arrayBuffer()}).then(c=>{const a=P(c);return Y(a)}).catch(c=>{throw console.error(c),c})}function Y(t){const n={id:t.id,authoritativeAnswer:t.aa===1,truncated:t.tc===1,recursionAvailable:t.ra===1,responseCode:t.rcode===0?"OK":"ERROR",questions:t.questions.map(e=>({name:u(e.qname),type:e.qtype})),answers:t.answers.map(e=>({name:u(e.name),type:e.type,ttl:e.ttl,value:A(e.type,e.rdata)})),authorityRecords:t.authorityRecords.map(e=>({name:u(e.name),type:e.type,ttl:e.ttl,value:A(e.type,e.rdata)})),additionalRecords:t.additionalRecords.map(e=>({name:u(e.name),type:e.type,ttl:e.ttl,value:A(e.type,e.rdata)}))};return JSON.stringify(n,null,2)}function A(t,n){switch(t){case 1:return n.join(".");case 28:return n.map(e=>e.toString(16)).join(":");default:return n}}d.resolve=X,d.version=J,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal-doh.umd.cjs","sources":["../lib/dns-message.ts","../lib/punycode.ts","../lib/index.ts"],"sourcesContent":["type RawDnsMessage = ArrayBuffer;\n\ninterface DnsMessage {\n id: number;\n // query (0), response (1)\n qr: BinaryFlag;\n /*\n 0 a standard query (QUERY)\n 1 an inverse query (IQUERY)\n 2 a server status request (STATUS)\n 3-15 reserved for future use\n */\n opcode: FourBitNumber;\n // Authoritative Answer\n aa: BinaryFlag;\n // TrunCation\n tc: BinaryFlag;\n // Recursion Desired\n rd: BinaryFlag;\n // Recursion Available\n ra: BinaryFlag;\n // reserved for future use - must be 0\n z: ThreeBitNumber;\n /*\n Response code\n 0 No error condition\n 1 Format error\n 2 Server failure\n 3 Name Error\n 4 Not Implemented\n 5 Refused\n 6-15 Reserved for future use.\n */\n rcode: FourBitNumber;\n // number of entries in the question section (0-65535)\n qdcount: number;\n // number of resource records in the answer section (0-65535)\n ancount: number;\n // number of name server resource records in the authority records section (0-65535)\n nscount: number;\n // number of resource records in the additional records section (0-65535)\n arcount: number;\n\n questions: DnsQuestion[];\n answers: DnsResourceRecord[];\n authorityRecords: DnsResourceRecord[];\n additionalRecords: DnsResourceRecord[];\n}\n\ntype Bytes = number[];\ntype Label = Bytes;\ntype DNSName = Label[];\n\ninterface DnsQuestion {\n qname: DNSName;\n // 16 bit unsigned integer\n qtype: number;\n // 16 bit unsigned integer\n qclass: number;\n}\n\ninterface DnsResourceRecord {\n name: DNSName;\n // 16 bit unsigned integer\n type: number;\n // 16 bit unsigned integer\n class: number;\n // 32 bit unsigned integer\n ttl: number;\n // 16 bit unsigned integer\n rdlength: number;\n rdata: Bytes;\n}\n\ntype BinaryFlag = 0 | 1;\ntype ThreeBitNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;\ntype FourBitNumber =\n | 0\n | 1\n | 2\n | 3\n | 4\n | 5\n | 6\n | 7\n | 8\n | 9\n | 10\n | 11\n | 12\n | 13\n | 14\n | 15;\n\nexport function dnsNameToString(name: DNSName): string {\n return name.map((label) => String.fromCharCode(...label)).join(\".\");\n}\n\nexport function stringToDNSName(name: string): DNSName {\n // we can assume string is ascii but it may not be a valid domain name\n const labels = name.split(\".\").filter((label) => label.length > 0);\n const dnsName: DNSName = [];\n for (const label of labels) {\n if (label.length < 1 || label.length > 63) {\n throw new Error(\n `Label \"${label}\" must be between 1 and 63 characters long`,\n );\n }\n\n if (label.startsWith(\"-\") || label.endsWith(\"-\")) {\n throw new Error(`Label \"${label}\" cannot start or end with a hyphen`);\n }\n\n const bytes: Bytes = [];\n\n for (const char of label) {\n const code = char.charCodeAt(0);\n if (\n (code >= 48 && code <= 57) || // '0'-'9'\n (code >= 97 && code <= 122) || // 'a'-'z'\n code === 45 // '-'\n ) {\n bytes.push(code);\n } else {\n throw new Error(`Invalid character '${char}' in label \"${label}\"`);\n }\n }\n dnsName.push(bytes);\n }\n return dnsName;\n}\n\nfunction createDnsMessage() {\n return {\n id: 0,\n qr: 0,\n opcode: 0,\n aa: 0,\n tc: 0,\n rd: 0,\n ra: 0,\n z: 0,\n rcode: 0,\n qdcount: 0,\n ancount: 0,\n nscount: 0,\n arcount: 0,\n questions: [],\n answers: [],\n authorityRecords: [],\n additionalRecords: [],\n } as DnsMessage;\n}\n\nexport function createDnsQuery(questions: DnsQuestion[]): DnsMessage {\n const message = createDnsMessage();\n message.rd = 1;\n message.qdcount += questions.length;\n message.questions.push(...questions);\n\n // notify the server that we support EDNS0 by adding an OPT record\n message.arcount += 1;\n message.additionalRecords.push({\n name: [],\n type: 41,\n class: 0xffff, // max supported payload size\n ttl: 0,\n rdlength: 0,\n rdata: [],\n });\n\n return message;\n}\n\nexport function serializeDnsQuery(query: DnsMessage): RawDnsMessage {\n const buffer = new ArrayBuffer(1024);\n const message = new DataView(buffer);\n\n let offset = 0;\n offset = serializeHeader(message, offset, query);\n\n for (const question of query.questions) {\n offset = serializeQuestion(message, offset, question);\n }\n\n // we ignore the answers and authority records for queries,\n // but we include the additional records for EDNS0 support\n if (query.answers.length > 0 || query.authorityRecords.length > 0) {\n throw new Error(\"Cannot serialize answers or authority records for query\");\n }\n\n for (const record of query.additionalRecords) {\n offset = serializeResourceRecord(message, offset, record);\n }\n\n // add padding to the message for privacy\n offset = serializeEDNS0Padding(message, offset);\n\n return buffer.slice(0, offset);\n}\n\nfunction serializeName(message: DataView, offset: number, name: DNSName) {\n // TODO: consider implementing compression\n for (const label of name) {\n message.setUint8(offset++, label.length);\n for (const byte of label) {\n message.setUint8(offset++, byte);\n }\n }\n\n // empty label to terminate the domain name\n message.setUint8(offset++, 0);\n\n return offset;\n}\n\nfunction serializeResourceRecord(\n message: DataView,\n offset: number,\n record: DnsResourceRecord,\n) {\n offset = serializeName(message, offset, record.name);\n message.setUint16(offset, record.type);\n offset += 2;\n message.setUint16(offset, record.class);\n offset += 2;\n message.setUint32(offset, record.ttl);\n offset += 4;\n message.setUint16(offset, record.rdlength);\n offset += 2;\n for (const byte of record.rdata) {\n message.setUint8(offset++, byte);\n }\n\n return offset;\n}\n\nfunction serializeEDNS0Padding(message: DataView, offset: number) {\n // RFC 8467 - Recommended Strategy: Block-Length Padding\n\n // padding header of 4 bytes must be included\n const length = offset + 4;\n const padding = Math.ceil(length / 128) * 128 - length;\n\n // RFC 7830\n message.setUint16(offset, 12); // OPTION-CODE for EDNS0 padding\n offset += 2;\n message.setUint16(offset, padding); // OPTION-CODE for EDNS0 padding\n offset += 2;\n for (let i = 0; i < padding; i++) {\n // we do not need to generate cryptographically secure random numbers\n // simple random numbers are enough to obfuscate the message\n message.setUint8(offset++, Math.floor(Math.random() * 0xff));\n }\n\n return offset;\n}\n\nfunction serializeQuestion(\n message: DataView,\n offset: number,\n question: DnsQuestion,\n) {\n offset = serializeName(message, offset, question.qname);\n\n message.setUint16(offset, question.qtype);\n offset += 2;\n message.setUint16(offset, question.qclass);\n offset += 2;\n\n return offset;\n}\n\nfunction serializeHeader(\n message: DataView,\n offset: number,\n header: DnsMessage,\n) {\n // message id\n message.setUint16(offset, header.id);\n offset += 2;\n\n // flags\n message.setUint16(\n offset,\n ((header.qr & 0b1) << 15) |\n ((header.opcode & 0b1111) << 11) |\n ((header.aa & 0b1) << 10) |\n ((header.tc & 0b1) << 9) |\n ((header.rd & 0b1) << 8) |\n ((header.ra & 0b1) << 7) |\n ((header.z & 0b111) << 4) |\n (header.rcode & 0b1111),\n );\n offset += 2;\n\n // question records count\n message.setUint16(4, header.qdcount);\n offset += 2;\n\n // answer records count\n message.setUint16(6, header.ancount);\n offset += 2;\n\n // authority records count\n message.setUint16(8, header.nscount);\n offset += 2;\n\n // additional records count\n message.setUint16(10, header.arcount);\n offset += 2;\n\n return offset;\n}\n\nexport function parseDnsMessage(\n raw: RawDnsMessage,\n offset: number = 0,\n): DnsMessage {\n const rawView = new DataView(raw);\n const message = createDnsMessage();\n\n offset = parseHeader(rawView, offset, message);\n\n offset = parseQuestion(rawView, offset, message.qdcount, message.questions);\n\n offset = parseResourceRecords(\n rawView,\n offset,\n message.ancount,\n message.answers,\n );\n offset = parseResourceRecords(\n rawView,\n offset,\n message.nscount,\n message.authorityRecords,\n );\n offset = parseResourceRecords(\n rawView,\n offset,\n message.arcount,\n message.additionalRecords,\n );\n\n if (offset !== raw.byteLength) {\n // TODO: implement support for parsing padding and replace the warning with error\n console.warn(\n `Unexpected end of message (offset: ${offset}, length: ${raw.byteLength})`,\n );\n }\n\n return message;\n}\n\nfunction parseQuestion(\n rawView: DataView,\n offset: number,\n number: number,\n records: DnsQuestion[],\n) {\n for (let i = 0; i < number; i++) {\n const qname: DNSName = [];\n offset = parseName(rawView, offset, qname, 0);\n\n const qtype = rawView.getUint16(offset);\n offset += 2;\n const qclass = rawView.getUint16(offset);\n offset += 2;\n\n records.push({ qname, qtype, qclass });\n }\n return offset;\n}\n\nfunction parseResourceRecords(\n rawView: DataView,\n offset: number,\n number: number,\n records: DnsResourceRecord[],\n) {\n for (let i = 0; i < number; i++) {\n const name: DNSName = [];\n offset = parseName(rawView, offset, name, 0);\n\n const type = rawView.getUint16(offset);\n offset += 2;\n const class_ = rawView.getUint16(offset);\n offset += 2;\n const ttl = rawView.getUint32(offset);\n offset += 4;\n const rdlength = rawView.getUint16(offset);\n offset += 2;\n const rdata = [];\n for (let j = 0; j < rdlength; j++) {\n rdata.push(rawView.getUint8(offset++));\n }\n\n records.push({ name, type, class: class_, ttl, rdlength, rdata });\n }\n\n return offset;\n}\n\nfunction parseName(\n view: DataView,\n offset: number,\n output: DNSName,\n recursionDepth = 0,\n) {\n if (recursionDepth > 20) {\n throw new Error(\"Too many nested labels\");\n }\n\n let length = view.getUint8(offset++);\n while (length !== 0) {\n const labelType = length >> 6;\n if (labelType === 0b00) {\n // standard label\n const label = [];\n for (let i = 0; i < length; i++) {\n label.push(view.getUint8(offset++));\n }\n output.push(label);\n length = view.getUint8(offset++);\n } else if (labelType === 0b11) {\n // compressed label\n const pointer = ((length & 0b00111111) << 8) | view.getUint8(offset++);\n // ignore the offset as we returning from a \"jump\"\n parseName(view, pointer, output, recursionDepth + 1);\n break;\n } else {\n // we do not (yet) support extended label types (RFC2671)\n throw new Error(`Invalid label type: ${labelType.toString(2)}`);\n }\n }\n return offset;\n}\n\nfunction parseHeader(raw: DataView, offset: number, output: DnsMessage) {\n output.id = raw.getUint16(offset);\n offset += 2;\n\n const flags = raw.getUint16(offset);\n offset += 2;\n\n output.qr = ((flags & 0b1000000000000000) >> 15) as BinaryFlag;\n output.opcode = ((flags & 0b0111100000000000) >> 11) as FourBitNumber;\n output.aa = ((flags & 0b0000010000000000) >> 10) as BinaryFlag;\n output.tc = ((flags & 0b0000001000000000) >> 9) as BinaryFlag;\n output.rd = ((flags & 0b0000000100000000) >> 8) as BinaryFlag;\n output.ra = ((flags & 0b0000000010000000) >> 7) as BinaryFlag;\n output.z = ((flags & 0b0000000001110000) >> 4) as ThreeBitNumber;\n output.rcode = (flags & 0b0000000000001111) as FourBitNumber;\n\n output.qdcount = raw.getUint16(offset);\n offset += 2;\n\n output.ancount = raw.getUint16(offset);\n offset += 2;\n\n output.nscount = raw.getUint16(offset);\n offset += 2;\n\n output.arcount = raw.getUint16(offset);\n offset += 2;\n\n return offset;\n}\n","export function domainToAscii(domain: string) {\n const preprocessed = preprocessDomain(domain);\n const labels = preprocessed.split(\".\");\n\n const asciiLabels = labels.map((label) => {\n if (stringIsAscii(label)) {\n return label;\n } else {\n return \"xn--\" + punycodeEncode(label);\n }\n });\n\n return asciiLabels.join(\".\").toLowerCase();\n}\n\nfunction preprocessDomain(domain: string) {\n // https://unicode.org/reports/tr46/#TableDerivationStep1\n const exceptionalMapped = domain\n .replace(/[.。。]/gu, \".\")\n .replace(/ẞ/gu, \"ß\");\n\n // we normalize the input to Unicode Normalization Form KC\n const normalized = exceptionalMapped.normalize(\"NFKC\");\n\n // TODO: we deviate from the spec here to simplify the implementation\n // this may need to be revisited in the future\n\n // we should perform case folding here (NFKC_Casefold)\n // but we simplify this step to just lowercase the input instead\n const lowercased = normalized.toLowerCase();\n\n // remove all code points in the range U+FE00 to U+FE0F\n // (Unicode variation selectors) from the input\n // as they break emoji domains handling\n const filtered = lowercased.replace(/[\\uFE00-\\uFE0F]/gu, \"\");\n\n return filtered;\n}\n\nfunction stringIsAscii(str: string): boolean {\n return Array.from(str).every(charIsAscii);\n}\n\nfunction charIsAscii(char: string): boolean {\n return char.charCodeAt(0) < 128;\n}\n\nconst base = 36;\nconst tmin = 1;\nconst tmax = 26;\nconst skew = 38;\nconst damp = 700;\nconst initial_bias = 72;\nconst initial_n = 0x80;\n\nexport function punycodeEncode(str: string) {\n let n = initial_n;\n let delta = 0;\n let bias = initial_bias;\n const output: string[] = [];\n\n const inputChars = Array.from(str);\n\n // copy ascii chars to output\n const asciiChars = inputChars.filter(charIsAscii);\n const basicCodePoints = asciiChars.length;\n let handledCodePoints = basicCodePoints;\n output.push(...asciiChars);\n\n // append delimiter if we consumed any ascii chars\n if (basicCodePoints > 0) {\n output.push(\"-\");\n }\n\n const inputCodePoints = inputChars.map((char) => char.codePointAt(0)!);\n const inputLength = inputCodePoints.length;\n\n while (handledCodePoints < inputLength) {\n // Find the minimum code point >= n\n let m = Number.MAX_SAFE_INTEGER;\n for (const c of inputCodePoints) {\n if (c >= n && c < m) {\n m = c;\n }\n }\n\n delta += (m - n) * (handledCodePoints + 1);\n n = m;\n\n for (const c of inputCodePoints) {\n if (c < n) {\n delta++;\n } else if (c === n) {\n let q = delta;\n let k = base;\n\n while (true) {\n let t: number;\n if (k <= bias) {\n t = tmin;\n } else if (k >= bias + tmax) {\n t = tmax;\n } else {\n t = k - bias;\n }\n if (q < t) break;\n const code = t + ((q - t) % (base - t));\n output.push(encodeDigit(code));\n q = div(q - t, base - t);\n k += base;\n }\n\n output.push(encodeDigit(q));\n bias = adaptBias(\n delta,\n handledCodePoints + 1,\n handledCodePoints === basicCodePoints,\n );\n delta = 0;\n handledCodePoints++;\n }\n }\n\n delta++;\n n++;\n }\n\n return output.join(\"\");\n}\n\nfunction encodeDigit(d: number): string {\n return String.fromCharCode(d + 22 + 75 * Number(d < 26));\n}\n\nfunction div(n: number, d: number) {\n return Math.floor(n / d);\n}\n\nfunction adaptBias(delta: number, numPoints: number, firstTime: boolean) {\n if (firstTime) {\n delta = div(delta, damp);\n } else {\n delta = div(delta, 2);\n }\n\n delta += div(delta, numPoints);\n\n let k = 0;\n while (delta > div((base - tmin) * tmax, 2)) {\n delta = div(delta, base - tmin);\n\n k += 36;\n }\n\n return k + div((36 - 1 + 1) * delta, delta + skew);\n}\n","export const version = __LIB_VERSION__;\nimport {\n serializeDnsQuery,\n createDnsQuery,\n parseDnsMessage,\n stringToDNSName,\n dnsNameToString,\n} from \"./dns-message\";\nimport { domainToAscii } from \"./punycode\";\n\nexport function resolve(name: string, type: string) {\n const qualifiedName = domainToAscii(name);\n\n const query = createDnsQuery([\n {\n qname: stringToDNSName(qualifiedName),\n qtype: parseInt(type, 10),\n qclass: 1, // INTERNET\n },\n ]);\n\n const buffer = serializeDnsQuery(query);\n\n const url = new URL(\"https://1.1.1.1/dns-query\");\n return fetch(url, {\n method: \"POST\",\n mode: \"cors\",\n headers: {\n Accept: \"application/dns-message\",\n \"Content-Type\": \"application/dns-message\",\n },\n body: buffer,\n })\n .then((response) => {\n if (!response.ok) {\n throw new Error(\n `Failed to fetch: ${response.status} ${response.statusText}`,\n );\n }\n return response.arrayBuffer();\n })\n .then((buffer) => {\n const message = parseDnsMessage(buffer);\n return formatDnsMessage(message);\n })\n .catch((error) => {\n console.error(error);\n throw error;\n });\n}\n\nfunction formatDnsMessage(message: ReturnType<typeof parseDnsMessage>) {\n const formatted = {\n id: message.id,\n authoritativeAnswer: message.aa === 1,\n truncated: message.tc === 1,\n recursionAvailable: message.ra === 1,\n responseCode: message.rcode === 0 ? \"OK\" : \"ERROR\",\n questions: message.questions.map((question) => ({\n name: dnsNameToString(question.qname),\n type: question.qtype,\n })),\n answers: message.answers.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n authorityRecords: message.authorityRecords.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n additionalRecords: message.additionalRecords.map((record) => ({\n name: dnsNameToString(record.name),\n type: record.type,\n ttl: record.ttl,\n value: formatRData(record.type, record.rdata),\n })),\n };\n return JSON.stringify(formatted, null, 2);\n}\n\nfunction formatRData(recordType: number, rdata: number[]) {\n // TODO: this has to be implemented in the parser as the data\n // may include dns names and labels like for CNAMEs\n // or TXT (where there are labels but merged into a single string)\n switch (recordType) {\n case 1:\n return rdata.join(\".\");\n case 28:\n return rdata.map((c) => c.toString(16)).join(\":\");\n default:\n return rdata;\n }\n}\n"],"names":["dnsNameToString","name","label","stringToDNSName","labels","dnsName","bytes","char","code","createDnsMessage","createDnsQuery","questions","message","serializeDnsQuery","query","buffer","offset","serializeHeader","question","serializeQuestion","record","serializeResourceRecord","serializeEDNS0Padding","serializeName","byte","length","padding","i","header","parseDnsMessage","raw","rawView","parseHeader","parseQuestion","parseResourceRecords","number","records","qname","parseName","qtype","qclass","type","class_","ttl","rdlength","rdata","j","view","output","recursionDepth","labelType","pointer","flags","domainToAscii","domain","preprocessDomain","stringIsAscii","punycodeEncode","str","charIsAscii","base","tmin","tmax","skew","damp","initial_bias","initial_n","delta","bias","inputChars","asciiChars","basicCodePoints","handledCodePoints","inputCodePoints","inputLength","m","c","q","k","t","encodeDigit","div","adaptBias","d","n","numPoints","firstTime","version","resolve","qualifiedName","url","response","formatDnsMessage","error","formatted","formatRData","recordType"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "universal-doh",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "DNS over HTTPS universal TypeScript library",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Wojciech Malinowski"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/wmalinowski/universal-doh.git"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"main": "dist/universal-doh.umd.cjs",
|
|
18
|
+
"module": "dist/universal-doh.js",
|
|
19
|
+
"types": "dist/universal-doh.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/universal-doh.js",
|
|
23
|
+
"require": "./dist/universal-doh.umd.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"coverage": "vitest run --coverage",
|
|
28
|
+
"dev": "vite --config vite.site.config.js",
|
|
29
|
+
"build:lib": "tsc && vite build",
|
|
30
|
+
"build:site": "tsc && vite build --config vite.site.config.js",
|
|
31
|
+
"build": "npm run build:lib && npm run build:site",
|
|
32
|
+
"preview": "vite preview --config vite.site.config.js",
|
|
33
|
+
"lint": "eslint .",
|
|
34
|
+
"prettier": "prettier --check .",
|
|
35
|
+
"prettier:fix": "npm run prettier -- --write",
|
|
36
|
+
"prepublish": "npm run lint && npm run prettier && npm run coverage && npm run build",
|
|
37
|
+
"test": "vitest"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@eslint/js": "^9.12.0",
|
|
41
|
+
"@types/eslint__js": "^8.42.3",
|
|
42
|
+
"@vitest/coverage-v8": "^2.1.3",
|
|
43
|
+
"eslint": "^9.12.0",
|
|
44
|
+
"eslint-config-prettier": "^9.1.0",
|
|
45
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
46
|
+
"prettier": "^3.3.3",
|
|
47
|
+
"typescript": "^5.6.3",
|
|
48
|
+
"typescript-eslint": "^8.9.0",
|
|
49
|
+
"vite": "^5.4.8",
|
|
50
|
+
"vite-plugin-dts": "^4.2.4",
|
|
51
|
+
"vitest": "^2.1.3"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|