/* 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 */ const beginningOfTime = 1262304000; // Jan 01 2010, 00:00 const endOfTime = 2147483647; // Jan 19, 2038, 03:14 var from = beginningOfTime; var until = endOfTime; var dateformat = "MMMM 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), endDate: moment(until * 1000), 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), moment(endOfTime)], }, opens: "center", showDropdowns: true, autoUpdateInput: true, }, function (startt, endt) { 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, isCNAME = false, regexLink = false; switch (data.status) { case "GRAVITY": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (gravity)"; buttontext = ''; break; case "FORWARDED": colorClass = "text-green"; icon = "fa-solid fa-cloud-download-alt"; fieldtext = "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)"; regexLink = data.regex > 0; buttontext = ''; break; case "DENYLIST": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (exact)"; buttontext = ''; break; case "EXTERNAL_BLOCKED_IP": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, IP)"; buttontext = ""; break; case "EXTERNAL_BLOCKED_NULL": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, NULL)"; buttontext = ""; break; case "EXTERNAL_BLOCKED_NXRA": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (external, NXRA)"; buttontext = ""; break; case "GRAVITY_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (gravity, CNAME)"; buttontext = ''; isCNAME = true; break; case "REGEX_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (regex diened, CNAME)"; regexLink = data.regex > 0; buttontext = ''; isCNAME = true; break; case "DENYLIST_CNAME": colorClass = "text-red"; icon = "fa-solid fa-ban"; fieldtext = "Blocked (exact diened, CNAME)"; buttontext = ''; isCNAME = 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; default: colorClass = "text-orange"; icon = "fa-solid fa-question"; fieldtext = data.status; buttontext = ""; } return { fieldtext: fieldtext, buttontext: buttontext, colorClass: colorClass, icon: icon, isCNAME: isCNAME, regexLink: regexLink, }; } function formatInfo(data) { // DNSSEC status var dnssecStatus = data.dnssec, dnssecClass; switch (data.dnssec) { case "SECURE": dnssecClass = "text-green"; break; case "INSECURE": dnssecClass = "text-orange"; break; case "BOGUS": dnssecClass = "text-red"; break; case "ABANDONED": dnssecClass = "text-red"; break; default: // No DNSSEC or UNKNOWN dnssecStatus = "N/A"; dnssecClass = false; } // Parse Query Status var queryStatus = parseQueryStatus(data); var divStart = '
'; var statusInfo = ""; if (queryStatus.colorClass !== false) { statusInfo = divStart + "Query Status:  " + '' + queryStatus.fieldtext + "
"; } var regexInfo = "", cnameInfo = ""; if (queryStatus.regexLink) { var regexLink = 'Regex ID ' + data.regex + ""; regexInfo = divStart + "Query was blocked by:" + regexLink + ""; } 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 (dnssecClass !== false) { dnssecInfo = divStart + 'DNSSEC status:  ' + dnssecStatus + ""; } // 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 = ""; if (data.reply.type !== "UNKNOWN") { replyInfo = divStart + "Reply:  " + data.reply.type; if (data.reply.time >= 0 && data.reply.type !== "UNKNOWN") { replyInfo += " (" + (data.reply.time < 1 ? (1e3 * data.reply.time).toFixed(1) + " ms)" : data.reply.time.toFixed(1) + " s)"); } replyInfo += ""; } else { replyInfo = divStart + "Reply:  No reply received"; } // 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 + statusInfo + cnameInfo + regexInfo + 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 //