diff --git a/README.md b/README.md index e3f3b257..987b2bb6 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,186 @@ -Pi-hole Admin Dashboard -============ -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/938b4d9e61b7487da77cf63ba05c683d)](https://www.codacy.com/app/Pi-hole/AdminLTE?utm_source=github.com&utm_medium=referral&utm_content=pi-hole/AdminLTE&utm_campaign=badger) -[![Join the chat at https://gitter.im/pi-hole/AdminLTE](https://badges.gitter.im/pi-hole/AdminLTE.svg)](https://gitter.im/pi-hole/AdminLTE?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +

+Pi-hole

+Network-wide ad blocking via your own Linux hardware
+
+Pi-hole Web interface
+

-[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif "AdminLTE Presentation")](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate") +Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/)'s Web interface (based off of [AdminLTE](https://almsaeedstudio.com)) provides a central location to manage your Pi-hole and review the statistics generated by FTLDNS[™](https://pi-hole.net/trademark-rules-and-brand-guidelines/). -Using **[AdminLTE](https://almsaeedstudio.com)**, this project will create a Web interface for the ad-blocking Pi-hole: **a black hole for Internet advertisements**. +- **Easy-to-interpret**: simple graphs and beautiful colors make Pi-hole's stats easy to understand +- **Responsive**: looks great on desktop, tablets, and mobile devices +- **Useful**: control and configure your Pi-hole with our settings +- **Insightful**: use the query log, audit log, or long-term stats to gain insight into your networks activity -From this interface, you will be able to see stats on how well your Pi-hole is performing. You will also be able to update the lists used to block ads. +--- + +
-![Pi-hole Web interface](http://i.imgur.com/EgGZXbT.png) +# Installation + +The Web interface is enabled by default when you install Pi-hole. + +## Post-installation: access the Web interface and gain insight into your network's activity +There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168): + +1. `http:///admin/` +2. `http:/pi.hole/admin/` (when using Pi-hole as your DNS server) +3. `http://pi.hole/` (when using Pi-hole as your DNS server) + +Once logged in (forgot your password?), you can view your network stats to see things like: + +- the domains being queried on your network +- the time the queries were initiated +- the amount of domains that were blocked +- the upstream server queries were sent to +- the type of queries (`A`, `AAAA`, `CNAME`, `SRV`, `TXT`, etc.) +--- + +## Pi-hole is free, but powered by your support +There are many reoccurring costs involved with maintaining free, open source, and privacy respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained. + +Make no mistake: **your support is absolutely vital to help keep us innovating!** + +### Donations +Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses: + +- PP Donate via PayPal
+- BTC [Bitcoin](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): 1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL
+- BTC [Bitcoin Cash](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): qqh25hlmqaj99xraw00e47xmf8sysnyxhyww2d7dnh
+- BTC [Ethereum](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): 0xF00aF43d2431BAD585056492b310e48eC40D87e8 + +### Alternative support +If you'd rather not [donate](https://pi-hole.net/donate/) (_which is okay!_), there are other ways you can help support us: + +- [Patreon](https://patreon.com/pihole) _Become a patron for rewards_ +- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_ +- [UNIXstickers.com](http://unixstickers.refr.cc/jacobs) _save $5 when you spend $9 using our affiliate link_ +- [Pi-hole Swag Store](https://pi-hole.net/shop/) _affiliate link_ +- [Amazon](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_ +- [DNS Made Easy](https://cp.dnsmadeeasy.com/u/133706) _affiliate link_ +- [Vultr](http://www.vultr.com/?ref=7190426) _affiliate link_ +- Spreading the word about our software, and how you have benefited from it + +### Contributing via GitHub +We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests. + +If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions that it asks will help the volunteers quickly understand what you're aiming to achieve. + +### Presentations about Pi-hole +Word-of-mouth continues to help our project grow immensely, and so we are helping make this easier for people. + +If you are going to be presenting Pi-hole at a conference, meetup or even a school project, [get in touch with us](https://pi-hole.net/2017/05/17/giving-a-presentation-on-pi-hole-contact-us-first-for-some-goodies-and-support/) so we can hook you up with free swag to hand out to your audience! + +----- + +## Getting in touch with us +While we are primarily reachable on our Discourse User Forum, we can also be found on a variety of social media outlets. **Please be sure to check the FAQ's** before starting a new discussion, as we do not have the spare time to reply to every request for assistance. + + + +# Features + +## Mobile friendly interface +

+Mobile friendly +

+ +## Password protection +

+Password protection +

+ +## Detailed graphs and doughnut charts +

+Pie charts +

+ +## Top lists of domains and clients +

+Top domains/top clients +

+ +## A filterable and sortable query log +

+Query log +

+ +## An audit log +

+Pi-hole Web interface +

+ +## Long Term Statistics to view data over user defined time ranges +

+Long-term stats +

+ +## A built-in debugger +

+Debugger +

+ +## Black and white lists +

+Blacklist +

+Whitelist +

+ +## The ability to easily manage and configure Pi-hole features +

+Settings +

+ +## ... and all the main features of the Command Line Interface! +

+Tail the log +

+Query ad lists +

## API -A read-only API can be accessed at `/admin/api.php`. With either no parameters or `api.php?summary` it returns the following JSON: +Full usage available [here](https://discourse.pi-hole.net/t/pi-hole-api/1863). can be accessed at `/admin/api.php`. With either no parameters or `/admin/api.php?summary` it returns the following JSON: ```JSON -{ - "domains_being_blocked": "136,708", - "dns_queries_today": "18,108", - "ads_blocked_today": "14,648", - "ads_percentage_today": "80.9" +{ + "domains_being_blocked":243038, + "dns_queries_today":2385, + "ads_blocked_today":414, + "ads_percentage_today":17.35849, + "unique_domains":429, + "queries_forwarded":1537, + "queries_cached":434, + "clients_ever_seen":5, + "unique_clients":5, + "status":"enabled" } ``` -There are many more parameters, such as `summaryRaw`, `overTimeData10mins`, `topItems`, ` topClients` or `getQuerySources`, `getQueryTypes`, `getForwardDestinations`, and finally `getAllQueries`. -Together with a token it is also possible to enable and disable (also with a set timeout) blocking via the API +[There are many more parameters](https://discourse.pi-hole.net/t/pi-hole-api/1863), such as: -The API returns more information (in a slighly different format if `FTL` is running) - it supports a fall-back to the "old" PHP API if `FTL` is not running. Test the type and/or version of the API by using the parameter `type` and `version`. +- `type & version` +- `summaryRaw` +- `summary` +- `overTimeData10mins` +- `topItems` +- `getQuerySources` +- `getForwardDestinations` +- `getQueryTypes` +- `getAllQueries` +- `enable` +- `disable` +- `recentBlocked` -
-
-We use BrowserStack for multi-platform multi-browser testing. +Together with a token it is also possible to [enable and disable (also with a set timeout) blocking via the API](https://discourse.pi-hole.net/t/is-there-an-api-command-to-disable-ad-blocking/7693). + +The API returns more information (in a slightly different format if `FTL` is running) - it supports a fall-back to the "old" PHP API if `FTL` is not running. Test the type and/or version of the API by using the parameter `type` and `version`. diff --git a/api.php b/api.php index 4092540d..f4221f30 100644 --- a/api.php +++ b/api.php @@ -73,23 +73,33 @@ elseif (isset($_GET['disable']) && $auth) } $data = array_merge($data, array("status" => "disabled")); } +elseif (isset($_GET['versions'])) +{ + // Determine if updates are available for Pi-hole + // using the same script that we use for the footer + // on the dashboard (update notifications are + // suppressed if on development branches) + require "scripts/pi-hole/php/update_checker.php"; + $updates = array("core_update" => $core_update, + "web_update" => $web_update, + "FTL_update" => $FTL_update); + $current = array("core_current" => $core_current, + "web_current" => $web_current, + "FTL_current" => $FTL_current); + $latest = array("core_latest" => $core_latest, + "web_latest" => $web_latest, + "FTL_latest" => $FTL_latest); + $branches = array("core_branch" => $core_branch, + "web_branch" => $web_branch, + "FTL_branch" => $FTL_branch); + $data = array_merge($data, $updates); + $data = array_merge($data, $current); + $data = array_merge($data, $latest); + $data = array_merge($data, $branches); +} // Other API functions -if(!testFTL($FTL_IP) && !isset($_GET["PHP"])) -{ - $data = array_merge($data, array("FTLnotrunning" => true)); -} -else -{ - if(!isset($_GET["PHP"])) - { - require("api_FTL.php"); - } - else - { - require("api_PHP.php"); - } -} +require("api_FTL.php"); if(isset($_GET["jsonForceObject"])) { diff --git a/api_FTL.php b/api_FTL.php index d4e1c085..19a94f82 100644 --- a/api_FTL.php +++ b/api_FTL.php @@ -15,339 +15,355 @@ if(!isset($api)) // $FTL_IP is defined in api.php $socket = connectFTL($FTL_IP); -if (isset($_GET['type'])) { - $data["type"] = "FTL"; -} - -if (isset($_GET['version'])) { - $data["version"] = 3; -} - -if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) +if(!is_resource($socket)) { - sendRequestFTL("stats"); - $return = getResponseFTL(); + $data = array_merge($data, array("FTLnotrunning" => true)); +} +else +{ + if (isset($_GET['type'])) { + $data["type"] = "FTL"; + } - $stats = []; - foreach($return as $line) + if (isset($_GET['version'])) { + $data["version"] = 3; + } + + if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) { - $tmp = explode(" ",$line); + require_once("scripts/pi-hole/php/gravity.php"); + sendRequestFTL("stats"); + $return = getResponseFTL(); - if(($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1])) || $tmp[0] === "status") + $stats = []; + foreach($return as $line) { - $stats[$tmp[0]] = $tmp[1]; - continue; - } + $tmp = explode(" ",$line); - if(isset($_GET['summary'])) - { - if($tmp[0] !== "ads_percentage_today") + if(($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1])) || $tmp[0] === "status") { - $stats[$tmp[0]] = number_format($tmp[1]); + $stats[$tmp[0]] = $tmp[1]; + continue; + } + + if(isset($_GET['summary'])) + { + if($tmp[0] !== "ads_percentage_today") + { + $stats[$tmp[0]] = number_format($tmp[1]); + } + else + { + $stats[$tmp[0]] = number_format($tmp[1], 1, '.', ''); + } } else { - $stats[$tmp[0]] = number_format($tmp[1], 1, '.', ''); + $stats[$tmp[0]] = floatval($tmp[1]); } } - else + $stats['gravity_last_updated'] = gravity_last_update(true); + $data = array_merge($data,$stats); + } + + if (isset($_GET['overTimeData10mins'])) + { + sendRequestFTL("overTime"); + $return = getResponseFTL(); + + $domains_over_time = array(); + $ads_over_time = array(); + foreach($return as $line) { - $stats[$tmp[0]] = floatval($tmp[1]); + $tmp = explode(" ",$line); + $domains_over_time[intval($tmp[0])] = intval($tmp[1]); + $ads_over_time[intval($tmp[0])] = intval($tmp[2]); } - } - $data = array_merge($data,$stats); -} - -if (isset($_GET['overTimeData10mins'])) -{ - sendRequestFTL("overTime"); - $return = getResponseFTL(); - - $domains_over_time = array(); - $ads_over_time = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - $domains_over_time[intval($tmp[0])] = intval($tmp[1]); - $ads_over_time[intval($tmp[0])] = intval($tmp[2]); - } - $result = array('domains_over_time' => $domains_over_time, - 'ads_over_time' => $ads_over_time); - $data = array_merge($data, $result); -} - -if (isset($_GET['topItems']) && $auth) -{ - if($_GET['topItems'] === "audit") - { - sendRequestFTL("top-domains for audit"); - } - else if(is_numeric($_GET['topItems'])) - { - sendRequestFTL("top-domains (".$_GET['topItems'].")"); - } - else - { - sendRequestFTL("top-domains"); + $result = array('domains_over_time' => $domains_over_time, + 'ads_over_time' => $ads_over_time); + $data = array_merge($data, $result); } - $return = getResponseFTL(); - $top_queries = array(); - foreach($return as $line) + if (isset($_GET['topItems']) && $auth) { - $tmp = explode(" ",$line); - $top_queries[$tmp[2]] = intval($tmp[1]); - } - - if($_GET['topItems'] === "audit") - { - sendRequestFTL("top-ads for audit"); - } - else if(is_numeric($_GET['topItems'])) - { - sendRequestFTL("top-ads (".$_GET['topItems'].")"); - } - else - { - sendRequestFTL("top-ads"); - } - - $return = getResponseFTL(); - $top_ads = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - if(count($tmp) === 4) - $top_ads[$tmp[2]." (".$tmp[3].")"] = intval($tmp[1]); - else - $top_ads[$tmp[2]] = intval($tmp[1]); - } - - $result = array('top_queries' => $top_queries, - 'top_ads' => $top_ads); - - $data = array_merge($data, $result); -} - -if ((isset($_GET['topClients']) || isset($_GET['getQuerySources'])) && $auth) -{ - - if(isset($_GET['topClients'])) - { - $number = $_GET['topClients']; - } - elseif(isset($_GET['getQuerySources'])) - { - $number = $_GET['getQuerySources']; - } - - if(is_numeric($number)) - { - sendRequestFTL("top-clients (".$number.")"); - } - else - { - sendRequestFTL("top-clients"); - } - - $return = getResponseFTL(); - $top_clients = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - if(count($tmp) == 4) + if($_GET['topItems'] === "audit") { - $top_clients[$tmp[3]."|".$tmp[2]] = intval($tmp[1]); + sendRequestFTL("top-domains for audit"); + } + else if(is_numeric($_GET['topItems'])) + { + sendRequestFTL("top-domains (".$_GET['topItems'].")"); } else { - $top_clients[$tmp[2]] = intval($tmp[1]); + sendRequestFTL("top-domains"); } - } - $result = array('top_sources' => $top_clients); - $data = array_merge($data, $result); -} - -if (isset($_GET['getForwardDestinations']) && $auth) -{ - if($_GET['getForwardDestinations'] === "unsorted") - { - sendRequestFTL("forward-dest unsorted"); - } - else - { - sendRequestFTL("forward-dest"); - } - $return = getResponseFTL(); - $forward_dest = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - if(count($tmp) == 4) + $return = getResponseFTL(); + $top_queries = array(); + foreach($return as $line) { - $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + $tmp = explode(" ",$line); + $top_queries[$tmp[2]] = intval($tmp[1]); + } + + if($_GET['topItems'] === "audit") + { + sendRequestFTL("top-ads for audit"); + } + else if(is_numeric($_GET['topItems'])) + { + sendRequestFTL("top-ads (".$_GET['topItems'].")"); } else { - $forward_dest[$tmp[2]] = floatval($tmp[1]); + sendRequestFTL("top-ads"); } - } - $result = array('forward_destinations' => $forward_dest); - $data = array_merge($data, $result); -} - -if (isset($_GET['getQueryTypes']) && $auth) -{ - sendRequestFTL("querytypes"); - $return = getResponseFTL(); - $querytypes = array(); - foreach($return as $ret) - { - $tmp = explode(": ",$ret); - $querytypes[$tmp[0]] = floatval($tmp[1]); - } - - $result = array('querytypes' => $querytypes); - $data = array_merge($data, $result); -} - -if (isset($_GET['getAllQueries']) && $auth) -{ - if(isset($_GET['from']) && isset($_GET['until'])) - { - // Get limited time interval - sendRequestFTL("getallqueries-time ".$_GET['from']." ".$_GET['until']); - } - else if(isset($_GET['domain'])) - { - // Get specific domain only - sendRequestFTL("getallqueries-domain ".$_GET['domain']); - } - else if(isset($_GET['client'])) - { - // Get specific client only - sendRequestFTL("getallqueries-client ".$_GET['client']); - } - else - { - // Get all queries - sendRequestFTL("getallqueries"); - } - $return = getResponseFTL(); - $allQueries = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - array_push($allQueries,$tmp); - } - - $result = array('data' => $allQueries); - $data = array_merge($data, $result); -} - -if(isset($_GET["recentBlocked"])) -{ - sendRequestFTL("recentBlocked"); - die(getResponseFTL()[0]); - unset($data); -} - -if (isset($_GET['overTimeDataForwards']) && $auth) -{ - sendRequestFTL("ForwardedoverTime"); - $return = getResponseFTL(); - $over_time = array(); - - foreach($return as $line) - { - $tmp = explode(" ",$line); - for ($i=0; $i < count($tmp)-1; $i++) { - $over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]); - } - } - $result = array('over_time' => $over_time); - $data = array_merge($data, $result); -} - -if (isset($_GET['getForwardDestinationNames']) && $auth) -{ - sendRequestFTL("forward-names"); - $return = getResponseFTL(); - $forward_dest = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - if(count($tmp) == 4) + $return = getResponseFTL(); + $top_ads = array(); + foreach($return as $line) { - $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + $tmp = explode(" ",$line); + if(count($tmp) > 3) + $top_ads[$tmp[2]." (".$tmp[3].")"] = intval($tmp[1]); + else + $top_ads[$tmp[2]] = intval($tmp[1]); + } + + $result = array('top_queries' => $top_queries, + 'top_ads' => $top_ads); + + $data = array_merge($data, $result); + } + + if ((isset($_GET['topClients']) || isset($_GET['getQuerySources'])) && $auth) + { + + if(isset($_GET['topClients'])) + { + $number = $_GET['topClients']; + } + elseif(isset($_GET['getQuerySources'])) + { + $number = $_GET['getQuerySources']; + } + + if(is_numeric($number)) + { + sendRequestFTL("top-clients (".$number.")"); } else { - $forward_dest[$tmp[2]] = floatval($tmp[1]); + sendRequestFTL("top-clients"); } - } - $result = array('forward_destinations' => $forward_dest); - $data = array_merge($data, $result); -} - -if (isset($_GET['overTimeDataQueryTypes']) && $auth) -{ - sendRequestFTL("QueryTypesoverTime"); - $return = getResponseFTL(); - $over_time = array(); - - foreach($return as $line) - { - $tmp = explode(" ",$line); - for ($i=0; $i < count($tmp)-1; $i++) { - $over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]); - } - } - $result = array('over_time' => $over_time); - $data = array_merge($data, $result); -} - -if (isset($_GET['getClientNames']) && $auth) -{ - sendRequestFTL("client-names"); - $return = getResponseFTL(); - $forward_dest = array(); - foreach($return as $line) - { - $tmp = explode(" ",$line); - if(count($tmp) == 4) + $return = getResponseFTL(); + $top_clients = array(); + foreach($return as $line) { - $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + $tmp = explode(" ",$line); + if(count($tmp) > 3 && strlen($tmp[3]) > 0) + $top_clients[$tmp[3]."|".$tmp[2]] = intval($tmp[1]); + else + $top_clients[$tmp[2]] = intval($tmp[1]); + } + + $result = array('top_sources' => $top_clients); + $data = array_merge($data, $result); + } + + if (isset($_GET['topClientsBlocked']) && $auth) + { + + if(isset($_GET['topClientsBlocked'])) + { + $number = $_GET['topClientsBlocked']; + } + + if(is_numeric($number)) + { + sendRequestFTL("top-clients blocked (".$number.")"); } else { - $forward_dest[$tmp[2]] = floatval($tmp[1]); + sendRequestFTL("top-clients blocked"); } + + $return = getResponseFTL(); + $top_clients = array(); + foreach($return as $line) + { + $tmp = explode(" ",$line); + if(count($tmp) > 3 && strlen($tmp[3]) > 0) + $top_clients[$tmp[3]."|".$tmp[2]] = intval($tmp[1]); + else + $top_clients[$tmp[2]] = intval($tmp[1]); + } + + $result = array('top_sources_blocked' => $top_clients); + $data = array_merge($data, $result); } - $result = array('clients' => $forward_dest); - $data = array_merge($data, $result); -} - -if (isset($_GET['overTimeDataClients']) && $auth) -{ - sendRequestFTL("ClientsoverTime"); - $return = getResponseFTL(); - $over_time = array(); - - foreach($return as $line) + if (isset($_GET['getForwardDestinations']) && $auth) { - $tmp = explode(" ",$line); - for ($i=0; $i < count($tmp)-1; $i++) { - $over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]); + if($_GET['getForwardDestinations'] === "unsorted") + { + sendRequestFTL("forward-dest unsorted"); + } + else + { + sendRequestFTL("forward-dest"); + } + $return = getResponseFTL(); + $forward_dest = array(); + foreach($return as $line) + { + $tmp = explode(" ",$line); + if(count($tmp) > 3 && strlen($tmp[3]) > 0) + $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + else + $forward_dest[$tmp[2]] = floatval($tmp[1]); } - } - $result = array('over_time' => $over_time); - $data = array_merge($data, $result); -} -disconnectFTL(); + $result = array('forward_destinations' => $forward_dest); + $data = array_merge($data, $result); + } + + if (isset($_GET['getQueryTypes']) && $auth) + { + sendRequestFTL("querytypes"); + $return = getResponseFTL(); + $querytypes = array(); + foreach($return as $ret) + { + $tmp = explode(": ",$ret); + $querytypes[$tmp[0]] = floatval($tmp[1]); + } + + $result = array('querytypes' => $querytypes); + $data = array_merge($data, $result); + } + + if (isset($_GET['getAllQueries']) && $auth) + { + if(isset($_GET['from']) && isset($_GET['until'])) + { + // Get limited time interval + sendRequestFTL("getallqueries-time ".$_GET['from']." ".$_GET['until']); + } + else if(isset($_GET['domain'])) + { + // Get specific domain only + sendRequestFTL("getallqueries-domain ".$_GET['domain']); + } + else if(isset($_GET['client'])) + { + // Get specific client only + sendRequestFTL("getallqueries-client ".$_GET['client']); + } + else if(is_numeric($_GET['getAllQueries'])) + { + sendRequestFTL("getallqueries (".$_GET['getAllQueries'].")"); + } + else + { + // Get all queries + sendRequestFTL("getallqueries"); + } + $return = getResponseFTL(); + $allQueries = array(); + foreach($return as $line) + { + $tmp = explode(" ",$line); + array_push($allQueries,$tmp); + } + + $result = array('data' => $allQueries); + $data = array_merge($data, $result); + } + + if(isset($_GET["recentBlocked"])) + { + sendRequestFTL("recentBlocked"); + die(getResponseFTL()[0]); + unset($data); + } + + if (isset($_GET['getForwardDestinationNames']) && $auth) + { + sendRequestFTL("forward-names"); + $return = getResponseFTL(); + $forward_dest = array(); + foreach($return as $line) + { + $tmp = explode(" ",$line); + if(count($tmp) > 3) + { + $forward_dest[$tmp[3]."|".$tmp[2]] = floatval($tmp[1]); + } + else + { + $forward_dest[$tmp[2]] = floatval($tmp[1]); + } + } + + $result = array('forward_destinations' => $forward_dest); + $data = array_merge($data, $result); + } + + if (isset($_GET['overTimeDataQueryTypes']) && $auth) + { + sendRequestFTL("QueryTypesoverTime"); + $return = getResponseFTL(); + $over_time = array(); + + foreach($return as $line) + { + $tmp = explode(" ",$line); + for ($i=0; $i < count($tmp)-1; $i++) { + $over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]); + } + } + $result = array('over_time' => $over_time); + $data = array_merge($data, $result); + } + + if (isset($_GET['getClientNames']) && $auth) + { + sendRequestFTL("client-names"); + $return = getResponseFTL(); + $client_names = array(); + foreach($return as $line) + { + $tmp = explode(" ", $line); + $client_names[] = array( + "name" => $tmp[0], + "ip" => $tmp[1] + ); + } + + $result = array('clients' => $client_names); + $data = array_merge($data, $result); + } + + if (isset($_GET['overTimeDataClients']) && $auth) + { + sendRequestFTL("ClientsoverTime"); + $return = getResponseFTL(); + $over_time = array(); + + foreach($return as $line) + { + $tmp = explode(" ",$line); + for ($i=0; $i < count($tmp)-1; $i++) { + $over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]); + } + } + $result = array('over_time' => $over_time); + $data = array_merge($data, $result); + } + + disconnectFTL(); +} ?> diff --git a/api_PHP.php b/api_PHP.php deleted file mode 100644 index dc7a1d2b..00000000 --- a/api_PHP.php +++ /dev/null @@ -1,93 +0,0 @@ -$value) { - if (is_array($value)) { - $outArray[htmlspecialchars($key)] = filterArray($value); - } else { - $outArray[htmlspecialchars($key)] = !is_numeric($value) ? htmlspecialchars($value) : $value; - } - } - return $outArray; - } - - $data = filterArray($data); -?> diff --git a/api_db.php b/api_db.php index 21f1106d..567e2c32 100644 --- a/api_db.php +++ b/api_db.php @@ -16,6 +16,37 @@ check_cors(); ini_set("max_execution_time","600"); $data = array(); +$clients = array(); +function resolveHostname($clientip, $printIP) +{ + global $clients; + $ipaddr = strtolower($clientip); + if(array_key_exists($clientip, $clients)) + { + // Entry already exists + $clientname = $clients[$ipaddr]; + if($printIP) + return $clientname."|".$clientip; + return $clientname; + } + + else if(filter_var($clientip, FILTER_VALIDATE_IP)) + { + // Get host name of client and convert to lower case + $clientname = strtolower(gethostbyaddr($ipaddr)); + } + else + { + // This is already a host name + $clientname = $ipaddr; + } + // Buffer result + $clients[$ipaddr] = $clientname; + + if($printIP) + return $clientname."|".$clientip; + return $clientname; +} // Get posible non-standard location of FTL's database $FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf"); @@ -77,7 +108,8 @@ if (isset($_GET['getAllQueries']) && $auth) if(!is_bool($results)) while ($row = $results->fetchArray()) { - $allQueries[] = [$row[0],$row[1] == 1 ? "IPv4" : "IPv6",$row[2],$row[3],$row[4]]; + $c = resolveHostname($row[3],false); + $allQueries[] = [$row[0],$row[1] == 1 ? "IPv4" : "IPv6",$row[2],$c,$row[4]]; } } $result = array('data' => $allQueries); @@ -105,32 +137,33 @@ if (isset($_GET['topClients']) && $auth) $stmt->bindValue(":until", intval($_GET['until']), SQLITE3_INTEGER); $results = $stmt->execute(); - $clients = array(); + $clientnums = array(); if(!is_bool($results)) while ($row = $results->fetchArray()) { - // Convert client to lower case - $c = strtolower($row[0]); - if(array_key_exists($c, $clients)) + + $c = resolveHostname($row[0],false); + + if(array_key_exists($c, $clientnums)) { // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database) - $clients[$c] += intval($row[1]); + $clientnums[$c] += intval($row[1]); } else { // Entry does not yet exist - $clients[$c] = intval($row[1]); + $clientnums[$c] = intval($row[1]); } } // Sort by number of hits - arsort($clients); + arsort($clientnums); // Extract only the first ten entries - $clients = array_slice($clients, 0, 10); + $clientnums = array_slice($clientnums, 0, 10); - $result = array('top_sources' => $clients); + $result = array('top_sources' => $clientnums); $data = array_merge($data, $result); } @@ -292,13 +325,38 @@ if (isset($_GET['getGraphData']) && $auth) $stmt->bindValue(":interval", $interval, SQLITE3_INTEGER); $results = $stmt->execute(); - $domains = array(); + // Parse the DB result into graph data, filling in missing sections with zero + function parseDBData($results, $interval) { + $data = array(); + $min = null; + $max = null; - if(!is_bool($results)) - while ($row = $results->fetchArray()) - { - $domains[$row[0]] = intval($row[1]); + if(!is_bool($results)) { + // Read in the data + while($row = $results->fetchArray()) { + // Get min and max timestamps + if($min === null || $min > $row[0]) + $min = $row[0]; + + if($max === null || $max < $row[0]) + $max = $row[0]; + + // Get the non-zero graph data + $data[$row[0]] = intval($row[1]); + } + + // Fill the missing intervals with zero + for($i = $min; $i < $max; $i += $interval) { + if(!array_key_exists($i, $data)) + $data[$i] = 0; + } } + + return $data; + } + + $domains = parseDBData($results, $interval); + $result = array('domains_over_time' => $domains); $data = array_merge($data, $result); @@ -309,13 +367,8 @@ if (isset($_GET['getGraphData']) && $auth) $stmt->bindValue(":interval", $interval, SQLITE3_INTEGER); $results = $stmt->execute(); - $addomains = array(); + $addomains = parseDBData($results, $interval); - if(!is_bool($results)) - while ($row = $results->fetchArray()) - { - $addomains[$row[0]] = intval($row[1]); - } $result = array('ads_over_time' => $addomains); $data = array_merge($data, $result); } diff --git a/gravity.php b/gravity.php index f11e6ab7..1b1bd3bb 100644 --- a/gravity.php +++ b/gravity.php @@ -9,7 +9,7 @@ ?> @@ -22,7 +22,7 @@ Success! - +

White- / Blacklist

Add or remove domains (or subdomains) from the white-/blacklist. If a domain is added to e.g. the whitelist, any possible entry of the same domain will be automatically removed from the blacklist and vice versa.

-

Wildcard blacklisting is supported (entering something.de will block this domain including all subdomains like a.bb.c.999.something.de). Note that wildcard whitelisting is not supported.

+

Regex blacklisting is supported (entering ^example will block any domain starting with example, see also our Regex documentation). You can still whitelist specific domains even if they fall under a regex pattern.

You can white-/blacklist multiple entries at a time if you separate the domains by spaces.

@@ -82,14 +82,14 @@
-

Tools → Update Lists

-

Will download any updates from the third-party ad-serving domain lists that we source. By default, this command runs once a week via cron (Sunday at 01:59).

+

Tools → Update Gravity

+

Will download any updates from the third-party blocklists that we source. By default, this command runs once a week via cron (Sunday).

-

Tools → Query adlists

- This function is useful to find out what list a domain appears on. Since we don't control what the third-parties put on the block lists, you may find that a domain you normally visit stops working. If this is the case, you could run this command to scan for strings in the list of blocked domains and it will return the list the domain is found on. This proved useful a while back when the Mahakala list was adding apple.com and microsoft.com to their block list.

+

Tools → Query Lists

+ This function is useful to find out what list a domain appears on. Since we don't control what the third-parties put on the blocklists, you may find that a domain you normally visit stops working. If this is the case, you could run this command to scan for strings in the list of blocked domains and it will return the list the domain is found on. This proved useful a while back when the Mahakala list was adding apple.com and microsoft.com to their block list.

@@ -102,26 +102,20 @@

Settings

Change settings for the Pi-hole -

Networking

- Displays information about the interfaces of the Pi-hole. No changes possible. -

Pi-hole DHCP Server

- Using this setting you can enable/disable the DHCP server of the Pi-hole. Note that you should disable any other DHCP server on your network to avoid IP addresses being used more than once. You have to give the range of IPs that DHCP will serve and the IP of the local router (gateway). If the DHCP server is active, the current leases are shown on the settings page. IPv4 DHCP will always be activated, IPv6 (stateless + statefull) can be enabled. -

Upstream DNS Servers

+

System

+ Displays network and other system information of Pi-hole. At the bottom there is a "Danger Zone" with actions such as disable query logging and reboot. +

Blocklists

+ View and edit the blocklists sourced for blocked domains. +

DNS

Customize used upstream DNS servers + advanced settings for DNS servers. Note that any number of DNS servers may be enabled at a time. -

Query Logging

- Enabled/disable query logging on your Pi-hole + provide option to flush the log -

API

- Change settings which apply to the API as well as the web UI -
    -
  • Show permitted domain entries: Toogle permitted queries in Query Log + Top Domains on Main Page
  • -
  • Show blockes domain entries: Toogle blocked queries in Query Log + Top Ads on Main Page
  • -
  • Privacy mode: Replace IPs in query log with "hidden"
  • -
-

Web User Interface

- Other settings which affect the webUI but not the API of Pi-hole -

System Administration

- Apply system-wide actions like restarting of the server -
+

DHCP

+ Using this setting you can enable/disable the DHCP server of the Pi-hole. Note that you should disable any other DHCP server on your network to avoid IP addresses being used more than once. You have to give the range of IPs that DHCP will serve and the IP of the local router (gateway). If the DHCP server is active, the current leases are shown on the settings page. IPv4 DHCP will always be activated, IPv6 (stateless + statefull) can be enabled. +

API / Web Interface

+ Change settings which apply to the API as well as the web interface +

Privacy

+ Set the privacy level for queries. Note that decreasing the privacy level will not disclose previously hidden query data. +

Teleporter

+ Import and export Pi-hole settings.
diff --git a/index.php b/index.php index 2ce90bfe..33d08c5e 100644 --- a/index.php +++ b/index.php @@ -7,12 +7,13 @@ * Please see LICENSE file for your rights under this license. */ $indexpage = true; require "scripts/pi-hole/php/header.php"; + require_once("scripts/pi-hole/php/gravity.php"); ?>
-
+

Total queries (- clients)

---

@@ -48,27 +49,10 @@
-d > 1) - $gravitydate = $gravitydiff->format("Blocking list updated %a days, %H:%I ago"); - elseif($gravitydiff->d == 1) - $gravitydate = $gravitydiff->format("Blocking list updated one day, %H:%I ago"); - else - $gravitydate = $gravitydiff->format("Blocking list updated %H:%I ago"); -} -else -{ - $gravitydate = "Blocking list not found"; -} -?>
-
+

Domains on Blocklist

---

@@ -114,7 +98,7 @@ else
- +
@@ -129,11 +113,14 @@ else
-

Query Types (integrated)

+

Query Types

-
- +
+ +
+
+
@@ -145,11 +132,14 @@ else
-

Forward Destinations (integrated)

+

Queries answered by

-
- +
+ +
+
+
@@ -223,18 +213,18 @@ else
-

Top Domains

+

Top Permitted Domains

@@ -284,11 +274,41 @@ else
+
+
-

Top Clients

+

Top Clients (total)

+
+ +
+
+ + + + + + + + +
ClientRequestsFrequency
+
+
+
+ +
+ +
+ +
+ + +
+
+
+

Top Clients (blocked only)

diff --git a/list.php b/list.php index 5efde479..cc566e92 100644 --- a/list.php +++ b/list.php @@ -1,4 +1,4 @@ -

-

Note that the ad list domains are automatically added to the whitelist so that a list can never get blocked by another list.

@@ -39,16 +38,13 @@ function getFullName() { +
- -

Note: Whitelisting a subdomain of a wildcard blocked domain is not possible.

-

Some of the domains shown below are domains of the adlists sources, which are automatically added in order to prevent adlists being able to blacklist each other. See here for the default set of adlists.

- diff --git a/scripts/pi-hole/php/password.php b/scripts/pi-hole/php/password.php index ad8cbd08..ed95ca31 100644 --- a/scripts/pi-hole/php/password.php +++ b/scripts/pi-hole/php/password.php @@ -24,9 +24,13 @@ } // If the user wants to log out, we free all session variables currently registered + // and delete any persistent cookie. if(isset($_GET["logout"])) { session_unset(); + setcookie('persistentlogin', ''); + header('Location: index.php'); + exit(); } $wrongpassword = false; @@ -35,8 +39,24 @@ // Test if password is set if(strlen($pwhash) > 0) { + // Check for and authorize from persistent cookie + if (isset($_COOKIE["persistentlogin"])) + { + if ($pwhash === $_COOKIE["persistentlogin"]) + { + $auth = true; + // Refresh cookie with new expiry + setcookie('persistentlogin', $pwhash, time()+60*60*24*7); + } + else + { + // Invalid cookie + $auth = false; + setcookie('persistentlogin', ''); + } + } // Compare doubly hashes password input with saved hash - if(isset($_POST["pw"])) + else if(isset($_POST["pw"])) { $postinput = hash('sha256',hash('sha256',$_POST["pw"])); if(hash_equals($pwhash, $postinput)) @@ -45,6 +65,11 @@ // Login successful, redirect the user to the homepage to discard the POST request if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['QUERY_STRING'] === 'login') { + // Set persistent cookie if selected + if (isset($_POST['persistentlogin'])) + { + setcookie('persistentlogin', $pwhash, time()+60*60*24*7); + } header('Location: index.php'); exit(); } diff --git a/scripts/pi-hole/php/queryads.php b/scripts/pi-hole/php/queryads.php index 133ea12c..0de64cb0 100644 --- a/scripts/pi-hole/php/queryads.php +++ b/scripts/pi-hole/php/queryads.php @@ -58,7 +58,7 @@ else $exact = ""; } -$proc = popen("sudo pihole -q ".$url." ".$exact, 'r'); +$proc = popen("sudo pihole -q -adlist ".$url." ".$exact, 'r'); while (!feof($proc)) { echoEvent(fread($proc, 4096)); } diff --git a/scripts/pi-hole/php/savesettings.php b/scripts/pi-hole/php/savesettings.php index 64914e77..c1226fd5 100644 --- a/scripts/pi-hole/php/savesettings.php +++ b/scripts/pi-hole/php/savesettings.php @@ -123,7 +123,8 @@ function isinserverlist($addr) { "Norton" => ["v4_1" => "199.85.126.10", "v4_2" => "199.85.127.10"], "Comodo" => ["v4_1" => "8.26.56.26", "v4_2" => "8.20.247.20"], "DNS.WATCH" => ["v4_1" => "84.200.69.80", "v4_2" => "84.200.70.40", "v6_1" => "2001:1608:10:25:0:0:1c04:b12f", "v6_2" => "2001:1608:10:25:0:0:9249:d69b"], - "Quad9" => ["v4_1" => "9.9.9.9", "v4_2" => "149.112.112.112", "v6_1" => "2620:fe::fe"] + "Quad9" => ["v4_1" => "9.9.9.9", "v4_2" => "149.112.112.112", "v6_1" => "2620:fe::fe"], + "Cloudflare" => ["v4_1" => "1.1.1.1", "v4_2" => "1.0.0.1", "v6_1" => "2606:4700:4700::1111", "v6_2" => "2606:4700:4700::1001"] ]; $adlist = []; @@ -186,20 +187,34 @@ function readAdlists() { if(array_key_exists("custom".$i,$_POST)) { - $IP = $_POST["custom".$i."val"]; - if(validIP($IP)) + $exploded = explode("#", $_POST["custom".$i."val"], 2); + $IP = $exploded[0]; + if(count($exploded) > 1) { - array_push($DNSservers,$IP); + $port = $exploded[1]; } else + { + $port = "53"; + } + if(!validIP($IP)) { $error .= "IP (".htmlspecialchars($IP).") is invalid!
"; } + elseif(!is_numeric($port)) + { + $error .= "Port (".htmlspecialchars($port).") is invalid!
"; + } + else + { + array_push($DNSservers,$IP."#".$port); + } } } + $DNSservercount = count($DNSservers); // Check if at least one DNS server has been added - if(count($DNSservers) < 1) + if($DNSservercount < 1) { $error .= "No DNS server has been selected.
"; } @@ -234,6 +249,28 @@ function readAdlists() $extra .= "no-dnssec"; } + // Check if Conditional Forwarding is requested + if(isset($_POST["conditionalForwarding"])) + { + // Validate conditional forwarding IP + if (!validIP($_POST["conditionalForwardingIP"])) + { + $error .= "Conditional forwarding IP (".htmlspecialchars($_POST["conditionalForwardingIP"]).") is invalid!
"; + } + + // Validate conditional forwarding domain name + if(!validDomain($_POST["conditionalForwardingDomain"])) + { + $error .= "Conditional forwarding domain name (".htmlspecialchars($_POST["conditionalForwardingDomain"]).") is invalid!
"; + } + if(!$error) + { + $addressArray = explode(".", $_POST["conditionalForwardingIP"]); + $reverseAddress = $addressArray[2].".".$addressArray[1].".".$addressArray[0].".in-addr.arpa"; + $extra .= " conditional_forwarding ".$_POST["conditionalForwardingIP"]." ".$_POST["conditionalForwardingDomain"]." $reverseAddress"; + } + } + // Check if DNSinterface is set if(isset($_POST["DNSinterface"])) { @@ -261,9 +298,9 @@ function readAdlists() if(!strlen($error)) { $IPs = implode (",", $DNSservers); - $return = exec("sudo pihole -a setdns ".$IPs." ".$extra); + $return = exec("sudo pihole -a setdns \"".$IPs."\" ".$extra); $success .= htmlspecialchars($return)."
"; - $success .= "The DNS settings have been updated (using ".count($DNSservers)." DNS servers)"; + $success .= "The DNS settings have been updated (using ".$DNSservercount." DNS servers)"; } else { @@ -415,6 +452,19 @@ function readAdlists() { exec('sudo pihole -a -c'); } + $adminemail = trim($_POST["adminemail"]); + if(strlen($adminemail) == 0 || !isset($adminemail)) + { + $adminemail = 'noadminemail'; + } + elseif(!filter_var($adminemail, FILTER_VALIDATE_EMAIL)) + { + $error .= "Administrator email address (".htmlspecialchars($adminemail).") is invalid!
"; + } + else + { + exec('sudo pihole -a -e '.$adminemail); + } if(isset($_POST["boxedlayout"])) { exec('sudo pihole -a layout boxed'); @@ -612,7 +662,19 @@ function readAdlists() // Reread available adlists $adlist = readAdlists(); + break; + case "privacyLevel": + $level = intval($_POST["privacylevel"]); + if($level >= 0 && $level <= 3) + { + exec("sudo pihole -a privacylevel ".$level); + $success .= "The privacy level has been updated"; + } + else + { + $error .= "Invalid privacy level (".$level.")!"; + } break; default: diff --git a/scripts/pi-hole/php/sub.php b/scripts/pi-hole/php/sub.php index bab6e51f..cb5803de 100644 --- a/scripts/pi-hole/php/sub.php +++ b/scripts/pi-hole/php/sub.php @@ -21,8 +21,30 @@ switch($type) { case "black": exec("sudo pihole -b -q -d ${_POST['domain']}"); break; - case "wild": - exec("sudo pihole -wild -q -d ${_POST['domain']}"); + case "regex": + if(($list = file_get_contents($regexfile)) === FALSE) + { + $err = error_get_last()["message"]; + echo "Unable to read ${regexfile}
Error message: $err"; + } + + // Remove the regex and any empty lines from the list + $list = explode("\n", $list); + $list = array_diff($list, array($_POST['domain'], "")); + $list = implode("\n", $list); + + if(file_put_contents($regexfile, $list) === FALSE) + { + $err = error_get_last()["message"]; + echo "Unable to remove regex \"".htmlspecialchars($_POST['domain'])."\" from ${regexfile}
Error message: $err"; + } + else + { + // Send SIGHUP to pihole-FTL using a frontend command + // to force reloading of the regex domains + // This will also wipe the resolver's cache + echo exec("sudo pihole restartdns reload"); + } break; } diff --git a/scripts/pi-hole/php/teleporter.php b/scripts/pi-hole/php/teleporter.php index 9efe7fd1..dbdb637d 100644 --- a/scripts/pi-hole/php/teleporter.php +++ b/scripts/pi-hole/php/teleporter.php @@ -14,14 +14,14 @@ if (php_sapi_name() !== "cli") { check_csrf(isset($_POST["token"]) ? $_POST["token"] : ""); } -function archive_add_file($path,$name) +function archive_add_file($path,$name,$subdir="") { global $archive; if(file_exists($path.$name)) - $archive[$name] = file_get_contents($path.$name); + $archive[$subdir.$name] = file_get_contents($path.$name); } -function archive_add_directory($path) +function archive_add_directory($path,$subdir="") { if($dir = opendir($path)) { @@ -29,7 +29,7 @@ function archive_add_directory($path) { if($entry !== "." && $entry !== "..") { - archive_add_file($path,$entry); + archive_add_file($path,$entry,$subdir); } } closedir($dir); @@ -43,7 +43,7 @@ function limit_length(&$item, $key) $item = substr($item, 0, 253); } -function process_file($contents) +function process_file($contents,$check=True) { $domains = array_filter(explode("\n",$contents)); @@ -51,8 +51,12 @@ function process_file($contents) // function to every member of the array of domains array_walk($domains, "limit_length"); - // Check validity of domains (after possible clipping) - check_domains($domains); + // Check validity of domains (don't do it for regex filters) + if($check) + { + check_domains($domains); + } + return $domains; } @@ -66,27 +70,6 @@ function check_domains($domains) } } -function getWildcardListContent() { - if(file_exists("/etc/dnsmasq.d/03-pihole-wildcard.conf")) - { - $rawList = file_get_contents("/etc/dnsmasq.d/03-pihole-wildcard.conf"); - $wclist = explode("\n", $rawList); - $list = []; - - foreach ($wclist as $entry) { - $expl = explode("/", $entry); - if(count($expl) == 3) - { - array_push($list,$expl[1]); - } - } - - return implode("\n",array_unique($list)); - } - - return ""; -} - if(isset($_POST["action"])) { if($_FILES["zip_file"]["name"] && $_POST["action"] == "in") @@ -125,28 +108,41 @@ if(isset($_POST["action"])) if(isset($_POST["blacklist"]) && $file->getFilename() === "blacklist.txt") { $blacklist = process_file(file_get_contents($file)); - echo "Processing blacklist.txt
\n"; + echo "Processing blacklist.txt (".count($blacklist)." entries)
\n"; exec("sudo pihole -b -nr --nuke"); exec("sudo pihole -b -q -nr ".implode(" ", $blacklist)); $importedsomething = true; } + if(isset($_POST["whitelist"]) && $file->getFilename() === "whitelist.txt") { $whitelist = process_file(file_get_contents($file)); - echo "Processing whitelist.txt
\n"; + echo "Processing whitelist.txt (".count($whitelist)." entries)
\n"; exec("sudo pihole -w -nr --nuke"); exec("sudo pihole -w -q -nr ".implode(" ", $whitelist)); $importedsomething = true; } - if(isset($_POST["wildlist"]) && $file->getFilename() === "wildcardblocking.txt") + if(isset($_POST["regexlist"]) && $file->getFilename() === "regex.list") { - $wildlist = process_file(file_get_contents($file)); - echo "Processing wildcardblocking.txt
\n"; - exec("sudo pihole -wild -nr --nuke"); - exec("sudo pihole -wild -q -nr ".implode(" ", $wildlist)); + $regexraw = file_get_contents($file); + $regexlist = process_file($regexraw,false); + echo "Processing regex.list (".count($regexlist)." entries)
\n"; + // NULL = overwrite (or create) the regex filter file + add_regex($regexraw, NULL,""); $importedsomething = true; } + + // Also try to import legacy wildcard list if found + if(isset($_POST["regexlist"]) && $file->getFilename() === "wildcardblocking.txt") + { + $wildlist = process_file(file_get_contents($file)); + echo "Processing wildcardblocking.txt (".count($wildlist)." entries)
\n"; + exec("sudo pihole --wild -nr --nuke"); + exec("sudo pihole --wild -q -nr ".implode(" ", $wildlist)); + $importedsomething = true; + } + if($importedsomething) { exec("sudo pihole restartdns"); @@ -177,9 +173,9 @@ else archive_add_file("/etc/pihole/","adlists.list"); archive_add_file("/etc/pihole/","setupVars.conf"); archive_add_file("/etc/pihole/","auditlog.list"); - archive_add_directory("/etc/dnsmasq.d/"); + archive_add_file("/etc/pihole/","regex.list"); + archive_add_directory("/etc/dnsmasq.d/","dnsmasq.d/"); - $archive["wildcardblocking.txt"] = getWildcardListContent(); $archive->compress(Phar::GZ); // Creates a gziped copy unlink($archive_file_name); // Unlink original tar file as it is not needed anymore $archive_file_name .= ".gz"; // Append ".gz" extension to ".tar" diff --git a/settings.php b/settings.php index 372f9393..73783d44 100644 --- a/settings.php +++ b/settings.php @@ -9,34 +9,29 @@ require "scripts/pi-hole/php/header.php"; require "scripts/pi-hole/php/savesettings.php"; // Reread ini file as things might have been changed $setupVars = parse_ini_file("/etc/pihole/setupVars.conf"); +$piholeFTLConfFile = "/etc/pihole/pihole-FTL.conf"; +if(is_readable($piholeFTLConfFile)) +{ + $piholeFTLConf = parse_ini_file($piholeFTLConfFile); +} +else +{ + $piholeFTLConf = array(); +} + +// Handling of PHP internal errors +$last_error = error_get_last(); +if($last_error["type"] === E_WARNING || $last_error["type"] === E_ERROR) +{ + $error .= "There was a problem applying your settings.
Debugging information:
PHP error (".htmlspecialchars($last_error["type"])."): ".htmlspecialchars($last_error["message"])." in ".htmlspecialchars($last_error["file"]).":".htmlspecialchars($last_error["line"]); +} ?>
@@ -248,7 +251,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
-

Lists used to generate Pi-hole's Gravity

+

Blocklists used to generate Pi-hole's Gravity:

@@ -281,7 +284,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
- +
@@ -555,7 +558,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
Remaining lease time:
DHCP UID: "> - + ">
value="">
@@ -704,7 +706,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" checked>
value="">
@@ -714,7 +715,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" checked>
value="">
@@ -724,7 +724,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" checked>
value="">
@@ -812,6 +811,42 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" DNSSEC. Note that the size of your log might increase significantly when enabling DNSSEC. A DNSSEC resolver test can be found here.

+ +

If not configured as your DHCP server, Pi-hole won't able to + determine the names of devices on your local network. As a + result, tables such as Top Clients will only show IP addresses.

+

One solution for this is to configure Pi-hole to forward these + requests to your home router, but only for devices on your + home network. To configure this we will need to know the IP + address of your router and the name of your local network.

+

Note: The local domain name must match the domain name specified + in your router, likely found within the DHCP settings.

+
+
+ +
+
+ + + + + + +
+
+ + + +
IP of your routerLocal domain name
+ value=""> + value=""> +
+
+
@@ -831,7 +866,13 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" } else { $temperatureunit = "C"; } - // Use $boxedlayout value determined in header.php + + // Administrator email address + if (isset($setupVars["ADMIN_EMAIL"])) { + $adminemail = $setupVars["ADMIN_EMAIL"]; + } else { + $adminemail = ""; + } ?>
in active">
@@ -869,39 +910,19 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
-
-

Privacy settings (Statistics / Query Log)

+
+

Query Log

-
- -
+
-
- -
-
-
-
-
-
-

Privacy mode

-
-
- -
+
@@ -950,6 +971,13 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" ?>>Fahrenheit
+

Administrator Email Address

+
+
+ +
+
@@ -963,6 +991,67 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
+ + +
in active"> +
+
+
+
+
+

Privacy settings

+
+
+
+
+

DNS resolver privacy level

+

Specify if DNS queries should be anonymized, available options are: +

+
+ +
+
+ +
+
+ +
+
+ +
+
+

The privacy level may be changed at any time without having to restart the DNS resolver. However, note that queries with (partially) hidden details cannot be disclosed with a subsequent reduction of the privacy level.

+ 0 && $piHoleLogging){ ?> +

Warning: Pi-hole's query logging is activated. Although the dashboard will hide the requested details, all queries are still fully logged to the pihole.log file.

+ +
+
+
+ +
+
+
+
+
in active">
@@ -1007,9 +1096,9 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists" Blacklist (exact)
- + Regex filters
diff --git a/style/pi-hole.css b/style/pi-hole.css index 541d5c6e..d622e9bc 100644 --- a/style/pi-hole.css +++ b/style/pi-hole.css @@ -15,6 +15,12 @@ -o-user-select: none; user-select: none; } +.small-box span { + transition-duration: 500ms; +} +.small-box span.glow { + text-shadow: 0px 0px 5px #fff; +} .skin-blue .list-group-item:hover { background: #ddd; } @@ -28,7 +34,7 @@ 50% {color:#e33100;text-shadow:0 0 5px #e33100;} to {color:#630030;text-shadow:0 0 2px transparent;} } -a.lookatme { +.lookatme { -webkit-animation-name: Pulse; animation-name: Pulse; -webkit-animation-duration: 2s; @@ -115,3 +121,57 @@ a.lookatme { -webkit-animation: fa-spin 1s infinite linear; animation: fa-spin 1s infinite linear; } + +.extratooltipcanvas{ + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} + +#chartjs-tooltip { + opacity: 1; + position: absolute; + background: rgba(0, 0, 0, .7); + color: white; + border-radius: 3px; + -webkit-transition: all .1s ease; + transition: all .1s ease; + pointer-events: none; + -webkit-transform: translate(-50%, 0); + transform: translate(-50%, 0); +} + +.chartjs-tooltip-key { + display: inline-block; + width: 20px; + height: 10px; + margin-right: 10px; +} + +.chart-legend { + height:250px; + overflow:auto; +} + +.chart-legend ul { + list-style-type: none; +} + +.chart-legend li { + cursor:pointer; +} + +.chart-legend li span { + display: inline-block; + width: 20px; + height: 12px; + margin-right: 5px; +} + +.strike { + text-decoration: line-through !important; +} + +.float-left{ + float:left; +} diff --git a/taillog-FTL.php b/taillog-FTL.php index 3c27cdcd..53b454ad 100644 --- a/taillog-FTL.php +++ b/taillog-FTL.php @@ -13,7 +13,7 @@
-

+

 
-

+