cf-doh
Version:
Typed Cloudflare DNS Over HTTP Resolver
278 lines (277 loc) • 14.4 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setFetch = exports.queryDNS = exports.queryDNSRecords = exports.DOHError = exports.DNSRecordType = exports.DOHStatusMessage = exports.DOHStatus = void 0;
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
var DOHStatus;
(function (DOHStatus) {
DOHStatus[DOHStatus["NoError"] = 0] = "NoError";
DOHStatus[DOHStatus["FormErr"] = 1] = "FormErr";
DOHStatus[DOHStatus["ServFail"] = 2] = "ServFail";
DOHStatus[DOHStatus["NXDomain"] = 3] = "NXDomain";
DOHStatus[DOHStatus["NotImp"] = 4] = "NotImp";
DOHStatus[DOHStatus["Refused"] = 5] = "Refused";
DOHStatus[DOHStatus["YXDomain"] = 6] = "YXDomain";
DOHStatus[DOHStatus["YXRRSet"] = 7] = "YXRRSet";
DOHStatus[DOHStatus["NXRRSet"] = 8] = "NXRRSet";
DOHStatus[DOHStatus["NotAuth"] = 9] = "NotAuth";
// NotAuth = 9, // Not Authorized [RFC8945]
DOHStatus[DOHStatus["NotZone"] = 10] = "NotZone";
DOHStatus[DOHStatus["DSOTYPENI"] = 11] = "DSOTYPENI";
// 12-15 Unassigned
DOHStatus[DOHStatus["BADVERS"] = 16] = "BADVERS";
DOHStatus[DOHStatus["BADSIG"] = 16] = "BADSIG";
DOHStatus[DOHStatus["BADKEY"] = 17] = "BADKEY";
DOHStatus[DOHStatus["BADTIME"] = 18] = "BADTIME";
DOHStatus[DOHStatus["BADMODE"] = 19] = "BADMODE";
DOHStatus[DOHStatus["BADNAME"] = 20] = "BADNAME";
DOHStatus[DOHStatus["BADALG"] = 21] = "BADALG";
DOHStatus[DOHStatus["BADTRUNC"] = 22] = "BADTRUNC";
DOHStatus[DOHStatus["BADCOOKIE"] = 23] = "BADCOOKIE";
// 24-3840 Unassigned
// 3841-4095 Reserved for Private Use [RFC6895]
// 4096-65534 Unassigned
// 65535 Reserved, can be allocated by Standards Action [RFC6895]
})(DOHStatus || (exports.DOHStatus = DOHStatus = {}));
exports.DOHStatusMessage = (_a = {},
_a[DOHStatus.NoError] = "No Error [RFC1035]",
_a[DOHStatus.FormErr] = "Format Error [RFC1035]",
_a[DOHStatus.ServFail] = "Server Failure [RFC1035]",
_a[DOHStatus.NXDomain] = "Non-Existent Domain [RFC1035]",
_a[DOHStatus.NotImp] = "Not Implemented [RFC1035]",
_a[DOHStatus.Refused] = "Query Refused [RFC1035]",
_a[DOHStatus.YXDomain] = "Name Exists when it should not [RFC2136][RFC6672]",
_a[DOHStatus.YXRRSet] = "RR Set Exists when it should not [RFC2136]",
_a[DOHStatus.NXRRSet] = "RR Set that should exist does not [RFC2136]",
_a[DOHStatus.NotAuth] = "Server Not Authoritative for zone [RFC2136] or Not Authorized [RFC8945]",
_a[DOHStatus.NotZone] = "Name not contained in zone [RFC2136]",
_a[DOHStatus.DSOTYPENI] = "DSO-TYPE Not Implemented [RFC8490]",
_a[DOHStatus.BADSIG] = "TSIG Signature Failure [RFC8945] or Bad OPT Version [RFC6891]",
_a[DOHStatus.BADKEY] = "Key not recognized [RFC8945]",
_a[DOHStatus.BADTIME] = "Signature out of time window [RFC8945]",
_a[DOHStatus.BADMODE] = "Bad TKEY Mode [RFC2930]",
_a[DOHStatus.BADNAME] = "Duplicate key name [RFC2930]",
_a[DOHStatus.BADALG] = "Algorithm not supported [RFC2930]",
_a[DOHStatus.BADTRUNC] = "Bad Truncation [RFC8945]",
_a[DOHStatus.BADCOOKIE] = "Bad/missing Server Cookie [RFC7873]",
_a);
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
var DNSRecordType;
(function (DNSRecordType) {
DNSRecordType[DNSRecordType["Reserved"] = 0] = "Reserved";
DNSRecordType[DNSRecordType["A"] = 1] = "A";
DNSRecordType[DNSRecordType["NS"] = 2] = "NS";
DNSRecordType[DNSRecordType["MD"] = 3] = "MD";
DNSRecordType[DNSRecordType["MF"] = 4] = "MF";
DNSRecordType[DNSRecordType["CNAME"] = 5] = "CNAME";
DNSRecordType[DNSRecordType["SOA"] = 6] = "SOA";
DNSRecordType[DNSRecordType["MB"] = 7] = "MB";
DNSRecordType[DNSRecordType["MG"] = 8] = "MG";
DNSRecordType[DNSRecordType["MR"] = 9] = "MR";
DNSRecordType[DNSRecordType["NULL"] = 10] = "NULL";
DNSRecordType[DNSRecordType["WKS"] = 11] = "WKS";
DNSRecordType[DNSRecordType["PTR"] = 12] = "PTR";
DNSRecordType[DNSRecordType["HINFO"] = 13] = "HINFO";
DNSRecordType[DNSRecordType["MINFO"] = 14] = "MINFO";
DNSRecordType[DNSRecordType["MX"] = 15] = "MX";
DNSRecordType[DNSRecordType["TXT"] = 16] = "TXT";
DNSRecordType[DNSRecordType["RP"] = 17] = "RP";
DNSRecordType[DNSRecordType["AFSDB"] = 18] = "AFSDB";
DNSRecordType[DNSRecordType["X25"] = 19] = "X25";
DNSRecordType[DNSRecordType["ISDN"] = 20] = "ISDN";
DNSRecordType[DNSRecordType["RT"] = 21] = "RT";
DNSRecordType[DNSRecordType["NSAP"] = 22] = "NSAP";
DNSRecordType[DNSRecordType["NSAP-PTR"] = 23] = "NSAP-PTR";
DNSRecordType[DNSRecordType["SIG"] = 24] = "SIG";
DNSRecordType[DNSRecordType["KEY"] = 25] = "KEY";
DNSRecordType[DNSRecordType["PX"] = 26] = "PX";
DNSRecordType[DNSRecordType["GPOS"] = 27] = "GPOS";
DNSRecordType[DNSRecordType["AAAA"] = 28] = "AAAA";
DNSRecordType[DNSRecordType["LOC"] = 29] = "LOC";
DNSRecordType[DNSRecordType["NXT"] = 30] = "NXT";
DNSRecordType[DNSRecordType["EID"] = 31] = "EID";
DNSRecordType[DNSRecordType["NIMLOC"] = 32] = "NIMLOC";
DNSRecordType[DNSRecordType["SRV"] = 33] = "SRV";
DNSRecordType[DNSRecordType["ATMA"] = 34] = "ATMA";
DNSRecordType[DNSRecordType["NAPTR"] = 35] = "NAPTR";
DNSRecordType[DNSRecordType["KX"] = 36] = "KX";
DNSRecordType[DNSRecordType["CERT"] = 37] = "CERT";
DNSRecordType[DNSRecordType["A6"] = 38] = "A6";
DNSRecordType[DNSRecordType["DNAME"] = 39] = "DNAME";
DNSRecordType[DNSRecordType["SINK"] = 40] = "SINK";
DNSRecordType[DNSRecordType["OPT"] = 41] = "OPT";
DNSRecordType[DNSRecordType["APL"] = 42] = "APL";
DNSRecordType[DNSRecordType["DS"] = 43] = "DS";
DNSRecordType[DNSRecordType["SSHFP"] = 44] = "SSHFP";
DNSRecordType[DNSRecordType["IPSECKEY"] = 45] = "IPSECKEY";
DNSRecordType[DNSRecordType["RRSIG"] = 46] = "RRSIG";
DNSRecordType[DNSRecordType["NSEC"] = 47] = "NSEC";
DNSRecordType[DNSRecordType["DNSKEY"] = 48] = "DNSKEY";
DNSRecordType[DNSRecordType["DHCID"] = 49] = "DHCID";
DNSRecordType[DNSRecordType["NSEC3"] = 50] = "NSEC3";
DNSRecordType[DNSRecordType["NSEC3PARAM"] = 51] = "NSEC3PARAM";
DNSRecordType[DNSRecordType["TLSA"] = 52] = "TLSA";
DNSRecordType[DNSRecordType["SMIMEA"] = 53] = "SMIMEA";
// 54 Unassigned
DNSRecordType[DNSRecordType["HIP"] = 55] = "HIP";
DNSRecordType[DNSRecordType["NINFO"] = 56] = "NINFO";
DNSRecordType[DNSRecordType["RKEY"] = 57] = "RKEY";
DNSRecordType[DNSRecordType["TALINK"] = 58] = "TALINK";
DNSRecordType[DNSRecordType["CDS"] = 59] = "CDS";
DNSRecordType[DNSRecordType["CDNSKEY"] = 60] = "CDNSKEY";
DNSRecordType[DNSRecordType["OPENPGPKEY"] = 61] = "OPENPGPKEY";
DNSRecordType[DNSRecordType["CSYNC"] = 62] = "CSYNC";
DNSRecordType[DNSRecordType["ZONEMD"] = 63] = "ZONEMD";
DNSRecordType[DNSRecordType["SVCB"] = 64] = "SVCB";
DNSRecordType[DNSRecordType["HTTPS"] = 65] = "HTTPS";
// 66-98 Unassigned
DNSRecordType[DNSRecordType["SPF"] = 99] = "SPF";
DNSRecordType[DNSRecordType["UINFO"] = 100] = "UINFO";
DNSRecordType[DNSRecordType["UID"] = 101] = "UID";
DNSRecordType[DNSRecordType["GID"] = 102] = "GID";
DNSRecordType[DNSRecordType["UNSPEC"] = 103] = "UNSPEC";
DNSRecordType[DNSRecordType["NID"] = 104] = "NID";
DNSRecordType[DNSRecordType["L32"] = 105] = "L32";
DNSRecordType[DNSRecordType["L64"] = 106] = "L64";
DNSRecordType[DNSRecordType["LP"] = 107] = "LP";
DNSRecordType[DNSRecordType["EUI48"] = 108] = "EUI48";
DNSRecordType[DNSRecordType["EUI64"] = 109] = "EUI64";
// 110-248 Unassigned
DNSRecordType[DNSRecordType["TKEY"] = 249] = "TKEY";
DNSRecordType[DNSRecordType["TSIG"] = 250] = "TSIG";
DNSRecordType[DNSRecordType["IXFR"] = 251] = "IXFR";
DNSRecordType[DNSRecordType["AXFR"] = 252] = "AXFR";
DNSRecordType[DNSRecordType["MAILB"] = 253] = "MAILB";
DNSRecordType[DNSRecordType["MAILA"] = 254] = "MAILA";
DNSRecordType[DNSRecordType["ANY"] = 255] = "ANY";
DNSRecordType[DNSRecordType["URI"] = 256] = "URI";
DNSRecordType[DNSRecordType["CAA"] = 257] = "CAA";
DNSRecordType[DNSRecordType["AVC"] = 258] = "AVC";
DNSRecordType[DNSRecordType["DOA"] = 259] = "DOA";
DNSRecordType[DNSRecordType["AMTRELAY"] = 260] = "AMTRELAY";
DNSRecordType[DNSRecordType["RESINFO"] = 261] = "RESINFO";
// 262-32767 Unassigned
DNSRecordType[DNSRecordType["TA"] = 32768] = "TA";
DNSRecordType[DNSRecordType["DLV"] = 32769] = "DLV";
// 32770-65279 Unassigned
// 65280-65534 Private use
// 65535 Reserved
})(DNSRecordType || (exports.DNSRecordType = DNSRecordType = {}));
var DOHError = /** @class */ (function () {
function DOHError(response) {
this.response = response;
this.message = exports.DOHStatusMessage[response.Status];
}
return DOHError;
}());
exports.DOHError = DOHError;
var queryDNSRecords = function (hostname, recordType) { return __awaiter(void 0, void 0, void 0, function () {
var r, b, e_1, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!_fetchImpl) {
throw new Error("Native fetch implementation not found, call setFetch with a fetch implementation before using cf-doh.");
}
return [4 /*yield*/, _fetchImpl("https://1.1.1.1/dns-query?name=".concat(hostname, "&type=").concat(recordType), {
headers: { Accept: "application/dns-json" },
})];
case 1:
r = _a.sent();
if (!!r.ok) return [3 /*break*/, 6];
b = "[binary data]";
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, r.text()];
case 3:
b = _a.sent();
return [3 /*break*/, 5];
case 4:
e_1 = _a.sent();
b = "Failed parsing, ".concat(e_1);
return [3 /*break*/, 5];
case 5: throw new Error("DoH request failed: [".concat(r.status, "] (").concat(b, ")"));
case 6: return [4 /*yield*/, r.json()];
case 7:
response = _a.sent();
if (typeof response.Status !== "number") {
throw new Error("Cloudflare returned and unexpected DoH response: ".concat(JSON.stringify(response)));
}
return [2 /*return*/, response];
}
});
}); };
exports.queryDNSRecords = queryDNSRecords;
var queryDNS = function (hostname, recordType) { return __awaiter(void 0, void 0, void 0, function () {
var r;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, (0, exports.queryDNSRecords)(hostname, recordType)];
case 1:
r = _a.sent();
if (r.Status !== DOHStatus.NoError) {
throw new DOHError(r);
}
return [2 /*return*/, r.Answer
? r.Answer.map(function (r) {
try {
// Text records are returned wrapped in quotes, parse them to strip the quotes
return JSON.parse(r.data);
}
catch (e) {
return r.data;
}
})
: []];
}
});
}); };
exports.queryDNS = queryDNS;
var _fetchImpl;
var setFetch = function (fetchImpl) {
_fetchImpl = fetchImpl;
};
exports.setFetch = setFetch;
if (typeof fetch !== "undefined") {
(0, exports.setFetch)(fetch);
}
else if (typeof self !== "undefined" && self.fetch) {
(0, exports.setFetch)(fetch);
}