Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Runs load_libresolv.lookup() against crafted DNS responses, with
* res_search() replaced by a stub, and posts the results back.
* The unixstyle of the OS is passed as the query string.
*/
import { load_libresolv } from "resource:///modules/DNS.worker.mjs";
const NS_T_MX = 15;
const NS_T_SRV = 33;
const QNAME = "a".repeat(42) + ".com";
function encodeName(domain) {
const bytes = [];
for (const label of domain.split(".")) {
bytes.push(label.length, ...Array.from(label, c => c.charCodeAt(0)));
}
bytes.push(0);
return bytes;
}
function u16(value) {
return [(value >> 8) & 0xff, value & 0xff];
}
/**
* @param {integer} type - The record type.
* @param {integer[][]} rdatas - The data of each answer record.
* @returns {integer[]} The DNS response.
*/
function buildResponse(type, rdatas) {
const bytes = [
...u16(0),
...u16(0x8180),
...u16(1),
...u16(rdatas.length),
...u16(0),
...u16(0),
...encodeName(QNAME),
...u16(type),
...u16(1),
];
for (const rdata of rdatas) {
bytes.push(
0xc0,
0x0c,
...u16(type),
...u16(1),
0,
0,
0x01,
0x2c,
...u16(rdata.length),
...rdata
);
}
return bytes;
}
function mxData(index) {
return [...u16(index), ...encodeName(`mx${index}.example.com`)];
}
function mxRecords(count) {
return Array.from({ length: count }, (_, i) => mxData(10 + i));
}
/**
* @param {integer} type - The record type to look up.
* @param {integer[]} response - The response res_search() should return.
* @param {integer} [bufferSize] - Override for the answer buffer size.
* @returns {object} The records, or the error message.
*/
function lookup(type, response, bufferSize) {
const dns = new load_libresolv(self.location.search.slice(1));
if (bufferSize) {
dns.QUERYBUF_SIZE = bufferSize;
}
dns.res_search = (qname, nsclass, typeID, answer, anslen) => {
const count = Math.min(response.length, anslen);
for (let i = 0; i < count; i++) {
answer[i] = response[i];
}
return response.length;
};
try {
return { records: dns.lookup(QNAME, type) };
} catch (e) {
return { error: e.message };
} finally {
dns.close();
}
}
self.postMessage({
large: lookup(NS_T_MX, buildResponse(NS_T_MX, mxRecords(40))),
exactBuffer: lookup(NS_T_MX, buildResponse(NS_T_MX, mxRecords(30)), 1024),
truncated: lookup(NS_T_MX, buildResponse(NS_T_MX, mxRecords(40)), 1024),
shortMX: lookup(NS_T_MX, buildResponse(NS_T_MX, [u16(10), mxData(20)])),
badPointerMX: lookup(
NS_T_MX,
buildResponse(NS_T_MX, [[...u16(10), 0xc3, 0xff]])
),
badPointerSRV: lookup(
NS_T_SRV,
buildResponse(NS_T_SRV, [[...u16(10), ...u16(20), ...u16(443), 0xc3, 0xff]])
),
shortSRV: lookup(
NS_T_SRV,
buildResponse(NS_T_SRV, [[...u16(10), ...u16(20), ...u16(443)]])
),
});