/* Pi-hole: A black hole for Internet advertisements * (c) 2017 Pi-hole, LLC (https://pi-hole.net) * Network-wide ad blocking via your own hardware. * * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ /* global moment:false, utils:false, REFRESH_INTERVAL:false */ const beginningOfTime = 1262304000; // Jan 01 2010, 00:00 in seconds const endOfTime = 2147483647; // Jan 19, 2038, 03:14 in seconds var from = beginningOfTime; var until = endOfTime; var dateformat = "MMM Do YYYY, HH:mm"; var table = null; var cursor = null; var filters = [ "client_ip", "client_name", "domain", "upstream", "type", "status", "reply", "dnssec", ]; function initDateRangePicker() { $("#querytime").daterangepicker( { timePicker: true, timePickerIncrement: 5, timePicker24Hour: true, locale: { format: dateformat }, startDate: moment(from * 1000), // convert to milliseconds since epoch endDate: moment(until * 1000), // convert to milliseconds since epoch ranges: { "Last 10 Minutes": [moment().subtract(10, "minutes"), moment()], "Last Hour": [moment().subtract(1, "hours"), moment()], Today: [moment().startOf("day"), moment().endOf("day")], Yesterday: [ moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day"), ], "Last 7 Days": [moment().subtract(6, "days"), moment().endOf("day")], "Last 30 Days": [moment().subtract(29, "days"), moment().endOf("day")], "This Month": [moment().startOf("month"), moment().endOf("month")], "Last Month": [ moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month"), ], "This Year": [moment().startOf("year"), moment().endOf("year")], "All Time": [moment(beginningOfTime * 1000), moment(endOfTime * 1000)], // convert to milliseconds since epoch }, opens: "center", showDropdowns: true, autoUpdateInput: true, }, function (startt, endt) { // Update global variables // Convert milliseconds (JS) to seconds (API) from = moment(startt).utc().valueOf() / 1000; until = moment(endt).utc().valueOf() / 1000; } ); } function handleAjaxError(xhr, textStatus) { if (textStatus === "timeout") { alert("The server took too long to send the data."); } else { alert("An unknown error occurred while loading the data.\n" + xhr.responseText); } $("#all-queries_processing").hide(); table.clear(); table.draw(); } function parseQueryStatus(data) { // Parse query status var fieldtext, buttontext, icon = null, colorClass = false, blocked = false, isCNAME = false; switch (data.status) { case "GRAVITY": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (gravity)"; buttontext = ''; blocked = true; break; case "FORWARDED": colorClass = "text-green"; icon = "fa-solid fa-cloud-download-alt"; fieldtext = (data.reply.type !== "UNKNOWN" ? "Forwarded, reply from " : "Forwarded to ") + data.upstream; buttontext = ''; break; case "CACHE": colorClass = "text-green"; icon = "fa-solid fa-database"; fieldtext = "Served from cache"; buttontext = ''; break; case "REGEX": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (regex)"; buttontext = ''; blocked = true; break; case "DENYLIST": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (exact)"; buttontext = ''; blocked = true; break; case "EXTERNAL_BLOCKED_IP": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, IP)"; buttontext = ""; blocked = true; break; case "EXTERNAL_BLOCKED_NULL": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, NULL)"; buttontext = ""; blocked = true; break; case "EXTERNAL_BLOCKED_NXRA": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, NXRA)"; buttontext = ""; blocked = true; break; case "GRAVITY_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (gravity, CNAME)"; buttontext = ''; isCNAME = true; blocked = true; break; case "REGEX_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (regex denied, CNAME)"; buttontext = ''; isCNAME = true; blocked = true; break; case "DENYLIST_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (exact denied, CNAME)"; buttontext = ''; isCNAME = true; blocked = true; break; case "RETRIED": colorClass = "text-green"; icon = "fa-solid fa-redo"; // fa-repeat fieldtext = "Retried"; buttontext = ""; break; case "RETRIED_DNSSEC": colorClass = "text-green"; icon = "fa-solid fa-redo"; // fa-repeat fieldtext = "Retried (ignored)"; buttontext = ""; break; case "IN_PROGRESS": colorClass = "text-green"; icon = "fa-solid fa-hourglass-half"; fieldtext = "Already forwarded, awaiting reply"; buttontext = ''; break; case "CACHE_STALE": colorClass = "text-green"; icon = "fa-solid fa-infinity"; fieldtext = "Served by cache optimizer"; buttontext = ''; break; case "SPECIAL_DOMAIN": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = data.status; buttontext = ""; blocked = true; break; default: colorClass = "text-orange"; icon = "fa-solid fa-question"; fieldtext = data.status; buttontext = ""; } var matchText = colorClass === "text-green" ? "allowed" : colorClass === "text-red" ? "blocked" : "matched"; return { fieldtext: fieldtext, buttontext: buttontext, colorClass: colorClass, icon: icon, isCNAME: isCNAME, matchText: matchText, blocked: blocked, }; } function formatReplyTime(replyTime, type) { if (type === "display") { // Units: // - seconds if replytime >= 1 second // - milliseconds if reply time >= 100 µs // - microseconds otherwise return replyTime < 1e-4 ? (1e6 * replyTime).toFixed(1) + " µs" : replyTime < 1 ? (1e3 * replyTime).toFixed(1) + " ms" : replyTime.toFixed(1) + " s"; } // else: return the number itself (for sorting and searching) return replyTime; } // Parse DNSSEC status function parseDNSSEC(data) { var icon = "", // Icon to display color = "", // Class to apply to text text = data.dnssec; // Text to display switch (text) { case "SECURE": icon = "fa-solid fa-lock"; color = "text-green"; break; case "INSECURE": icon = "fa-solid fa-lock-open"; color = "text-orange"; break; case "BOGUS": icon = "fa-solid fa-exclamation-triangle"; color = "text-red"; break; case "ABANDONED": icon = "fa-solid fa-exclamation-triangle"; color = "text-red"; break; default: // No DNSSEC or UNKNOWN text = "N/A"; color = ""; icon = ""; } return { text: text, icon: icon, color: color }; } function formatInfo(data) { // Parse Query Status var dnssec = parseDNSSEC(data); var queryStatus = parseQueryStatus(data); var divStart = '
'; var statusInfo = ""; if (queryStatus.colorClass !== false) { statusInfo = divStart + "Query Status:  " + '' + queryStatus.fieldtext + "
"; } var listInfo = "", cnameInfo = ""; if (data.list_id !== null && data.list_id !== -1) { // Some list matched - add link to search page var listLink = 'search lists'; listInfo = divStart + "Query was " + queryStatus.matchText + ", " + listLink + ""; } if (queryStatus.isCNAME) { cnameInfo = divStart + "Query was blocked during CNAME inspection of  " + data.cname + ""; } // Show TTL if applicable var ttlInfo = ""; if (data.ttl > 0) { ttlInfo = divStart + "Time-to-live (TTL):  " + moment.duration(data.ttl, "s").humanize() + " (" + data.ttl + "s)"; } // Show client information, show hostname only if available var ipInfo = data.client.name !== null && data.client.name.length > 0 ? utils.escapeHtml(data.client.name) + " (" + data.client.ip + ")" : data.client.ip; var clientInfo = divStart + "Client:  " + ipInfo + ""; // Show DNSSEC status if applicable var dnssecInfo = ""; if (dnssec.color !== "") { dnssecInfo = divStart + 'DNSSEC status:  ' + dnssec.text + ""; } // Show long-term database information if applicable var dbInfo = ""; if (data.dbid !== false) { dbInfo = divStart + "Database ID:  " + data.id + ""; } // Always show reply info, add reply delay if applicable var replyInfo = ""; replyInfo = data.reply.type !== "UNKNOWN" ? divStart + "Reply:  " + data.reply.type + "" : divStart + "Reply:  No reply received"; // Show extended DNS error if applicable var edeInfo = ""; if (data.ede !== null && data.ede.text !== null) { edeInfo = divStart + "Extended DNS error:  "; } // Compile extra info for displaying return ( '
' + divStart + "Query received on:  " + moment.unix(data.time).format("Y-MM-DD HH:mm:ss.SSS z") + "
" + clientInfo + dnssecInfo + edeInfo + statusInfo + cnameInfo + listInfo + ttlInfo + replyInfo + dbInfo + "" ); } function addSelectSuggestion(name, dict, data) { var obj = $("#" + name + "_filter"), value = ""; obj.empty(); // In order for the placeholder value to appear, we have to have a blank //