2755 lines
59 KiB
JavaScript
2755 lines
59 KiB
JavaScript
import e from "node:os";
|
|
|
|
import t from "node:dgram";
|
|
|
|
import { BlockList as s } from "node:net";
|
|
|
|
let n = function(e) {
|
|
e[e.QUERY = 0] = "QUERY";
|
|
e[e.RESPONSE = 32768] = "RESPONSE";
|
|
return e;
|
|
}({});
|
|
|
|
let r = function(e) {
|
|
e[e.A = 1] = "A";
|
|
e[e.NS = 2] = "NS";
|
|
e[e.CNAME = 5] = "CNAME";
|
|
e[e.SOA = 6] = "SOA";
|
|
e[e.NULL = 10] = "NULL";
|
|
e[e.PTR = 12] = "PTR";
|
|
e[e.HINFO = 13] = "HINFO";
|
|
e[e.MX = 15] = "MX";
|
|
e[e.TXT = 16] = "TXT";
|
|
e[e.RP = 17] = "RP";
|
|
e[e.AFSDB = 18] = "AFSDB";
|
|
e[e.SIG = 24] = "SIG";
|
|
e[e.KEY = 25] = "KEY";
|
|
e[e.AAAA = 28] = "AAAA";
|
|
e[e.LOC = 29] = "LOC";
|
|
e[e.SRV = 33] = "SRV";
|
|
e[e.NAPTR = 35] = "NAPTR";
|
|
e[e.KX = 36] = "KX";
|
|
e[e.CERT = 37] = "CERT";
|
|
e[e.DNAME = 39] = "DNAME";
|
|
e[e.OPT = 41] = "OPT";
|
|
e[e.APL = 42] = "APL";
|
|
e[e.DS = 43] = "DS";
|
|
e[e.SSHFP = 44] = "SSHFP";
|
|
e[e.IPSECKEY = 45] = "IPSECKEY";
|
|
e[e.RRSIG = 46] = "RRSIG";
|
|
e[e.NSEC = 47] = "NSEC";
|
|
e[e.DNSKEY = 48] = "DNSKEY";
|
|
e[e.DHCID = 49] = "DHCID";
|
|
e[e.NSEC3 = 50] = "NSEC3";
|
|
e[e.NSEC3PARAM = 51] = "NSEC3PARAM";
|
|
e[e.TLSA = 52] = "TLSA";
|
|
e[e.HIP = 55] = "HIP";
|
|
e[e.CDS = 59] = "CDS";
|
|
e[e.CDNSKEY = 60] = "CDNSKEY";
|
|
e[e.SVCB = 64] = "SVCB";
|
|
e[e.HTTPS = 65] = "HTTPS";
|
|
e[e.SPF = 99] = "SPF";
|
|
e[e.TKEY = 249] = "TKEY";
|
|
e[e.TSIG = 250] = "TSIG";
|
|
e[e.IXFR = 251] = "IXFR";
|
|
e[e.AXFR = 252] = "AXFR";
|
|
e[e.ANY = 255] = "ANY";
|
|
e[e.CAA = 257] = "CAA";
|
|
e[e.TA = 32768] = "TA";
|
|
e[e.DLV = 32769] = "DLV";
|
|
return e;
|
|
}({});
|
|
|
|
let a = function(e) {
|
|
e[e.IN = 1] = "IN";
|
|
e[e.CS = 2] = "CS";
|
|
e[e.CH = 3] = "CH";
|
|
e[e.HS = 4] = "HS";
|
|
e[e.ANY = 255] = "ANY";
|
|
return e;
|
|
}({});
|
|
|
|
let i = function(e) {
|
|
e[e.NOERR = 0] = "NOERR";
|
|
e[e.FORMERR = 1] = "FORMERR";
|
|
e[e.SERVFAIL = 2] = "SERVFAIL";
|
|
e[e.NXDOMAIN = 3] = "NXDOMAIN";
|
|
e[e.NOTIMP = 4] = "NOTIMP";
|
|
e[e.REFUSED = 5] = "REFUSED";
|
|
e[e.YXDOMAIN = 6] = "YXDOMAIN";
|
|
e[e.YXRRSET = 7] = "YXRRSET";
|
|
e[e.NXRRSET = 8] = "NXRRSET";
|
|
e[e.NOTAUTH = 9] = "NOTAUTH";
|
|
e[e.NOTZONE = 10] = "NOTZONE";
|
|
e[e.CHECKING_DISABLED = 16] = "CHECKING_DISABLED";
|
|
e[e.AUTHENTIC_DATA = 32] = "AUTHENTIC_DATA";
|
|
e[e.RECURSION_AVAILABLE = 128] = "RECURSION_AVAILABLE";
|
|
e[e.RECURSION_DESIRED = 256] = "RECURSION_DESIRED";
|
|
e[e.TRUNCATED_RESPONSE = 512] = "TRUNCATED_RESPONSE";
|
|
e[e.AUTHORITATIVE_ANSWER = 1024] = "AUTHORITATIVE_ANSWER";
|
|
return e;
|
|
}({});
|
|
|
|
let o = function(e) {
|
|
e[e.OPTION_0 = 0] = "OPTION_0";
|
|
e[e.LLQ = 1] = "LLQ";
|
|
e[e.UL = 2] = "UL";
|
|
e[e.NSID = 3] = "NSID";
|
|
e[e.OPTION_4 = 4] = "OPTION_4";
|
|
e[e.DAU = 5] = "DAU";
|
|
e[e.DHU = 6] = "DHU";
|
|
e[e.N3U = 7] = "N3U";
|
|
e[e.CLIENT_SUBNET = 8] = "CLIENT_SUBNET";
|
|
e[e.EXPIRE = 9] = "EXPIRE";
|
|
e[e.COOKIE = 10] = "COOKIE";
|
|
e[e.TCP_KEEPALIVE = 11] = "TCP_KEEPALIVE";
|
|
e[e.PADDING = 12] = "PADDING";
|
|
e[e.CHAIN = 13] = "CHAIN";
|
|
e[e.KEY_TAG = 14] = "KEY_TAG";
|
|
e[e.DEVICEID = 26946] = "DEVICEID";
|
|
e[e.OPTION_65535 = 65535] = "OPTION_65535";
|
|
return e;
|
|
}({});
|
|
|
|
const c = new TextEncoder;
|
|
|
|
const f = new TextDecoder;
|
|
|
|
const l = "undefined" != typeof Buffer ? e => Buffer.byteLength(e) : e => {
|
|
let t = e.length;
|
|
for (let s = t - 1; s >= 0; s--) {
|
|
const n = e.charCodeAt(s);
|
|
if (n > 127 && n <= 2047) {
|
|
t++;
|
|
} else if (n > 2047 && n <= 65535) {
|
|
t += 2;
|
|
}
|
|
if (n >= 56320 && n <= 57343) {
|
|
s--;
|
|
}
|
|
}
|
|
return t;
|
|
};
|
|
|
|
const d = {
|
|
bytes(e) {
|
|
let t = 2;
|
|
switch (e) {
|
|
case "":
|
|
case ".":
|
|
case "..":
|
|
return 1;
|
|
|
|
default:
|
|
if ("." === e[0]) {
|
|
t--;
|
|
}
|
|
if ("." === e[e.length - 1]) {
|
|
t--;
|
|
}
|
|
t += e.replace(/\\\./g, ".").length;
|
|
if (t > 255) {
|
|
throw new RangeError(`Name "${e}" is above 255 byte limit.`);
|
|
}
|
|
return t;
|
|
}
|
|
},
|
|
write(e, t, s) {
|
|
const n = c.encode(s);
|
|
for (let r = 46 === n[0] ? 1 : 0, a = 0; r < n.byteLength; r = a + 1) {
|
|
a = n.indexOf(46, r);
|
|
while (a > -1 && 92 === n[a - 1]) {
|
|
a = n.indexOf(46, a + 1);
|
|
}
|
|
if (-1 === a) {
|
|
a = n.byteLength;
|
|
}
|
|
if (a === r) {
|
|
continue;
|
|
} else if (a - r > 63) {
|
|
throw new RangeError(`Label in "${s}" is above 63 byte limit.`);
|
|
}
|
|
let i = t + 1;
|
|
for (let t = r; t < a; t++) {
|
|
if (92 === n[t] && 46 === n[t + 1]) {
|
|
t++;
|
|
}
|
|
e.setUint8(i++, n[t]);
|
|
}
|
|
e.setUint8(t, i - t - 1);
|
|
t = i;
|
|
r = a + 1;
|
|
}
|
|
return t + 1;
|
|
},
|
|
read(e, t) {
|
|
const s = [];
|
|
let n = t.offset;
|
|
let r = t;
|
|
while (1) {
|
|
const t = e.getUint8(r.offset);
|
|
if (0 === t) {
|
|
advance(r, 1);
|
|
break;
|
|
} else if (!(192 & t)) {
|
|
advance(r, 1);
|
|
const n = sliceView(e, r, t);
|
|
s.push(f.decode(n).replace(/\./g, "\\."));
|
|
} else {
|
|
const t = e.getUint16(r.offset) - 49152;
|
|
advance(r, 2);
|
|
if (t < n) {
|
|
r = {
|
|
offset: n = t,
|
|
length: 0
|
|
};
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return s.join(".") || ".";
|
|
}
|
|
};
|
|
|
|
const u = {
|
|
bytes: e => "string" == typeof e ? l(e) : e.byteLength,
|
|
write(e, t, s) {
|
|
const n = "string" == typeof s ? c.encode(s) : s;
|
|
new Uint8Array(e.buffer, e.byteOffset + t, n.byteLength).set(n);
|
|
return t + n.byteLength;
|
|
},
|
|
read: (e, t) => sliceView(e, t)
|
|
};
|
|
|
|
const h = {
|
|
bytes: e => e.byteLength + 1,
|
|
write(e, t, s) {
|
|
e.setUint8(t++, s.byteLength);
|
|
new Uint8Array(e.buffer, e.byteOffset + t, s.byteLength).set(s);
|
|
return t + s.byteLength;
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
advance(t, 1);
|
|
return sliceView(e, t, s);
|
|
}
|
|
};
|
|
|
|
const y = {
|
|
bytes: e => l(e) + 1,
|
|
write(e, t, s) {
|
|
const n = c.encode(s);
|
|
e.setUint8(t++, n.byteLength);
|
|
return u.write(e, t, n);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
advance(t, 1);
|
|
return f.decode(sliceView(e, t, s));
|
|
}
|
|
};
|
|
|
|
const g = {
|
|
bytes(e) {
|
|
const t = [];
|
|
for (let s = 0; s < e.length; s++) {
|
|
t[e[s] >> 8] = Math.max(t[e[s] >> 8] || 0, 255 & e[s]);
|
|
}
|
|
let s = 0;
|
|
for (let e = 0; e < t.length; e++) {
|
|
if (null != t[e]) {
|
|
s += 2 + Math.ceil((t[e] + 1) / 8);
|
|
}
|
|
}
|
|
return s;
|
|
},
|
|
write(e, t, s) {
|
|
const n = [];
|
|
for (let e = 0; e < s.length; e++) {
|
|
(n[s[e] >> 8] || (n[s[e] >> 8] = []))[s[e] >> 3 & 31] |= 1 << 7 - (7 & s[e]);
|
|
}
|
|
for (let s = 0; s < n.length; s++) {
|
|
const r = n[s];
|
|
if (null != r) {
|
|
e.setUint8(t++, s);
|
|
e.setUint8(t++, r.length);
|
|
for (let s = 0; s < r.length; s++) {
|
|
e.setUint8(t++, r[s]);
|
|
}
|
|
}
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const {offset: s, length: n} = t;
|
|
const r = [];
|
|
while (t.offset - s < n) {
|
|
const s = e.getUint8(t.offset);
|
|
const n = e.getUint8(t.offset + 1);
|
|
for (let a = 0; a < n; a++) {
|
|
const n = e.getUint8(t.offset + 2 + a);
|
|
for (let e = 0; e < 8; e++) {
|
|
if (n & 1 << 7 - e) {
|
|
r.push(s << 8 | a << 3 | e);
|
|
}
|
|
}
|
|
}
|
|
advance(t, 2 + n);
|
|
}
|
|
return r;
|
|
}
|
|
};
|
|
|
|
const p = {
|
|
bytes: () => 4,
|
|
write(e, t, s) {
|
|
const n = s.split(".", 4);
|
|
for (let s = 0; s < 4; s++) {
|
|
e.setUint8(t++, parseInt(n[s], 10));
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const s = Math.min(t.length, 4);
|
|
const n = new Array(4).fill(0).map((n, r) => r < s ? e.getUint8(t.offset + r) : 0).join(".");
|
|
advance(t, s);
|
|
return n;
|
|
}
|
|
};
|
|
|
|
const b = {
|
|
bytes: () => 2,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s);
|
|
return t + 2;
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
advance(t, 2);
|
|
return s;
|
|
}
|
|
};
|
|
|
|
const w = {
|
|
bytes: () => 16,
|
|
write(e, t, s) {
|
|
const n = s.indexOf("::");
|
|
const r = (n > -1 ? s.slice(0, n) : s).split(":");
|
|
const a = n > -1 ? s.slice(n + 2).split(":") : [];
|
|
const i = a.length > 0 && a[a.length - 1].includes(".") ? a.pop() : void 0;
|
|
for (let s = 0; s < r.length; s++) {
|
|
e.setUint16(t, parseInt(r[s], 16));
|
|
t += 2;
|
|
}
|
|
for (let s = 8 - (r.length + a.length + (i ? 2 : 0)); s > 0; s--) {
|
|
e.setUint16(t, 0);
|
|
t += 2;
|
|
}
|
|
for (let s = 0; s < a.length; s++) {
|
|
e.setUint16(t, parseInt(a[s], 16));
|
|
t += 2;
|
|
}
|
|
if (i) {
|
|
const s = i.split(".", 4).map(e => parseInt(e, 10));
|
|
e.setUint16(t, s[0] << 8 | s[1]);
|
|
e.setUint16(t + 2, s[2] << 8 | s[3]);
|
|
t += 4;
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
let s = "";
|
|
const n = Math.min(t.length, 16);
|
|
for (let r = 0; r < n; r += 2) {
|
|
if (0 !== r) {
|
|
s += ":";
|
|
}
|
|
s += e.getUint16(t.offset + r).toString(16);
|
|
}
|
|
advance(t, n);
|
|
return s.replace(/(^|:)0(:0)*:0(:|$)/, "$1::$3").replace(/:{3,4}/, "::");
|
|
}
|
|
};
|
|
|
|
const withRDLength = e => ({
|
|
bytes: t => e.bytes(t) + 2,
|
|
write(t, s, n) {
|
|
const r = s;
|
|
s = e.write(t, s + 2, n);
|
|
t.setUint16(r, s - r - 2);
|
|
return s;
|
|
},
|
|
read(t, s) {
|
|
const {offset: n, length: r} = s;
|
|
const a = s.length = t.getUint16(s.offset);
|
|
s.offset += 2;
|
|
const i = e.read(t, s);
|
|
s.offset = n + 2 + a;
|
|
s.length = r;
|
|
return i;
|
|
}
|
|
});
|
|
|
|
const array = e => ({
|
|
bytes(t) {
|
|
let s = 0;
|
|
for (let n = 0; null != t && n < t.length; n++) {
|
|
s += e.bytes(t[n]);
|
|
}
|
|
return s;
|
|
},
|
|
write(t, s, n) {
|
|
for (let r = 0; null != n && r < n.length; r++) {
|
|
s = e.write(t, s, n[r]);
|
|
}
|
|
return s;
|
|
},
|
|
read(t, s) {
|
|
const {offset: n, length: r} = s;
|
|
const a = [];
|
|
while (s.offset - n < r) {
|
|
a.push(e.read(t, s));
|
|
}
|
|
return a;
|
|
}
|
|
});
|
|
|
|
const advance = (e, t) => {
|
|
e.offset += 0 | t;
|
|
e.length -= 0 | t;
|
|
e.length &= ~(e.length >> 31);
|
|
};
|
|
|
|
const encodeIntoBuffer = (e, t) => {
|
|
const s = new ArrayBuffer(e.bytes(t));
|
|
const n = e.write(new DataView(s), 0, t);
|
|
return new Uint8Array(s, 0, n);
|
|
};
|
|
|
|
const sliceView = (e, t, s = t.length) => {
|
|
const n = new Uint8Array(e.buffer, e.byteOffset + t.offset, s);
|
|
advance(t, s);
|
|
return n;
|
|
};
|
|
|
|
const m = {
|
|
bytes: e => d.bytes(e.name) + 4,
|
|
write(e, t, s) {
|
|
let n = s.class || a.IN;
|
|
if (s.qu) {
|
|
n |= 32768;
|
|
}
|
|
t = d.write(e, t, s.name);
|
|
e.setUint16(t, s.type);
|
|
e.setUint16(t + 2, n);
|
|
return t + 4;
|
|
},
|
|
read(e, t) {
|
|
const s = d.read(e, t);
|
|
const n = e.getUint16(t.offset);
|
|
let r = e.getUint16(t.offset + 2) || a.ANY;
|
|
let i = !1;
|
|
if (r !== a.ANY && 32768 & r) {
|
|
r &= -32769;
|
|
i = !0;
|
|
}
|
|
advance(t, 4);
|
|
return {
|
|
name: s,
|
|
type: n,
|
|
class: r,
|
|
qu: i
|
|
};
|
|
}
|
|
};
|
|
|
|
const A = withRDLength({
|
|
bytes: e => u.bytes(e.data),
|
|
write: (e, t, s) => u.write(e, t, s.data),
|
|
read: (e, t) => ({
|
|
code: o.OPTION_0,
|
|
data: u.read(e, t)
|
|
})
|
|
});
|
|
|
|
const S = "(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])";
|
|
|
|
const E = new RegExp(`^(?:${S}\\.){3}${S}$`);
|
|
|
|
const U = withRDLength({
|
|
bytes: e => Math.ceil((e.sourcePrefixLength || 0) / 8) + 4,
|
|
write(e, t, s) {
|
|
const n = s.sourcePrefixLength || 0;
|
|
const r = s.scopePrefixLength || 0;
|
|
const a = s.family || (E.test(s.ip) ? 1 : 2);
|
|
const i = Math.ceil(n / 8);
|
|
e.setUint16(t, a);
|
|
e.setUint8(t + 2, n);
|
|
e.setUint8(t + 3, r);
|
|
t += 4;
|
|
const o = encodeIntoBuffer(1 === a ? p : w, s.ip);
|
|
for (let s = 0; s < i; s++) {
|
|
e.setUint8(t++, o[s]);
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const n = e.getUint8(t.offset + 2);
|
|
const r = e.getUint8(t.offset + 3);
|
|
advance(t, 4);
|
|
return {
|
|
code: o.CLIENT_SUBNET,
|
|
family: s,
|
|
sourcePrefixLength: n,
|
|
scopePrefixLength: r,
|
|
ip: 1 === s ? p.read(e, t) : w.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const T = withRDLength({
|
|
bytes: e => e.timeout ? 2 : 0,
|
|
write(e, t, s) {
|
|
if (s.timeout) {
|
|
e.setUint16(t, s.timeout);
|
|
t += 2;
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
if (t.length) {
|
|
const s = e.getUint16(t.offset);
|
|
advance(t, 2);
|
|
return {
|
|
code: o.TCP_KEEPALIVE,
|
|
timeout: s
|
|
};
|
|
} else {
|
|
return {
|
|
code: o.TCP_KEEPALIVE,
|
|
timeout: void 0
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
const N = withRDLength({
|
|
bytes: e => e.length || 0,
|
|
write: (e, t, s) => t + (s.length || 0),
|
|
read(e, t) {
|
|
const {length: s} = t;
|
|
advance(t, s);
|
|
return {
|
|
code: o.PADDING,
|
|
length: s
|
|
};
|
|
}
|
|
});
|
|
|
|
const I = withRDLength({
|
|
bytes: e => 2 * e.tags.length,
|
|
write(e, t, s) {
|
|
for (let n = 0; n < s.tags.length; n++) {
|
|
e.setUint16(t, s.tags[n]);
|
|
t += 2;
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const {offset: s, length: n} = t;
|
|
const r = [];
|
|
while (t.offset - s < n) {
|
|
r.push(e.getUint16(t.offset));
|
|
advance(t, 2);
|
|
}
|
|
return {
|
|
code: o.KEY_TAG,
|
|
tags: r
|
|
};
|
|
}
|
|
});
|
|
|
|
const isUnknownOpt = e => !!e.data;
|
|
|
|
const R = {
|
|
bytes(e) {
|
|
if (isUnknownOpt(e)) {
|
|
return A.bytes(e) + 2;
|
|
}
|
|
switch (e.code) {
|
|
case o.CLIENT_SUBNET:
|
|
return U.bytes(e) + 2;
|
|
|
|
case o.TCP_KEEPALIVE:
|
|
return T.bytes(e) + 2;
|
|
|
|
case o.PADDING:
|
|
return N.bytes(e) + 2;
|
|
|
|
case o.KEY_TAG:
|
|
return I.bytes(e) + 2;
|
|
}
|
|
},
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.code);
|
|
t += 2;
|
|
if (isUnknownOpt(s)) {
|
|
return A.write(e, t, s);
|
|
}
|
|
switch (s.code) {
|
|
case o.CLIENT_SUBNET:
|
|
return U.write(e, t, s);
|
|
|
|
case o.TCP_KEEPALIVE:
|
|
return T.write(e, t, s);
|
|
|
|
case o.PADDING:
|
|
return N.write(e, t, s);
|
|
|
|
case o.KEY_TAG:
|
|
return I.write(e, t, s);
|
|
}
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
advance(t, 2);
|
|
switch (s) {
|
|
case o.CLIENT_SUBNET:
|
|
return U.read(e, t);
|
|
|
|
case o.TCP_KEEPALIVE:
|
|
return T.read(e, t);
|
|
|
|
case o.PADDING:
|
|
return N.read(e, t);
|
|
|
|
case o.KEY_TAG:
|
|
return I.read(e, t);
|
|
|
|
default:
|
|
const n = A.read(e, t);
|
|
n.code = s;
|
|
return n;
|
|
}
|
|
}
|
|
};
|
|
|
|
const P = withRDLength(array(b));
|
|
|
|
const C = withRDLength(array(y));
|
|
|
|
const k = withRDLength(b);
|
|
|
|
const O = withRDLength(array(p));
|
|
|
|
const L = withRDLength(array(w));
|
|
|
|
const v = withRDLength(u);
|
|
|
|
const D = {
|
|
bytes(e) {
|
|
let t = 0;
|
|
if (null != e.mandatory) {
|
|
t += P.bytes(e.mandatory) + 2;
|
|
}
|
|
if (null != e.alpn) {
|
|
t += C.bytes(e.alpn) + 2;
|
|
}
|
|
if (e["no-default-alpn"]) {
|
|
t += 4;
|
|
}
|
|
if (null != e.port) {
|
|
t += k.bytes(e.port) + 2;
|
|
}
|
|
if (e.ipv4hint) {
|
|
t += O.bytes(e.ipv4hint) + 2;
|
|
}
|
|
if (e.ipv6hint) {
|
|
t += L.bytes(e.ipv6hint) + 2;
|
|
}
|
|
if (e.echconfig) {
|
|
t += v.bytes(e.echconfig) + 2;
|
|
}
|
|
if (e.dohpath) {
|
|
t += v.bytes(e.dohpath) + 2;
|
|
}
|
|
if (e.odoh) {
|
|
t += v.bytes(e.odoh) + 2;
|
|
}
|
|
return t;
|
|
},
|
|
write(e, t, s) {
|
|
if (null != s.mandatory) {
|
|
e.setUint16(t, 0);
|
|
t = P.write(e, t + 2, s.mandatory);
|
|
}
|
|
if (null != s.alpn) {
|
|
e.setUint16(t, 1);
|
|
t = C.write(e, t + 2, s.alpn);
|
|
}
|
|
if (s["no-default-alpn"]) {
|
|
e.setUint16(t, 2);
|
|
e.setUint16(t + 2, 0);
|
|
t += 4;
|
|
}
|
|
if (null != s.port) {
|
|
e.setUint16(t, 3);
|
|
t = k.write(e, t + 2, s.port);
|
|
}
|
|
if (s.ipv4hint) {
|
|
e.setUint16(t, 4);
|
|
t = O.write(e, t + 2, s.ipv4hint);
|
|
}
|
|
if (s.ipv6hint) {
|
|
e.setUint16(t, 6);
|
|
t = L.write(e, t + 2, s.ipv6hint);
|
|
}
|
|
if (s.echconfig) {
|
|
e.setUint16(t, 5);
|
|
t = v.write(e, t + 2, s.echconfig);
|
|
}
|
|
if (s.dohpath) {
|
|
e.setUint16(t, 7);
|
|
t = v.write(e, t + 2, s.dohpath);
|
|
}
|
|
if (s.odoh) {
|
|
e.setUint16(t, 32769);
|
|
t = v.write(e, t + 2, s.odoh);
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const {length: s, offset: n} = t;
|
|
const r = {
|
|
mandatory: void 0,
|
|
alpn: void 0,
|
|
"no-default-alpn": !1,
|
|
port: void 0,
|
|
ipv4hint: void 0,
|
|
ipv6hint: void 0,
|
|
echconfig: void 0,
|
|
dohpath: void 0,
|
|
odoh: void 0
|
|
};
|
|
while (t.offset - n < s) {
|
|
const s = e.getUint16(t.offset);
|
|
advance(t, 2);
|
|
switch (s) {
|
|
case 0:
|
|
r.mandatory = P.read(e, t);
|
|
break;
|
|
|
|
case 1:
|
|
r.alpn = C.read(e, t);
|
|
break;
|
|
|
|
case 2:
|
|
r["no-default-alpn"] = !0;
|
|
advance(t, 2);
|
|
break;
|
|
|
|
case 3:
|
|
r.port = k.read(e, t);
|
|
break;
|
|
|
|
case 4:
|
|
r.ipv4hint = O.read(e, t);
|
|
break;
|
|
|
|
case 6:
|
|
r.ipv6hint = L.read(e, t);
|
|
break;
|
|
|
|
case 5:
|
|
r.echconfig = v.read(e, t);
|
|
break;
|
|
|
|
case 7:
|
|
r.dohpath = f.decode(v.read(e, t));
|
|
break;
|
|
|
|
case 32769:
|
|
r.odoh = v.read(e, t);
|
|
break;
|
|
|
|
default:
|
|
v.read(e, t);
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
};
|
|
|
|
const x = withRDLength(u);
|
|
|
|
const _ = withRDLength(d);
|
|
|
|
const M = withRDLength(p);
|
|
|
|
const V = withRDLength(w);
|
|
|
|
const Y = withRDLength(array(y));
|
|
|
|
const H = withRDLength({
|
|
bytes: e => d.bytes(e.target) + 6,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.priority || 0);
|
|
e.setUint16(t + 2, s.weight || 0);
|
|
e.setUint16(t + 4, s.port || 0);
|
|
return d.write(e, t + 6, s.target);
|
|
},
|
|
read(e, t) {
|
|
const s = {
|
|
priority: 0,
|
|
weight: 0,
|
|
port: 0,
|
|
target: ""
|
|
};
|
|
s.priority = e.getUint16(t.offset);
|
|
s.weight = e.getUint16(t.offset + 2);
|
|
s.port = e.getUint16(t.offset + 4);
|
|
advance(t, 6);
|
|
s.target = d.read(e, t);
|
|
return s;
|
|
}
|
|
});
|
|
|
|
const q = withRDLength({
|
|
bytes: e => y.bytes(e.cpu) + y.bytes(e.os),
|
|
write(e, t, s) {
|
|
t = y.write(e, t, s.cpu);
|
|
return y.write(e, t, s.os);
|
|
},
|
|
read: (e, t) => ({
|
|
cpu: y.read(e, t),
|
|
os: y.read(e, t)
|
|
})
|
|
});
|
|
|
|
const toCaaTag = e => {
|
|
switch (e) {
|
|
case "issue":
|
|
case "issuewild":
|
|
case "iodef":
|
|
return e;
|
|
|
|
default:
|
|
return "issue";
|
|
}
|
|
};
|
|
|
|
const K = withRDLength({
|
|
bytes: e => y.bytes(e.tag) + u.bytes(e.value) + 1,
|
|
write(e, t, s) {
|
|
let n = s.flags || 0;
|
|
if (s.issuerCritical) {
|
|
n |= 128;
|
|
}
|
|
e.setUint8(t, n);
|
|
t = y.write(e, t + 1, s.tag);
|
|
return u.write(e, t, s.value);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
advance(t, 1);
|
|
return {
|
|
flags: s,
|
|
tag: toCaaTag(y.read(e, t)),
|
|
value: u.read(e, t),
|
|
issuerCritical: !!(128 & s)
|
|
};
|
|
}
|
|
});
|
|
|
|
const X = withRDLength({
|
|
bytes: e => d.bytes(e.mname) + d.bytes(e.rname) + 20,
|
|
write(e, t, s) {
|
|
t = d.write(e, t, s.mname);
|
|
t = d.write(e, t, s.rname);
|
|
e.setUint32(t, s.serial || 0);
|
|
e.setUint32(t + 4, s.refresh || 0);
|
|
e.setUint32(t + 8, s.retry || 0);
|
|
e.setUint32(t + 12, s.expire || 0);
|
|
e.setUint32(t + 16, s.minimum || 0);
|
|
return t + 20;
|
|
},
|
|
read(e, t) {
|
|
const s = {
|
|
mname: d.read(e, t),
|
|
rname: d.read(e, t),
|
|
serial: e.getUint32(t.offset),
|
|
refresh: e.getUint32(t.offset + 4),
|
|
retry: e.getUint32(t.offset + 8),
|
|
expire: e.getUint32(t.offset + 12),
|
|
minimum: e.getUint32(t.offset + 16)
|
|
};
|
|
t.offset += 20;
|
|
t.length -= 20;
|
|
return s;
|
|
}
|
|
});
|
|
|
|
const $ = withRDLength({
|
|
bytes: e => d.bytes(e.exchange) + 2,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.preference || 0);
|
|
return d.write(e, t + 2, s.exchange);
|
|
},
|
|
read(e, t) {
|
|
const s = {
|
|
preference: e.getUint16(t.offset),
|
|
exchange: ""
|
|
};
|
|
advance(t, 2);
|
|
s.exchange = d.read(e, t);
|
|
return s;
|
|
}
|
|
});
|
|
|
|
const F = withRDLength({
|
|
bytes: e => u.bytes(e.key) + 4,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.flags);
|
|
e.setUint8(t + 2, 3);
|
|
e.setUint8(t + 3, s.algorithm);
|
|
return u.write(e, t + 4, s.key);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const n = e.getUint8(t.offset + 3);
|
|
advance(t, 4);
|
|
return {
|
|
flags: s,
|
|
algorithm: n,
|
|
key: u.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const G = withRDLength({
|
|
bytes: e => 18 + d.bytes(e.signersName) + u.bytes(e.signature),
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.typeCovered);
|
|
e.setUint8(t + 2, s.algorithm);
|
|
e.setUint8(t + 3, s.labels);
|
|
e.setUint32(t + 4, s.originalTTL);
|
|
e.setUint32(t + 8, s.expiration);
|
|
e.setUint32(t + 12, s.inception);
|
|
e.setUint16(t + 16, s.keyTag);
|
|
t = d.write(e, t + 18, s.signersName);
|
|
return u.write(e, t, s.signature);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const n = e.getUint8(t.offset + 2);
|
|
const r = e.getUint8(t.offset + 3);
|
|
const a = e.getUint32(t.offset + 4);
|
|
const i = e.getUint32(t.offset + 8);
|
|
const o = e.getUint32(t.offset + 12);
|
|
const c = e.getUint16(t.offset + 16);
|
|
advance(t, 18);
|
|
return {
|
|
typeCovered: s,
|
|
algorithm: n,
|
|
labels: r,
|
|
originalTTL: a,
|
|
expiration: i,
|
|
inception: o,
|
|
keyTag: c,
|
|
signersName: d.read(e, t),
|
|
signature: u.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const B = withRDLength({
|
|
bytes: e => d.bytes(e.mbox) + d.bytes(e.txt),
|
|
write(e, t, s) {
|
|
t = d.write(e, t, s.mbox);
|
|
return d.write(e, t, s.txt);
|
|
},
|
|
read: (e, t) => ({
|
|
mbox: d.read(e, t),
|
|
txt: d.read(e, t)
|
|
})
|
|
});
|
|
|
|
const z = withRDLength({
|
|
bytes: e => d.bytes(e.nextDomain) + g.bytes(e.rrtypes),
|
|
write(e, t, s) {
|
|
t = d.write(e, t, s.nextDomain);
|
|
return g.write(e, t, s.rrtypes);
|
|
},
|
|
read: (e, t) => ({
|
|
nextDomain: d.read(e, t),
|
|
rrtypes: g.read(e, t)
|
|
})
|
|
});
|
|
|
|
const Q = withRDLength({
|
|
bytes: e => h.bytes(e.salt) + h.bytes(e.nextDomain) + g.bytes(e.rrtypes) + 4,
|
|
write(e, t, s) {
|
|
e.setUint8(t, s.algorithm);
|
|
e.setUint8(t + 1, s.flags);
|
|
e.setUint16(t + 2, s.iterations);
|
|
t = h.write(e, t + 4, s.salt);
|
|
t = h.write(e, t, s.nextDomain);
|
|
return g.write(e, t, s.rrtypes);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
const n = e.getUint8(t.offset + 1);
|
|
const r = e.getUint16(t.offset + 2);
|
|
advance(t, 4);
|
|
return {
|
|
algorithm: s,
|
|
flags: n,
|
|
iterations: r,
|
|
salt: h.read(e, t),
|
|
nextDomain: h.read(e, t),
|
|
rrtypes: g.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const j = withRDLength({
|
|
bytes: e => u.bytes(e.fingerprint) + 2,
|
|
write(e, t, s) {
|
|
e.setUint8(t, s.algorithm);
|
|
e.setUint8(t + 1, s.hash);
|
|
return u.write(e, t + 2, s.fingerprint);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
const n = e.getUint8(t.offset + 1);
|
|
advance(t, 2);
|
|
return {
|
|
algorithm: s,
|
|
hash: n,
|
|
fingerprint: u.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const W = withRDLength({
|
|
bytes: e => u.bytes(e.digest) + 4,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.keyTag);
|
|
e.setUint8(t + 2, s.algorithm);
|
|
e.setUint8(t + 3, s.digestType);
|
|
return u.write(e, t + 4, s.digest);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const n = e.getUint8(t.offset + 2);
|
|
const r = e.getUint8(t.offset + 3);
|
|
advance(t, 4);
|
|
return {
|
|
keyTag: s,
|
|
algorithm: n,
|
|
digestType: r,
|
|
digest: u.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const Z = withRDLength({
|
|
bytes: e => y.bytes(e.flags) + y.bytes(e.services) + y.bytes(e.regexp) + d.bytes(e.replacement) + 4,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.order);
|
|
e.setUint16(t + 2, s.preference);
|
|
t = y.write(e, t + 4, s.flags);
|
|
t = y.write(e, t, s.services);
|
|
t = y.write(e, t, s.regexp);
|
|
return d.write(e, t, s.replacement);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const n = e.getUint16(t.offset + 2);
|
|
advance(t, 4);
|
|
return {
|
|
order: s,
|
|
preference: n,
|
|
flags: y.read(e, t),
|
|
services: y.read(e, t),
|
|
regexp: y.read(e, t),
|
|
replacement: d.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const J = withRDLength({
|
|
bytes: e => u.bytes(e.certificate) + 3,
|
|
write(e, t, s) {
|
|
e.setUint8(t, s.usage);
|
|
e.setUint8(t + 1, s.selector);
|
|
e.setUint8(t + 2, s.matchingType);
|
|
return u.write(e, t + 3, s.certificate);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint8(t.offset);
|
|
const n = e.getUint8(t.offset + 1);
|
|
const r = e.getUint8(t.offset + 2);
|
|
advance(t, 3);
|
|
return {
|
|
usage: s,
|
|
selector: n,
|
|
matchingType: r,
|
|
certificate: u.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const ee = withRDLength({
|
|
bytes: e => d.bytes(e.name) + D.bytes(e.params) + 2,
|
|
write(e, t, s) {
|
|
e.setUint16(t, s.priority || 0);
|
|
t = d.write(e, t + 2, s.name);
|
|
return D.write(e, t, s.params);
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
advance(t, 2);
|
|
return {
|
|
name: d.read(e, t),
|
|
priority: s,
|
|
params: D.read(e, t)
|
|
};
|
|
}
|
|
});
|
|
|
|
const te = withRDLength(array(R));
|
|
|
|
const se = {
|
|
bytes(e) {
|
|
const t = 8 + d.bytes(e.type === r.OPT ? "." : e.name);
|
|
switch (e.type) {
|
|
case r.A:
|
|
return t + M.bytes(e.data);
|
|
|
|
case r.NS:
|
|
return t + _.bytes(e.data);
|
|
|
|
case r.SOA:
|
|
return t + X.bytes(e.data);
|
|
|
|
case r.HINFO:
|
|
return t + q.bytes(e.data);
|
|
|
|
case r.MX:
|
|
return t + $.bytes(e.data);
|
|
|
|
case r.TXT:
|
|
return t + Y.bytes(e.data);
|
|
|
|
case r.RP:
|
|
return t + B.bytes(e.data);
|
|
|
|
case r.AAAA:
|
|
return t + V.bytes(e.data);
|
|
|
|
case r.SRV:
|
|
return t + H.bytes(e.data);
|
|
|
|
case r.NAPTR:
|
|
return t + Z.bytes(e.data);
|
|
|
|
case r.OPT:
|
|
return t + te.bytes(e.data);
|
|
|
|
case r.DS:
|
|
return t + W.bytes(e.data);
|
|
|
|
case r.SSHFP:
|
|
return t + j.bytes(e.data);
|
|
|
|
case r.RRSIG:
|
|
return t + G.bytes(e.data);
|
|
|
|
case r.NSEC:
|
|
return t + z.bytes(e.data);
|
|
|
|
case r.DNSKEY:
|
|
return t + F.bytes(e.data);
|
|
|
|
case r.NSEC3:
|
|
return t + Q.bytes(e.data);
|
|
|
|
case r.TLSA:
|
|
return t + J.bytes(e.data);
|
|
|
|
case r.SVCB:
|
|
case r.HTTPS:
|
|
return t + ee.bytes(e.data);
|
|
|
|
case r.CAA:
|
|
return t + K.bytes(e.data);
|
|
|
|
case r.PTR:
|
|
case r.CNAME:
|
|
case r.DNAME:
|
|
return t + _.bytes(e.data);
|
|
|
|
default:
|
|
return t + x.bytes(e.data);
|
|
}
|
|
},
|
|
write(e, t, s) {
|
|
if (s.type === r.OPT) {
|
|
t = d.write(e, t, ".");
|
|
e.setUint16(t, s.type);
|
|
e.setUint16(t + 2, s.udpPayloadSize || 4096);
|
|
e.setUint8(t + 4, s.extendedRcode || 0);
|
|
e.setUint8(t + 5, s.ednsVersion || 0);
|
|
e.setUint16(t + 6, s.flags || 0);
|
|
return te.write(e, t += 8, s.data);
|
|
}
|
|
t = d.write(e, t, s.name);
|
|
e.setUint16(t, s.type);
|
|
e.setUint16(t + 2, (s.class || 0) | (s.flush ? 32768 : 0));
|
|
e.setUint32(t + 4, s.ttl || 0);
|
|
t += 8;
|
|
switch (s.type) {
|
|
case r.A:
|
|
return M.write(e, t, s.data);
|
|
|
|
case r.NS:
|
|
return _.write(e, t, s.data);
|
|
|
|
case r.SOA:
|
|
return X.write(e, t, s.data);
|
|
|
|
case r.HINFO:
|
|
return q.write(e, t, s.data);
|
|
|
|
case r.MX:
|
|
return $.write(e, t, s.data);
|
|
|
|
case r.TXT:
|
|
return Y.write(e, t, s.data);
|
|
|
|
case r.RP:
|
|
return B.write(e, t, s.data);
|
|
|
|
case r.AAAA:
|
|
return V.write(e, t, s.data);
|
|
|
|
case r.SRV:
|
|
return H.write(e, t, s.data);
|
|
|
|
case r.NAPTR:
|
|
return Z.write(e, t, s.data);
|
|
|
|
case r.DS:
|
|
return W.write(e, t, s.data);
|
|
|
|
case r.SSHFP:
|
|
return j.write(e, t, s.data);
|
|
|
|
case r.RRSIG:
|
|
return G.write(e, t, s.data);
|
|
|
|
case r.NSEC:
|
|
return z.write(e, t, s.data);
|
|
|
|
case r.DNSKEY:
|
|
return F.write(e, t, s.data);
|
|
|
|
case r.NSEC3:
|
|
return Q.write(e, t, s.data);
|
|
|
|
case r.TLSA:
|
|
return J.write(e, t, s.data);
|
|
|
|
case r.SVCB:
|
|
case r.HTTPS:
|
|
return ee.write(e, t, s.data);
|
|
|
|
case r.CAA:
|
|
return K.write(e, t, s.data);
|
|
|
|
case r.PTR:
|
|
case r.CNAME:
|
|
case r.DNAME:
|
|
return _.write(e, t, s.data);
|
|
|
|
default:
|
|
return x.write(e, t, s.data);
|
|
}
|
|
},
|
|
read(e, t) {
|
|
const s = d.read(e, t);
|
|
const n = e.getUint16(t.offset);
|
|
if (n === r.OPT) {
|
|
const s = e.getUint16(t.offset + 2) || 4096;
|
|
const r = e.getUint8(t.offset + 4);
|
|
const a = e.getUint8(t.offset + 5);
|
|
const i = e.getUint16(t.offset + 6);
|
|
advance(t, 8);
|
|
return {
|
|
type: n,
|
|
udpPayloadSize: s,
|
|
extendedRcode: r,
|
|
ednsVersion: a,
|
|
flags: i,
|
|
data: te.read(e, t)
|
|
};
|
|
}
|
|
const a = e.getUint16(t.offset + 2);
|
|
const i = e.getUint32(t.offset + 4);
|
|
advance(t, 8);
|
|
const o = {
|
|
name: s,
|
|
type: n,
|
|
class: -32769 & a,
|
|
flush: !!(32768 & a),
|
|
ttl: i,
|
|
data: null
|
|
};
|
|
switch (o.type) {
|
|
case r.A:
|
|
o.data = M.read(e, t);
|
|
return o;
|
|
|
|
case r.NS:
|
|
o.data = _.read(e, t);
|
|
return o;
|
|
|
|
case r.SOA:
|
|
o.data = X.read(e, t);
|
|
return o;
|
|
|
|
case r.HINFO:
|
|
o.data = q.read(e, t);
|
|
return o;
|
|
|
|
case r.MX:
|
|
o.data = $.read(e, t);
|
|
return o;
|
|
|
|
case r.TXT:
|
|
o.data = Y.read(e, t);
|
|
return o;
|
|
|
|
case r.RP:
|
|
o.data = B.read(e, t);
|
|
return o;
|
|
|
|
case r.AAAA:
|
|
o.data = V.read(e, t);
|
|
return o;
|
|
|
|
case r.SRV:
|
|
o.data = H.read(e, t);
|
|
return o;
|
|
|
|
case r.NAPTR:
|
|
o.data = Z.read(e, t);
|
|
return o;
|
|
|
|
case r.DS:
|
|
o.data = W.read(e, t);
|
|
return o;
|
|
|
|
case r.SSHFP:
|
|
o.data = j.read(e, t);
|
|
return o;
|
|
|
|
case r.RRSIG:
|
|
o.data = G.read(e, t);
|
|
return o;
|
|
|
|
case r.NSEC:
|
|
o.data = z.read(e, t);
|
|
return o;
|
|
|
|
case r.DNSKEY:
|
|
o.data = F.read(e, t);
|
|
return o;
|
|
|
|
case r.NSEC3:
|
|
o.data = Q.read(e, t);
|
|
return o;
|
|
|
|
case r.TLSA:
|
|
o.data = J.read(e, t);
|
|
return o;
|
|
|
|
case r.SVCB:
|
|
case r.HTTPS:
|
|
o.data = ee.read(e, t);
|
|
return o;
|
|
|
|
case r.CAA:
|
|
o.data = K.read(e, t);
|
|
return o;
|
|
|
|
case r.PTR:
|
|
case r.CNAME:
|
|
case r.DNAME:
|
|
o.data = _.read(e, t);
|
|
return o;
|
|
|
|
default:
|
|
o.data = x.read(e, t);
|
|
return o;
|
|
}
|
|
}
|
|
};
|
|
|
|
const compareAnswers = (e, t) => {
|
|
if (e.type === r.OPT || t.type === r.OPT) {
|
|
return 0;
|
|
}
|
|
const s = e.class || a.IN;
|
|
const n = t.class || a.IN;
|
|
if (s !== n) {
|
|
return s - n;
|
|
} else if (e.type !== t.type) {
|
|
return e.type - t.type;
|
|
}
|
|
let i;
|
|
switch (e.type) {
|
|
case r.A:
|
|
i = M;
|
|
break;
|
|
|
|
case r.NS:
|
|
i = _;
|
|
break;
|
|
|
|
case r.SOA:
|
|
i = X;
|
|
break;
|
|
|
|
case r.HINFO:
|
|
i = q;
|
|
break;
|
|
|
|
case r.MX:
|
|
i = $;
|
|
break;
|
|
|
|
case r.TXT:
|
|
i = Y;
|
|
break;
|
|
|
|
case r.RP:
|
|
i = B;
|
|
break;
|
|
|
|
case r.AAAA:
|
|
i = V;
|
|
break;
|
|
|
|
case r.SRV:
|
|
i = H;
|
|
break;
|
|
|
|
case r.NAPTR:
|
|
i = Z;
|
|
break;
|
|
|
|
case r.DS:
|
|
i = W;
|
|
break;
|
|
|
|
case r.SSHFP:
|
|
i = j;
|
|
break;
|
|
|
|
case r.RRSIG:
|
|
i = G;
|
|
break;
|
|
|
|
case r.NSEC:
|
|
i = z;
|
|
break;
|
|
|
|
case r.DNSKEY:
|
|
i = F;
|
|
break;
|
|
|
|
case r.NSEC3:
|
|
i = Q;
|
|
break;
|
|
|
|
case r.TLSA:
|
|
i = J;
|
|
break;
|
|
|
|
case r.SVCB:
|
|
case r.HTTPS:
|
|
i = ee;
|
|
break;
|
|
|
|
case r.CAA:
|
|
i = K;
|
|
break;
|
|
|
|
case r.PTR:
|
|
case r.CNAME:
|
|
case r.DNAME:
|
|
i = _;
|
|
break;
|
|
|
|
default:
|
|
i = x;
|
|
}
|
|
const o = encodeIntoBuffer(i, e.data);
|
|
const c = encodeIntoBuffer(i, t.data);
|
|
const f = o.byteLength < c.byteLength ? o.byteLength : c.byteLength;
|
|
for (let e = 2; e < f; e++) {
|
|
const t = o[e] - c[e];
|
|
if (0 !== t) {
|
|
return t < 0 ? -1 : 1;
|
|
}
|
|
}
|
|
return o.byteLength !== c.byteLength ? o.byteLength < c.byteLength ? -1 : 1 : 0;
|
|
};
|
|
|
|
const readList = (e, t, s, n) => {
|
|
if (!n) {
|
|
return;
|
|
}
|
|
const {offset: r, length: a} = s;
|
|
const i = [];
|
|
for (let o = 0; o < n && s.offset - r < a; o++) {
|
|
i.push(e.read(t, s));
|
|
}
|
|
return i;
|
|
};
|
|
|
|
const ne = {
|
|
bytes(e) {
|
|
const {questions: t, answers: s, authorities: n, additionals: r} = e;
|
|
let a = 12;
|
|
let i = 0;
|
|
for (i = 0; t && i < t.length; i++) {
|
|
a += m.bytes(t[i]);
|
|
}
|
|
for (i = 0; s && i < s.length; i++) {
|
|
a += se.bytes(s[i]);
|
|
}
|
|
for (i = 0; n && i < n.length; i++) {
|
|
a += se.bytes(n[i]);
|
|
}
|
|
for (i = 0; r && i < r.length; i++) {
|
|
a += se.bytes(r[i]);
|
|
}
|
|
return a;
|
|
},
|
|
write(e, t, s) {
|
|
const {questions: r, answers: a, authorities: i, additionals: o} = s;
|
|
let c = 32767 & (s.flags || 0) | (s.type || n.QUERY) | (s.rtype || 0);
|
|
e.setUint16(t, s.id || 0);
|
|
e.setUint16(t + 2, c);
|
|
e.setUint16(t + 4, s.questions?.length || 0);
|
|
e.setUint16(t + 6, s.answers?.length || 0);
|
|
e.setUint16(t + 8, s.authorities?.length || 0);
|
|
e.setUint16(t + 10, s.additionals?.length || 0);
|
|
t += 12;
|
|
let f = 0;
|
|
for (f = 0; r && f < r.length; f++) {
|
|
t = m.write(e, t, r[f]);
|
|
}
|
|
for (f = 0; a && f < a.length; f++) {
|
|
t = se.write(e, t, a[f]);
|
|
}
|
|
for (f = 0; i && f < i.length; f++) {
|
|
t = se.write(e, t, i[f]);
|
|
}
|
|
for (f = 0; o && f < o.length; f++) {
|
|
t = se.write(e, t, o[f]);
|
|
}
|
|
return t;
|
|
},
|
|
read(e, t) {
|
|
const s = e.getUint16(t.offset);
|
|
const r = e.getUint16(t.offset + 2);
|
|
const a = e.getUint16(t.offset + 4);
|
|
const i = e.getUint16(t.offset + 6);
|
|
const o = e.getUint16(t.offset + 8);
|
|
const c = e.getUint16(t.offset + 10);
|
|
advance(t, 12);
|
|
return {
|
|
id: s,
|
|
flags: r,
|
|
rtype: 15 & r,
|
|
type: r & n.RESPONSE ? n.RESPONSE : n.QUERY,
|
|
questions: readList(m, e, t, a),
|
|
answers: readList(se, e, t, i),
|
|
authorities: readList(se, e, t, o),
|
|
additionals: readList(se, e, t, c)
|
|
};
|
|
}
|
|
};
|
|
|
|
function encode(e) {
|
|
const t = new ArrayBuffer(ne.bytes(e));
|
|
const s = ne.write(new DataView(t), 0, e);
|
|
return new Uint8Array(t, 0, s);
|
|
}
|
|
|
|
const re = (() => {
|
|
let t = null;
|
|
let s = null;
|
|
return () => {
|
|
if (!t) {
|
|
t = e.networkInterfaces();
|
|
}
|
|
if (!s) {
|
|
s = Promise.resolve().then(() => t = s = null);
|
|
}
|
|
return t;
|
|
};
|
|
})();
|
|
|
|
const hasScopeid = e => null != e.scopeid && e.scopeid > 0;
|
|
|
|
let ae;
|
|
|
|
const hostname = () => ae || (ae = e.hostname());
|
|
|
|
const hammingWeight = e => {
|
|
e = (e = (858993459 & (e -= e >> 1 & 1431655765)) + (e >> 2 & 858993459)) + (e >> 4) & 252645135;
|
|
return 127 & (e += e >> 8) + (e >> 16);
|
|
};
|
|
|
|
const getIPv6PrefixFromNetmask = e => e.split(":").map(e => e && parseInt(e, 16) || 0).reduce((e, t) => e + hammingWeight(t), 0);
|
|
|
|
const getIPv4PrefixFromNetmask = e => e.split(".").map(e => e && parseInt(e, 10) || 0).reduce((e, t) => e + hammingWeight(t), 0);
|
|
|
|
let ie = !1;
|
|
|
|
const sanitizeLabel = e => e.trim().replace(/\.local\.?$/i, "").replace(/[^a-zA-Z0-9-]/g, "-").replace(/^-+|-+$/g, "").toLowerCase().slice(0, fe);
|
|
|
|
const srvAnswer = (e, t) => ({
|
|
type: r.SRV,
|
|
class: a.IN,
|
|
name: e.fqdnOut,
|
|
ttl: t,
|
|
flush: !0,
|
|
data: {
|
|
priority: 0,
|
|
weight: 0,
|
|
port: e.port,
|
|
target: e.host
|
|
}
|
|
});
|
|
|
|
const txtAnswer = (e, t) => ({
|
|
type: r.TXT,
|
|
class: a.IN,
|
|
name: e.fqdnOut,
|
|
ttl: t,
|
|
flush: !0,
|
|
data: e.txt
|
|
});
|
|
|
|
const ptrAnswer = (e, t, s) => ({
|
|
type: r.PTR,
|
|
class: a.IN,
|
|
name: e,
|
|
ttl: s,
|
|
flush: !1,
|
|
data: t
|
|
});
|
|
|
|
const ptrAnswers = (e, t) => [ ptrAnswer(e.domain, e.fqdnOut, t), ptrAnswer(de, e.domain, t), ...Object.keys(e.subtypes).map(s => ptrAnswer(s, e.fqdnOut, t)) ];
|
|
|
|
const aAnswers = (e, t, s) => t.filter(e => e.family === oe.v4).map(t => ({
|
|
type: r.A,
|
|
class: a.IN,
|
|
name: e.host,
|
|
ttl: s,
|
|
flush: !0,
|
|
data: t.address
|
|
}));
|
|
|
|
const aaaaAnswers = (e, t, s) => t.filter(e => e.family === oe.v6).map(t => ({
|
|
type: r.AAAA,
|
|
class: a.IN,
|
|
name: e.host,
|
|
ttl: s,
|
|
flush: !0,
|
|
data: t.address
|
|
}));
|
|
|
|
const answers = (e, t, s) => [ ...ptrAnswers(e, s), srvAnswer(e, s), txtAnswer(e, s), ...aAnswers(e, t, s), ...aaaaAnswers(e, t, s) ];
|
|
|
|
const authorities = (e, t, s) => [ ...aAnswers(e, t, s), txtAnswer(e, s), ...aaaaAnswers(e, t, s), srvAnswer(e, s) ];
|
|
|
|
const checkAnswerConflicts = (e, t, s) => {
|
|
let n = 0;
|
|
const a = new Set;
|
|
const i = new Set;
|
|
for (const s of e) {
|
|
const e = s.name?.toLowerCase();
|
|
if (s.type === r.SRV && e === t.fqdnIn && (s.data.port !== t.port || s.data.target.toLowerCase() !== t.host)) {
|
|
n |= 1;
|
|
} else if (s.type === r.A && e === t.host) {
|
|
a.add(s.data.toLowerCase());
|
|
} else if (s.type === r.AAAA && e === t.host) {
|
|
i.add(s.data.toLowerCase());
|
|
}
|
|
}
|
|
if (a.size || i.size) {
|
|
let e = 0;
|
|
let t = 0;
|
|
for (const r of s) {
|
|
if (r.family === oe.v4) {
|
|
e++;
|
|
if (a.size && !a.has(r.address)) {
|
|
n |= 2;
|
|
break;
|
|
}
|
|
} else if (r.family === oe.v6) {
|
|
t++;
|
|
if (i.size && !i.has(r.address)) {
|
|
n |= 4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (a.size && e !== a.size) {
|
|
n |= 2;
|
|
}
|
|
if (i.size && t !== i.size) {
|
|
n |= 4;
|
|
}
|
|
}
|
|
return n;
|
|
};
|
|
|
|
const checkResponseConflicts = (e, t, s) => {
|
|
let r = 0;
|
|
if (e.type === n.RESPONSE) {
|
|
if (e.answers?.length) {
|
|
r |= checkAnswerConflicts(e.answers, t, s);
|
|
}
|
|
if (e.additionals?.length) {
|
|
r |= checkAnswerConflicts(e.additionals, t, s);
|
|
}
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const responseMessage = (e, t, s, a) => {
|
|
if (e.type !== n.QUERY || !e.questions?.length) {
|
|
return null;
|
|
}
|
|
const o = Object.create(null);
|
|
let c = !1;
|
|
let f = !1;
|
|
let l = !1;
|
|
let d = !1;
|
|
if (e.answers) {
|
|
for (const s of e.answers) {
|
|
const e = s.name?.toLowerCase();
|
|
switch (s.type) {
|
|
case r.SRV:
|
|
c ||= e === t.fqdnIn;
|
|
break;
|
|
|
|
case r.TXT:
|
|
f ||= e === t.fqdnIn;
|
|
break;
|
|
|
|
case r.A:
|
|
l ||= e === t.host;
|
|
break;
|
|
|
|
case r.AAAA:
|
|
d ||= e === t.host;
|
|
break;
|
|
|
|
case r.PTR:
|
|
switch (e) {
|
|
case t.domain:
|
|
if (s.data.toLowerCase() === t.fqdnIn) {
|
|
o[t.domain] = !0;
|
|
}
|
|
break;
|
|
|
|
case de:
|
|
if (s.data.toLowerCase() === t.domain) {
|
|
o[de] = !0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (e && t.subtypes[e] && s.data.toLowerCase() === t.fqdnIn) {
|
|
o[e] = !0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const u = [];
|
|
const h = [];
|
|
for (const n of e.questions) {
|
|
if (!!n.qu !== a) {
|
|
continue;
|
|
}
|
|
const e = n.name.toLowerCase();
|
|
switch (n.type) {
|
|
case r.SRV:
|
|
if (!c && e === t.fqdnIn) {
|
|
u.push(srvAnswer(t, t.ttl));
|
|
c = !0;
|
|
}
|
|
break;
|
|
|
|
case r.TXT:
|
|
if (!f && e === t.fqdnIn) {
|
|
u.push(txtAnswer(t, t.ttl));
|
|
f = !0;
|
|
}
|
|
break;
|
|
|
|
case r.A:
|
|
if (!l && e === t.host) {
|
|
u.push(...aAnswers(t, s, t.ttl));
|
|
l = !0;
|
|
}
|
|
break;
|
|
|
|
case r.AAAA:
|
|
if (!d && e === t.host) {
|
|
u.push(...aaaaAnswers(t, s, t.ttl));
|
|
d = !0;
|
|
}
|
|
break;
|
|
|
|
case r.PTR:
|
|
switch (e) {
|
|
case t.domain:
|
|
if (!o[t.domain]) {
|
|
u.push(ptrAnswer(t.domain, t.fqdnOut, t.ttl));
|
|
o[t.domain] = !0;
|
|
}
|
|
break;
|
|
|
|
case de:
|
|
if (!o[de]) {
|
|
u.push(ptrAnswer(de, t.domain, t.ttl));
|
|
o[de] = !0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (t.subtypes[e]) {
|
|
u.push(ptrAnswer(e, t.fqdnOut, t.ttl));
|
|
o[e] = !0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case r.ANY:
|
|
switch (e) {
|
|
case t.fqdnIn:
|
|
if (!c) {
|
|
u.push(srvAnswer(t, t.ttl));
|
|
c = !0;
|
|
}
|
|
if (!f) {
|
|
u.push(txtAnswer(t, t.ttl));
|
|
f = !0;
|
|
}
|
|
break;
|
|
|
|
case t.host:
|
|
if (!l) {
|
|
u.push(...aAnswers(t, s, t.ttl));
|
|
l = !0;
|
|
}
|
|
if (!d) {
|
|
u.push(...aaaaAnswers(t, s, t.ttl));
|
|
d = !0;
|
|
}
|
|
break;
|
|
|
|
case t.domain:
|
|
if (!o[t.domain]) {
|
|
u.push(ptrAnswer(t.domain, t.fqdnOut, t.ttl));
|
|
o[t.domain] = !0;
|
|
}
|
|
break;
|
|
|
|
case de:
|
|
if (!o[de]) {
|
|
u.push(ptrAnswer(de, t.domain, t.ttl));
|
|
o[de] = !0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (t.subtypes[e]) {
|
|
u.push(ptrAnswer(e, t.fqdnOut, t.ttl));
|
|
o[e] = !0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (o[t.domain] && !c) {
|
|
h.push(srvAnswer(t, t.ttl));
|
|
c = !0;
|
|
}
|
|
if (o[t.domain] && !f) {
|
|
h.push(txtAnswer(t, t.ttl));
|
|
f = !0;
|
|
}
|
|
if (c && !l) {
|
|
h.push(...aAnswers(t, s, t.ttl));
|
|
l = !0;
|
|
}
|
|
if (c && !d) {
|
|
h.push(...aaaaAnswers(t, s, t.ttl));
|
|
d = !0;
|
|
}
|
|
if (u.length > 0) {
|
|
return encode({
|
|
type: n.RESPONSE,
|
|
flags: i.AUTHORITATIVE_ANSWER,
|
|
answers: u,
|
|
additionals: h
|
|
});
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const createSocketSettings = (e, t) => {
|
|
const s = t === oe.v4 ? ce.v4 : ce.v6;
|
|
const n = ((e, t) => {
|
|
let s = re()[e]?.filter(e => e.family === t).map(s => ({
|
|
...s,
|
|
family: t,
|
|
iname: e
|
|
}));
|
|
if (s && t === oe.v6) {
|
|
s?.sort((e, t) => {
|
|
if (e.address.startsWith("fe80:")) {
|
|
return 1;
|
|
} else if (t.address.startsWith("fe80:")) {
|
|
return -1;
|
|
} else {
|
|
return e.address < t.address ? -1 : 1;
|
|
}
|
|
});
|
|
}
|
|
return s?.length ? s : void 0;
|
|
})(e, t);
|
|
if (!n?.length) {
|
|
return null;
|
|
}
|
|
const r = new Set;
|
|
let a;
|
|
if (t === oe.v4) {
|
|
a = n[0].address;
|
|
for (const e of n) {
|
|
r.add(e.address);
|
|
}
|
|
} else {
|
|
const t = "win32" === process.platform ? n.find(hasScopeid)?.scopeid.toString() : e;
|
|
if (!t) {
|
|
return null;
|
|
}
|
|
r.add(a = `::%${t}`);
|
|
}
|
|
return {
|
|
family: t,
|
|
bindings: n,
|
|
memberships: r,
|
|
multicastAddress: s,
|
|
multicastInterface: a
|
|
};
|
|
};
|
|
|
|
const addMembership = (e, t, s) => {
|
|
try {
|
|
e.addMembership(t.multicastAddress, s);
|
|
return !0;
|
|
} catch (e) {
|
|
return !1;
|
|
}
|
|
};
|
|
|
|
const dropMembership = (e, t, s) => {
|
|
try {
|
|
e.dropMembership(t.multicastAddress, s);
|
|
return !0;
|
|
} catch {
|
|
return !1;
|
|
}
|
|
};
|
|
|
|
const createInterfaceSocket = (e, n, r) => {
|
|
const a = [];
|
|
let i = null;
|
|
let o = initSocket();
|
|
function initSocket() {
|
|
const a = createSocketSettings(e, n);
|
|
if (!a) {
|
|
return null;
|
|
}
|
|
let i;
|
|
if ("linux" === process.platform) {
|
|
const e = new s;
|
|
for (const t of a.bindings) {
|
|
if (t.family === oe.v4) {
|
|
e.addSubnet(t.address, getIPv4PrefixFromNetmask(t.netmask), "ipv4");
|
|
} else {
|
|
e.addSubnet(t.address, getIPv6PrefixFromNetmask(t.netmask), "ipv6");
|
|
}
|
|
}
|
|
const t = n === oe.v4 ? "ipv4" : "ipv6";
|
|
i = s => e.check(s, t);
|
|
}
|
|
const o = t.createSocket(n === oe.v4 ? {
|
|
type: "udp4",
|
|
reuseAddr: !0
|
|
} : {
|
|
type: "udp6",
|
|
reuseAddr: !0,
|
|
ipv6Only: !0
|
|
});
|
|
o.unref();
|
|
o.on("message", async (t, s) => {
|
|
let a = -1;
|
|
if (n === oe.v6 && (a = s.address.indexOf("%")) > -1) {
|
|
if (s.address.slice(a + 1) !== e) {
|
|
return;
|
|
}
|
|
} else if (-1 === a && i && !i(s.address)) {
|
|
return;
|
|
}
|
|
try {
|
|
await r.onMessage(t, {
|
|
socket: c,
|
|
family: "IPv6" === s.family ? oe.v6 : oe.v4,
|
|
address: s.address,
|
|
port: s.port,
|
|
reply: e => send(e, s.address, s.port)
|
|
});
|
|
} catch {}
|
|
});
|
|
scheduleTimer(new Promise((e, t) => {
|
|
o.prependOnceListener("error", t);
|
|
o.prependOnceListener("close", closeSocket);
|
|
o.bind(le, () => {
|
|
try {
|
|
setupSocket(o, a);
|
|
e();
|
|
} catch (e) {
|
|
closeSocket();
|
|
t(e);
|
|
} finally {
|
|
o.removeListener("error", t);
|
|
o.on("error", closeSocket);
|
|
}
|
|
});
|
|
}));
|
|
return {
|
|
settings: a,
|
|
socket: o
|
|
};
|
|
}
|
|
function setupSocket(e, t) {
|
|
const s = t !== o?.settings ? o?.settings : null;
|
|
let n = !!s && s.multicastInterface !== t.multicastInterface;
|
|
try {
|
|
e.setMulticastTTL(255);
|
|
e.setMulticastLoopback(!0);
|
|
e.setMulticastInterface(t.multicastInterface);
|
|
} catch {
|
|
closeSocket();
|
|
return !1;
|
|
}
|
|
if (s) {
|
|
for (const r of s.memberships) {
|
|
if (!t.memberships.has(r)) {
|
|
dropMembership(e, s, r);
|
|
n = !0;
|
|
}
|
|
}
|
|
}
|
|
for (const r of t.memberships) {
|
|
if (!s?.memberships.has(r)) {
|
|
if (!addMembership(e, t, r)) {
|
|
t.memberships.delete(r);
|
|
} else if (s) {
|
|
n = !0;
|
|
}
|
|
}
|
|
}
|
|
if (!t.memberships.size) {
|
|
closeSocket();
|
|
return !1;
|
|
} else if (o) {
|
|
o.settings = t;
|
|
}
|
|
return n;
|
|
}
|
|
function closeSocket() {
|
|
if (o) {
|
|
const {socket: e} = o;
|
|
o = null;
|
|
try {
|
|
e.close();
|
|
} catch {}
|
|
}
|
|
}
|
|
function sendImmediate(e) {
|
|
try {
|
|
if (o) {
|
|
o.socket.send(e.message, 0, e.message.byteLength, e.port, e.address, e.onSent);
|
|
} else {
|
|
e.onSent(null);
|
|
}
|
|
} catch (t) {
|
|
e.onSent(t);
|
|
}
|
|
}
|
|
function flushQueue(e) {
|
|
if (null === e || i === e) {
|
|
i = null;
|
|
}
|
|
let t;
|
|
while (!i && null != (t = a.shift())) {
|
|
sendImmediate(t);
|
|
}
|
|
}
|
|
function scheduleTimer(e = function waitTick() {
|
|
return new Promise(e => setTimeout(e, 0).unref());
|
|
}()) {
|
|
if (!i) {
|
|
const t = i = e.then(() => flushQueue(t), () => flushQueue(null));
|
|
}
|
|
}
|
|
async function send(e, t, s) {
|
|
return new Promise((n, r) => {
|
|
scheduleTimer();
|
|
a.push({
|
|
message: e,
|
|
address: t,
|
|
port: s,
|
|
onSent(e) {
|
|
if (null != e) {
|
|
r(e);
|
|
} else {
|
|
n();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
const c = {
|
|
get closed() {
|
|
return !o;
|
|
},
|
|
get bindings() {
|
|
return o?.settings.bindings ?? [];
|
|
},
|
|
async send(e) {
|
|
if (o) {
|
|
await send(e, o.settings.multicastAddress, le);
|
|
}
|
|
},
|
|
refresh() {
|
|
if (o) {
|
|
const t = createSocketSettings(e, n);
|
|
if (t) {
|
|
return setupSocket(o.socket, t);
|
|
} else {
|
|
closeSocket();
|
|
return !1;
|
|
}
|
|
} else {
|
|
o = initSocket();
|
|
return !!o;
|
|
}
|
|
},
|
|
close() {
|
|
closeSocket();
|
|
flushQueue(null);
|
|
}
|
|
};
|
|
return c;
|
|
};
|
|
|
|
let oe = function(e) {
|
|
e.v4 = "IPv4";
|
|
e.v6 = "IPv6";
|
|
return e;
|
|
}({});
|
|
|
|
let ce = function(e) {
|
|
e.v4 = "224.0.0.251";
|
|
e.v6 = "ff02::fb";
|
|
return e;
|
|
}({});
|
|
|
|
const fe = 63;
|
|
|
|
const le = 5353;
|
|
|
|
const de = "_services._dns-sd._udp.local";
|
|
|
|
const ue = {
|
|
onError() {},
|
|
createSocket: (e, t) => {
|
|
let s;
|
|
let n = null;
|
|
if ("IPv4" === t.stack) {
|
|
s = createInterfaceSocket(e, oe.v4, t);
|
|
} else if ("IPv6" === t.stack) {
|
|
s = createInterfaceSocket(e, oe.v6, t);
|
|
} else {
|
|
s = createInterfaceSocket(e, oe.v4, t);
|
|
n = createInterfaceSocket(e, oe.v6, t);
|
|
}
|
|
return {
|
|
get closed() {
|
|
return s.closed && (!n || n.closed);
|
|
},
|
|
get bindings() {
|
|
return n ? [ ...s.bindings, ...n.bindings ] : s.bindings;
|
|
},
|
|
async send(e) {
|
|
await Promise.all([ s.send(e), n?.send(e) ]);
|
|
},
|
|
refresh() {
|
|
const e = !!s.refresh();
|
|
const t = !!n?.refresh();
|
|
return e || t;
|
|
},
|
|
close() {
|
|
s.close();
|
|
n?.close();
|
|
}
|
|
};
|
|
},
|
|
createScheduler: function createScheduler() {
|
|
const e = new Set;
|
|
return {
|
|
schedule: async function schedule(t, s) {
|
|
return await async function schedule(n, r) {
|
|
if (!r) {
|
|
r = getDelay(t, n);
|
|
}
|
|
return new Promise(async (a, i) => {
|
|
const o = Math.max(r, 20);
|
|
const c = runTimer(t, o, async () => {
|
|
e.delete(onCancel);
|
|
let o = !1;
|
|
try {
|
|
let e;
|
|
if (s) {
|
|
e = await s({
|
|
attempt: n,
|
|
retry(e) {
|
|
o = !0;
|
|
return schedule(n + 1, e);
|
|
}
|
|
});
|
|
}
|
|
a(e);
|
|
} catch (e) {
|
|
if (!o && shouldRetry(t, n)) {
|
|
schedule(n + 1, r).then(a, i);
|
|
} else {
|
|
i(e);
|
|
}
|
|
}
|
|
});
|
|
function onCancel() {
|
|
i(new AbortError);
|
|
c();
|
|
}
|
|
e.add(onCancel);
|
|
});
|
|
}(0);
|
|
},
|
|
cancel() {
|
|
for (const t of e) {
|
|
t();
|
|
}
|
|
e.clear();
|
|
}
|
|
};
|
|
},
|
|
createServiceInput: e => ({
|
|
...e,
|
|
nameSeed: 0,
|
|
hostnameSeed: ie && e.hostname === hostname() ? 1 : 0
|
|
}),
|
|
createServiceRecord: e => {
|
|
const t = ((e, t) => {
|
|
let s = sanitizeLabel(e);
|
|
if (t) {
|
|
ie ||= e === hostname();
|
|
const n = /[-_](\d+)$/.exec(s);
|
|
if (n) {
|
|
const e = s.slice(0, -n[0].length);
|
|
const r = `-${(parseInt(n[1], 10) || t) + 1}`;
|
|
s = e.slice(0, fe - r.length) + r;
|
|
} else {
|
|
const e = `-${t + 1}`;
|
|
s = s.slice(0, fe - e.length) + e;
|
|
}
|
|
}
|
|
return s;
|
|
})(e.hostname, e.hostnameSeed);
|
|
const s = ((e, t, s) => {
|
|
const n = (e => e.trim().replace(/\.+/, "_").slice(0, fe))(e);
|
|
if (s) {
|
|
const e = ` (${((e, t) => {
|
|
const s = `${hostname()}:${e}`;
|
|
let n = 5381;
|
|
if (0 !== t) {
|
|
n = (n << 5) + n + (255 & t);
|
|
}
|
|
for (let e = 0, t = s.length; e < t; e++) {
|
|
n = (n << 5) + n + s.charCodeAt(e);
|
|
}
|
|
return (65535 & n).toString(16).toUpperCase().padStart(4, "0");
|
|
})(t, s - 1)})`;
|
|
return n.slice(0, fe - e.length) + e;
|
|
} else {
|
|
return n;
|
|
}
|
|
})(e.name, e.port, e.nameSeed);
|
|
const n = `_${sanitizeLabel(e.type)}._${sanitizeLabel(e.protocol)}.local`;
|
|
const r = `${s}.${n}`;
|
|
const a = [];
|
|
for (const t in e.txt) {
|
|
const s = e.txt[t];
|
|
if ("string" == typeof s || "number" == typeof s) {
|
|
a.push(`${t}=${s}`);
|
|
} else if ("boolean" == typeof s && s) {
|
|
a.push(t);
|
|
}
|
|
}
|
|
return {
|
|
domain: n,
|
|
fqdnOut: r,
|
|
fqdnIn: r.toLowerCase(),
|
|
host: `${t}.local`,
|
|
port: e.port >>> 0,
|
|
subtypes: (e.subtypes || []).reduce((e, t) => {
|
|
e[`${(e => e.trim().replace(/[^a-zA-Z0-9-_.]/g, "-").replace(/^-+|-+$/g, "").toLowerCase())(t)}._sub.${n}`] = !0;
|
|
return e;
|
|
}, Object.create(null)),
|
|
txt: a,
|
|
ttl: e.ttl
|
|
};
|
|
},
|
|
networkInterfaceNames: () => {
|
|
const e = [];
|
|
const t = re();
|
|
for (const s in t) {
|
|
const n = t[s];
|
|
if (n?.some(e => !e.internal)) {
|
|
e.push(s);
|
|
}
|
|
}
|
|
return e.length ? e : Object.keys(t);
|
|
},
|
|
hostname
|
|
};
|
|
|
|
const he = new Map;
|
|
|
|
const randomDelay = (e, t) => e + Math.floor(Math.random() * (t - e + 1));
|
|
|
|
const shouldRetry = (e, t) => {
|
|
switch (e) {
|
|
case 0:
|
|
case 1:
|
|
return t < 4;
|
|
|
|
case 2:
|
|
return t < 3;
|
|
|
|
case 3:
|
|
return !0;
|
|
}
|
|
};
|
|
|
|
const getDelay = (e, t) => {
|
|
switch (e) {
|
|
case 0:
|
|
return randomDelay(20, 120);
|
|
|
|
case 1:
|
|
return t ? 250 : randomDelay(0, 250);
|
|
|
|
case 2:
|
|
return t ? 1e3 * 2 ** (Math.min(t, 3) - 1) : 0;
|
|
|
|
case 3:
|
|
return 6e3;
|
|
}
|
|
};
|
|
|
|
const runTimer = (e, t, s) => {
|
|
const n = Date.now() + t;
|
|
let r = he.get(e);
|
|
let a;
|
|
if (r) {
|
|
for (const t of r) {
|
|
if (3 === e || Math.abs(t.time - n) <= 100) {
|
|
a = t;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
r = new Set;
|
|
he.set(e, r);
|
|
}
|
|
if (!a) {
|
|
const e = setTimeout(() => {
|
|
r.delete(a);
|
|
for (const e of a.tasks) {
|
|
e();
|
|
}
|
|
}, t);
|
|
if ("unref" in e) {
|
|
e.unref();
|
|
}
|
|
r.add(a = {
|
|
time: n,
|
|
tasks: new Set,
|
|
timeout: e
|
|
});
|
|
}
|
|
a.tasks.add(s);
|
|
return () => {
|
|
a.tasks.delete(s);
|
|
if (!a.tasks.size) {
|
|
clearTimeout(a.timeout);
|
|
r.delete(a);
|
|
}
|
|
};
|
|
};
|
|
|
|
class AbortError extends Error {
|
|
static isAbortError(e) {
|
|
return e && "object" == typeof e && "AbortError" === e.name;
|
|
}
|
|
constructor() {
|
|
super("Operation cancelled");
|
|
this.name = "AbortError";
|
|
}
|
|
}
|
|
|
|
function createInterfaceAdvertiser(e, t, s) {
|
|
const o = s.createServiceInput(t);
|
|
const c = s.createScheduler();
|
|
let f = 0;
|
|
let l = 0;
|
|
let d = s.createServiceRecord(o);
|
|
let u = 0;
|
|
let h = 0;
|
|
const y = s.createSocket(e, {
|
|
stack: t.stack,
|
|
async onMessage(e, t) {
|
|
if (3 === u) {
|
|
return;
|
|
}
|
|
const a = function decode(e) {
|
|
const t = "buffer" in e ? new DataView(e.buffer, e.byteOffset, e.byteLength) : new DataView(e);
|
|
return ne.read(t, {
|
|
offset: 0,
|
|
length: t.byteLength
|
|
});
|
|
}(e);
|
|
if (0 === u) {
|
|
l++;
|
|
if (a.type === n.QUERY) {
|
|
const e = ((e, t, s) => {
|
|
if (e.type !== n.QUERY || !e.questions?.length || !e.authorities?.length) {
|
|
return 0;
|
|
}
|
|
if (!e.questions.some(e => {
|
|
const s = e.name.toLowerCase();
|
|
return (e => e.type === r.ANY || e.type === r.A || e.type === r.AAAA || e.type === r.SRV || e.type === r.TXT || e.type === r.PTR)(e) && (s === t.host || s === t.fqdnIn);
|
|
})) {
|
|
return 0;
|
|
}
|
|
const a = ((e, t) => {
|
|
e.sort(compareAnswers);
|
|
t.sort(compareAnswers);
|
|
const s = e.length < t.length ? e.length : t.length;
|
|
for (let n = 0; n < s; n++) {
|
|
const s = compareAnswers(e[n], t[n]);
|
|
if (0 !== s) {
|
|
return s;
|
|
}
|
|
}
|
|
return e.length !== t.length ? e.length < t.length ? -1 : 1 : 0;
|
|
})(authorities(t, s, t.ttl), e.authorities.filter(e => e.name?.toLowerCase() === t.host || e.name?.toLowerCase() === t.fqdnIn));
|
|
if (a < 0) {
|
|
return checkAnswerConflicts(e.authorities, t, s);
|
|
} else {
|
|
return 0;
|
|
}
|
|
})(a, d, y.bindings);
|
|
h |= 0 !== e ? 8 | e : 0;
|
|
} else if (a.type === n.RESPONSE) {
|
|
h |= checkResponseConflicts(a, d, y.bindings);
|
|
}
|
|
} else if (2 === u) {
|
|
h = checkResponseConflicts(a, d, y.bindings);
|
|
if (resolveConflicts()) {
|
|
u = 0;
|
|
} else {
|
|
try {
|
|
await async function sendReply(e, t) {
|
|
const s = responseMessage(e, d, y.bindings, !1);
|
|
const n = responseMessage(e, d, y.bindings, !0);
|
|
await Promise.all([ s && c.schedule(0, () => t.reply(s)), n && c.schedule(0, () => y.send(n)) ]);
|
|
}(a, t);
|
|
} catch (e) {
|
|
if (!AbortError.isAbortError(e)) {
|
|
s.onError(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
async function sendAnnouncement() {
|
|
const e = ((e, t) => encode({
|
|
type: n.RESPONSE,
|
|
flags: i.AUTHORITATIVE_ANSWER,
|
|
answers: answers(e, t, e.ttl)
|
|
}))(d, y.bindings);
|
|
await c.schedule(0, () => y.send(e));
|
|
}
|
|
function resolveConflicts() {
|
|
if (0 !== h) {
|
|
if (1 & h) {
|
|
o.nameSeed++;
|
|
}
|
|
if (6 & h) {
|
|
o.hostnameSeed++;
|
|
}
|
|
d = s.createServiceRecord(o);
|
|
h = 0;
|
|
return !0;
|
|
} else {
|
|
return !1;
|
|
}
|
|
}
|
|
function next() {
|
|
switch (u) {
|
|
case 0:
|
|
return async function probe() {
|
|
f = 0;
|
|
l = 0;
|
|
h = 0;
|
|
let e = 3;
|
|
await c.schedule(1, async t => {
|
|
const s = 8 & h;
|
|
if (y.closed) {
|
|
u = 3;
|
|
return;
|
|
} else if (0 !== u) {
|
|
return;
|
|
} else if (resolveConflicts()) {
|
|
e += 4;
|
|
if (++f < 15) {
|
|
return t.retry(s ? 1e3 : void 0);
|
|
} else {
|
|
u = 3;
|
|
}
|
|
} else if (t.attempt < e) {
|
|
await async function sendProbe() {
|
|
const e = ((e, t) => encode({
|
|
type: n.QUERY,
|
|
questions: [ {
|
|
name: e.fqdnOut,
|
|
type: r.ANY,
|
|
class: a.IN,
|
|
qu: !0
|
|
}, {
|
|
name: e.host,
|
|
type: r.ANY,
|
|
class: a.IN,
|
|
qu: !0
|
|
} ],
|
|
authorities: authorities(e, t, e.ttl)
|
|
}))(d, y.bindings);
|
|
await c.schedule(0, () => y.send(e));
|
|
}();
|
|
return t.retry();
|
|
} else {
|
|
u = l ? 0 === h ? 2 : 3 : u = 3;
|
|
}
|
|
});
|
|
return next();
|
|
}();
|
|
|
|
case 2:
|
|
return async function announce() {
|
|
while (2 === u && !y.closed) {
|
|
if (!await c.schedule(2, async e => {
|
|
if (2 !== u) {
|
|
return !1;
|
|
} else if (e.attempt > 2 && y.refresh()) {
|
|
return !0;
|
|
}
|
|
if (!y.closed) {
|
|
await sendAnnouncement();
|
|
if (e.attempt < 3) {
|
|
return e.retry();
|
|
}
|
|
}
|
|
return !1;
|
|
})) {
|
|
await c.schedule(3, async e => {
|
|
if (2 !== u) {
|
|
return;
|
|
} else if (!y.refresh() && !y.closed) {
|
|
return e.retry();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return next();
|
|
}();
|
|
|
|
case 3:
|
|
return async function reopen() {
|
|
c.cancel();
|
|
while (3 === u && f < 15) {
|
|
f++;
|
|
await c.schedule(3, async e => {
|
|
if (3 !== u) {
|
|
return;
|
|
}
|
|
if (!y.refresh() || y.closed) {
|
|
return e.retry();
|
|
}
|
|
u = 0;
|
|
});
|
|
}
|
|
return next();
|
|
}();
|
|
}
|
|
}
|
|
let g = !1;
|
|
return {
|
|
promise: (async () => {
|
|
try {
|
|
u = 0;
|
|
await next();
|
|
c.cancel();
|
|
} catch (e) {
|
|
if (!AbortError.isAbortError(e)) {
|
|
s.onError(e);
|
|
}
|
|
} finally {
|
|
if (!g) {
|
|
y.close();
|
|
c.cancel();
|
|
}
|
|
}
|
|
})(),
|
|
async close() {
|
|
try {
|
|
g = !0;
|
|
c.cancel();
|
|
if (3 !== u) {
|
|
u = 3;
|
|
await async function sendGoodbye() {
|
|
const e = ((e, t) => encode({
|
|
type: n.RESPONSE,
|
|
flags: i.AUTHORITATIVE_ANSWER,
|
|
answers: answers(e, t, 0)
|
|
}))(d, y.bindings);
|
|
await c.schedule(0, () => y.send(e));
|
|
}();
|
|
}
|
|
} catch (e) {
|
|
if (!AbortError.isAbortError(e)) {
|
|
s.onError(e);
|
|
}
|
|
} finally {
|
|
c.cancel();
|
|
y.close();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function advertise(e) {
|
|
let t = null;
|
|
if ("IPv4" === e.stack) {
|
|
t = "IPv4";
|
|
} else if ("IPv6" === e.stack) {
|
|
t = "IPv6";
|
|
}
|
|
return function advertiseInternal(e, t) {
|
|
const s = new Set(t.networkInterfaceNames());
|
|
const n = new Map;
|
|
const r = t.createScheduler();
|
|
for (const r of s) {
|
|
n.set(r, createInterfaceAdvertiser(r, e, t));
|
|
}
|
|
r.schedule(3, s => {
|
|
try {
|
|
const s = new Set(t.networkInterfaceNames());
|
|
for (const r of s) {
|
|
if (!n.has(r)) {
|
|
n.set(r, createInterfaceAdvertiser(r, e, t));
|
|
}
|
|
}
|
|
for (const [e, t] of n) {
|
|
if (!s.has(e)) {
|
|
n.delete(e);
|
|
t.close();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (!AbortError.isAbortError(e)) {
|
|
t.onError(e);
|
|
}
|
|
}
|
|
return s.retry();
|
|
}).catch(e => {
|
|
if (!AbortError.isAbortError(e)) {
|
|
t.onError(e);
|
|
}
|
|
});
|
|
return async () => {
|
|
r.cancel();
|
|
try {
|
|
await Promise.all([ ...n.values() ].map(e => e.close()));
|
|
} catch (e) {
|
|
if (!AbortError.isAbortError(e)) {
|
|
t.onError(e);
|
|
}
|
|
}
|
|
};
|
|
}({
|
|
name: e.name,
|
|
type: e.type,
|
|
protocol: e.protocol,
|
|
hostname: e.hostname || ue.hostname(),
|
|
port: e.port,
|
|
subtypes: e.subtypes || [],
|
|
txt: e.txt || {},
|
|
ttl: e.ttl || 120,
|
|
stack: t
|
|
}, ue);
|
|
}
|
|
|
|
export { advertise };
|
|
//# sourceMappingURL=dnssd-advertise.mjs.map
|