UNPKG

cf-doh

Version:

Typed Cloudflare DNS Over HTTP Resolver

278 lines (277 loc) 14.4 kB
"use strict"; 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); }