diff --git a/advanced/index.php b/advanced/index.php index a5545ea4..aca1ce3f 100644 --- a/advanced/index.php +++ b/advanced/index.php @@ -6,30 +6,21 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ -// Function to validate server name (Including underscores & IPv6) -ini_set("pcre.recursion_limit", 1500); -function validate_server_name($domain) { // Cr: http://stackoverflow.com/a/4694816 - if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return TRUE; - return (preg_match("/^([a-z\d]((-|_)*[a-z\d])*)(\.([a-z\d]((-|_)*[a-z\d])*))*$/i", $domain) // Valid chars check - && preg_match("/^.{1,253}$/", $domain) // Overall length check - && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain)); // Length of each label -} - -// Validate HTTP_HOST output -if (validate_server_name($_SERVER["HTTP_HOST"]) === TRUE) { - $serverName = $_SERVER["HTTP_HOST"]; -} else { - die("[ERROR]: HTTP_HOST header output does not appear to be valid: ".$_SERVER["HTTP_HOST"].""); -} +// Sanitise HTTP_HOST output +$serverName = htmlspecialchars($_SERVER["HTTP_HOST"]); // Get values from setupVars.conf -$setupVars = parse_ini_file("/etc/pihole/setupVars.conf"); -$svFQDN = (!empty($setupVars["FQDN"]) && validate_server_name($setupVars["FQDN"]) === TRUE) ? $setupVars["FQDN"] : ""; -$svPasswd = !empty($setupVars["WEBPASSWORD"]); -$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : ""; -unset($setupVars); +if (is_file("/etc/pihole/setupVars.conf")) { + $setupVars = parse_ini_file("/etc/pihole/setupVars.conf"); + $svFQDN = $setupVars["FQDN"]; + $svPasswd = !empty($setupVars["WEBPASSWORD"]); + $svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : ""; + unset($setupVars); +} else { + die("[ERROR] File not found: /etc/pihole/setupVars.conf"); +} -// Set landing page name, found within /var/www/html/pihole/ +// Set landing page location, found within /var/www/html/ $landPage = "../landing.php"; // Set empty array for hostnames to be accepted as self address for splash page @@ -40,14 +31,10 @@ if (!empty($svFQDN)) array_push($authorizedHosts, $svFQDN); // Append virtual hostname to $authorizedHosts if (!empty($_SERVER["VIRTUAL_HOST"])) { - if (validate_server_name($_SERVER["VIRTUAL_HOST"]) === TRUE) { - array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]); - } else { - die("[ERROR]: VIRTUAL_HOST header output does not appear to be valid: ".$_SERVER["VIRTUAL_HOST"].""); - } + array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]); } -// Set which extension types get rendered as "Website Blocked" (Including "" for index file extensions) +// Set which extension types render as Block Page (Including "" for index.wxyz) $validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", ""); // Get extension of current URL @@ -62,31 +49,33 @@ function setHeader($type = "x") { if (isset($type) && $type === "js") header("Content-Type: application/javascript"); } -// Determine block page redirect +// Determine block page redirect type if ($serverName === "pi.hole") { exit(header("Location: /admin")); } elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) { - // Show splash page or landing page when directly browsing via IP or auth'd hostname + // Set Splash Page output $splashPage = " $viewPort
Pi-hole: Your black hole for Internet advertisements "; - $pageType = is_file(getcwd()."/$landPage") ? include $landPage : "$splashPage"; + + // Render splash page or landing page when directly browsing via IP or auth'd hostname + $renderPage = is_file(getcwd()."/$landPage") ? include $landPage : "$splashPage"; unset($serverName, $svFQDN, $svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt, $viewPort); - exit($pageType); + exit($renderPage); } elseif ($currentUrlExt === "js") { - // Set Javascript redirect for blocked sources + // Serve dummy Javascript for blocked domains exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."'); } elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) { - // Set blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER (Presumably from iframe) + // Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER (e.g: an iframe of a blocked domain) exit(setHeader().' '); } elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) { - // Set svg image upon receiving non $validExtTypes URL extension or query string (Presumably not from an iframe) + // Serve SVG upon receiving non $validExtTypes URL extension or query string (e.g: not an iframe of a blocked domain) $blockImg = 'Blocked by Pi-hole'; exit(setHeader()." $viewPort @@ -94,89 +83,86 @@ if ($serverName === "pi.hole") { "); } -/* Start processing block page from here */ - -// Get Pi-hole core branch name -$phBranch = exec("cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD"); -if ($phBranch !== "master") { - error_reporting(E_ALL); - ini_set("display_errors", 1); - ini_set("display_startup_errors", 1); -} - -// Validate SERVER_IP output -if (filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP)) { - $serverAddr = $_SERVER["SERVER_ADDR"]; -} else { - die("[ERROR]: SERVER_IP header output does not appear to be valid: ".$_SERVER["SERVER_ADDR"].""); -} +/* Start processing Block Page from here */ // Determine placeholder text based off $svPasswd presence $wlPlaceHolder = empty($svPasswd) ? "No admin password set" : "Javascript disabled"; -// Get admin email address +// Define admin email address text $bpAskAdmin = !empty($svEmail) ? '' : ""; // Determine if at least one block list has been generated -if (empty(glob("/etc/pihole/list.0.*.domains"))) die("[ERROR]: There are no domain lists generated lists within /etc/pihole/! Please update gravity by running pihole -g, or repair Pi-hole using pihole -r."); +if (empty(glob("/etc/pihole/list.0.*.domains"))) + die("[ERROR] There are no domain lists generated lists within /etc/pihole/! Please update gravity by running pihole -g, or repair Pi-hole using pihole -r."); -// Get contents of adlist.list -$adLists = is_file("/etc/pihole/adlists.list") ? "/etc/pihole/adlists.list" : "/etc/pihole/adlists.default"; -if (!is_file($adLists)) die("[ERROR]: Unable to find file: $adLists"); +// Set location of adlists file +if (is_file("/etc/pihole/adlists.list")) { + $adLists = "/etc/pihole/adlists.list"; +} elseif (is_file("/etc/pihole/adlists.default")) { + $adLists = "/etc/pihole/adlists.default"; +} else { + die("[ERROR] File not found: /etc/pihole/adlists.list"); +} -// Get all URLs starting with "http" or "www" from $adLists and re-index array numerically +// Get all URLs starting with "http" or "www" from adlists and re-index array numerically $adlistsUrls = array_values(preg_grep("/(^http)|(^www)/i", file($adLists, FILE_IGNORE_NEW_LINES))); -if (empty($adlistsUrls)) die("[ERROR]: There are no adlist URL's found within $adLists"); -$adlistsCount = count($adlistsUrls) + 3; // +1 because array starts at 0, +2 for Blacklist & Wildcard lists + +if (empty($adlistsUrls)) + die("[ERROR]: There are no adlist URL's found within $adLists"); + +// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists) +$adlistsCount = count($adlistsUrls) + 3; // Get results of queryads.php exact search ini_set("default_socket_timeout", 3); function queryAds($serverName) { + // Determine the time it takes while querying adlists $preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]; - $queryAds = file("http://127.0.0.1/admin/scripts/pi-hole/php/queryads.php?domain=$serverName&exact", FILE_IGNORE_NEW_LINES); + $queryAds = file("http://127.0.0.1/admin/scripts/pi-hole/php/queryads.php?domain=$serverName&bp", FILE_IGNORE_NEW_LINES); + $queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds))); $queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime); + + // Exception Handling try { if ($queryTime >= ini_get("default_socket_timeout")) { throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)"); - } elseif ($queryAds[0][0] === ":") { - if (strpos($queryAds[0], "Invalid") !== FALSE) throw new Exception ("Invalid Domain ($serverName)"); - if (strpos($queryAds[0], "No exact") !== FALSE) return array("0" => "none"); + } elseif (!strpos($queryAds[0], ".") !== false) { + if (strpos($queryAds[0], "No exact results") !== FALSE) return array("0" => "none"); throw new Exception ("Unhandled error message ($queryAds[0])"); - } elseif ($queryAds[0][0] !== "/") { - throw new Exception ("Unexpected output ($queryAds[0])"); } return $queryAds; } catch (Exception $e) { return array("0" => "error", "1" => $e->getMessage()); } + } + $queryAds = queryAds($serverName); if ($queryAds[0] === "error") { die("[ERROR]: Unable to parse results from queryads.php: ".$queryAds[1].""); -} - -// Filter, sort, and count $queryAds array -if ($queryAds[0] !== "none") { - $queryAds = preg_replace("/(\/etc\/pihole\/)|(\/etc\/dnsmasq\.d\/)/", "", $queryAds); - $queryAds = preg_replace("/(^list\.)|(\..*domains)/", "", $queryAds); +} else { $featuredTotal = count($queryAds); + + // Place results into key => value array + $queryResults = null; + foreach ($queryAds as $str) { + $value = explode(" ", $str); + @$queryResults[$value[0]] .= "$value[1]"; + } } -// Determine if domain has been blacklisted or wildcarded -if ($queryAds[0] === "blacklist.txt") { - $intBlacklist = array("π" => $queryAds[0]); - $queryAds[0] = "π"; // Manually blacklisted sites do not have a number +// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked +if (strpos($queryAds[0], "blacklist") !== FALSE) { $notableFlagClass = "blacklist"; -} elseif ($queryAds[0] === "whitelist.txt") { - $intBlacklist = array("π" => $queryAds[0]); - $queryAds[0] = "π"; + $adlistsUrls = array("π" => substr($queryAds[0], 2)); +} elseif (strpos($queryAds[0], "whitelist") !== FALSE) { $notableFlagClass = "noblock"; + $adlistsUrls = array("π" => substr($queryAds[0], 2)); $wlInfo = "recentwl"; -} elseif ($queryAds[0] === "03-pihole-wildcard.conf") { - $intBlacklist = array("π" => $queryAds[0]); - $queryAds[0] = "π"; +} elseif (strpos($queryAds[0], "wildcard") !== FALSE) { $notableFlagClass = "wildcard"; + $adlistsUrls = array("π" => substr($queryAds[0], 2)); } elseif ($queryAds[0] === "none") { $featuredTotal = "0"; $notableFlagClass = "noblock"; @@ -190,38 +176,34 @@ if ($queryAds[0] === "blacklist.txt") { } } -// Merge $intBlacklist with $adlistsUrls if domain has been blacklisted or wildcarded -if (isset($intBlacklist)) $adlistsUrls = array_merge($intBlacklist, $adlistsUrls); - // Set #bpOutput notification $wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden"; $wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "$wlInfo" : ""; -// Get Pi-hole core version -if ($phBranch !== "master") { - $phVersion = exec("cd /etc/.pihole/ && git describe --long --dirty --tags"); - $execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]; -} else { - $phVersion = exec("cd /etc/.pihole/ && git describe --tags --abbrev=0"); -} +// Get Pi-hole Core version +$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags"); + +// Print $execTime on development branches +if (substr_count("-", $phVersion) != "1") + $execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]; ?> - + - - + + ● <?=$serverName ?> - +