mirror of
https://github.com/pi-hole/web.git
synced 2024-12-06 19:36:21 +01:00
@@ -1,32 +1,186 @@
|
||||
Pi-hole Admin Dashboard
|
||||
============
|
||||
[](https://www.codacy.com/app/Pi-hole/AdminLTE?utm_source=github.com&utm_medium=referral&utm_content=pi-hole/AdminLTE&utm_campaign=badger)
|
||||
[](https://gitter.im/pi-hole/AdminLTE?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<p align="center">
|
||||
<a href="https://pi-hole.net"><img src="https://pi-hole.github.io/graphics/Vortex/Vortex_with_text.png" width="150" height="255" alt="Pi-hole"></a><br/></br>
|
||||
<b>Network-wide ad blocking via your own Linux hardware</b><br/>
|
||||
</br>
|
||||
<a href="https://pi-hole.net"><img src="https://pi-hole.github.io/graphics/Screenshots/pihole-dashboard.png" alt="Pi-hole Web interface"></a><br/>
|
||||
</p>
|
||||
|
||||
[](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.
|
||||
---
|
||||
<a class="badge-align" href="https://www.codacy.com/app/Pi-hole/AdminLTE?utm_source=github.com&utm_medium=referral&utm_content=pi-hole/AdminLTE&utm_campaign=Badge_Grade"><img src="https://api.codacy.com/project/badge/Grade/10540ea45a3b4d5f992c05a2c9714609"/></a>
|
||||
<img src="https://pi-hole.github.io/graphics/Badges/browserstack-badge.png" height="80"><br>
|
||||
|
||||

|
||||
# 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://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/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:
|
||||
|
||||
- <img src="https://pi-hole.github.io/graphics/Badges/paypal-badge-black.svg" width="24" height="24" alt="PP"/> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate via PayPal</a><br/>
|
||||
- <img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> [Bitcoin](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL</code></br>
|
||||
- <img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> [Bitcoin Cash](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>qqh25hlmqaj99xraw00e47xmf8sysnyxhyww2d7dnh</code></br>
|
||||
- <img src="https://pi-hole.github.io/graphics/Badges/ethereum-badge-black.svg" width="24" height="24" alt="BTC"/> [Ethereum](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>0xF00aF43d2431BAD585056492b310e48eC40D87e8</code>
|
||||
|
||||
### 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 <a href="https://discourse.pi-hole.net/">Discourse User Forum</a>, 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.
|
||||
|
||||
<ul>
|
||||
<li><b><a href="https://discourse.pi-hole.net/c/faqs">Frequently Asked Questions</a></b></li>
|
||||
<li><b><a href="https://github.com/pi-hole/pi-hole/wiki">Pi-hole Wiki</a></b></li>
|
||||
<li><b><a href="https://discourse.pi-hole.net/c/feature-requests?order=votes">Feature Requests</a></b></li>
|
||||
<li><a href="https://discourse.pi-hole.net/">Discourse User Forum</a></li>
|
||||
<li><a href="https://www.reddit.com/r/pihole/">Reddit</a></li>
|
||||
<li><a href="https://twitter.com/The_Pi_Hole">Twitter</a></li>
|
||||
<li><a href="https://www.facebook.com/ThePiHole/">Facebook</a></li>
|
||||
<li><a href="https://gitter.im/pi-hole/pi-hole">Gitter</a> (Real-time chat)</li>
|
||||
<li><a href="https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w">YouTube</a></li>
|
||||
</ul>
|
||||
|
||||
# Features
|
||||
|
||||
## Mobile friendly interface
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/mobile-friendly.png" height="300" alt="Mobile friendly"></a>
|
||||
</p>
|
||||
|
||||
## Password protection
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/password-protection.png" height="400" alt="Password protection"></a>
|
||||
</p>
|
||||
|
||||
## Detailed graphs and doughnut charts
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/piecharts.png" alt="Pie charts"></a>
|
||||
</p>
|
||||
|
||||
## Top lists of domains and clients
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/topdomains-clients.png" alt="Top domains/top clients"></a>
|
||||
</p>
|
||||
|
||||
## A filterable and sortable query log
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/query-log-sorted.png" alt="Query log"></a>
|
||||
</p>
|
||||
|
||||
## An audit log
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/audit-log.png" alt="Pi-hole Web interface"></a>
|
||||
</p>
|
||||
|
||||
## Long Term Statistics to view data over user defined time ranges
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/long-term-stats.png" alt="Long-term stats"></a>
|
||||
</p>
|
||||
|
||||
## A built-in debugger
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/debug.png" alt="Debugger"></a>
|
||||
</p>
|
||||
|
||||
## Black and white lists
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/blacklist.png" alt="Blacklist"></a>
|
||||
</br></br>
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/whitelist.png" alt="Whitelist"></a>
|
||||
</p>
|
||||
|
||||
## The ability to easily manage and configure Pi-hole features
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/dashboard-settings.gif" alt="Settings"></a>
|
||||
</p>
|
||||
|
||||
## ... and all the main features of the Command Line Interface!
|
||||
<p align="center">
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/pihole-t.png" alt="Tail the log"></a>
|
||||
</br></br>
|
||||
<img src="https://pi-hole.github.io/graphics/Screenshots/pihole-q.png" alt="Query ad lists"></a>
|
||||
</p>
|
||||
|
||||
## 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`
|
||||
|
||||
<hr>
|
||||
<img src="https://assets.pi-hole.net/static/BStackLogo.png" height="80"><br>
|
||||
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`.
|
||||
|
||||
@@ -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"]))
|
||||
{
|
||||
|
||||
+306
-290
@@ -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();
|
||||
}
|
||||
?>
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
/* 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. */
|
||||
|
||||
|
||||
if(!isset($api))
|
||||
{
|
||||
die("Direct call to api_PHP.php is not allowed!");
|
||||
}
|
||||
|
||||
include('scripts/pi-hole/php/data.php');
|
||||
|
||||
// Non-Auth
|
||||
|
||||
if (isset($_GET['type'])) {
|
||||
$data["type"] = "PHP";
|
||||
}
|
||||
|
||||
if (isset($_GET['version'])) {
|
||||
$data["version"] = 2;
|
||||
}
|
||||
|
||||
if (isset($_GET['summaryRaw'])) {
|
||||
$data = array_merge($data, getSummaryData());
|
||||
}
|
||||
|
||||
if (isset($_GET['summary']) || !count($_GET)) {
|
||||
$sum = getSummaryData();
|
||||
$sum['ads_blocked_today'] = number_format( $sum['ads_blocked_today']);
|
||||
$sum['dns_queries_today'] = number_format( $sum['dns_queries_today']);
|
||||
$sum['ads_percentage_today'] = number_format( $sum['ads_percentage_today'], 1, '.', '');
|
||||
$sum['domains_being_blocked'] = number_format( $sum['domains_being_blocked']);
|
||||
$data = array_merge($data, $sum);
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeData'])) {
|
||||
$data = array_merge($data, getOverTimeData());
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeData10mins'])) {
|
||||
$data = array_merge($data, getOverTimeData10mins());
|
||||
}
|
||||
|
||||
// Auth Required
|
||||
|
||||
if (isset($_GET['topItems']) && $auth) {
|
||||
$data = array_merge($data, getTopItems($_GET['topItems']));
|
||||
}
|
||||
|
||||
if (isset($_GET['recentItems']) && $auth) {
|
||||
if (is_numeric($_GET['recentItems'])) {
|
||||
$data = array_merge($data, getRecentItems($_GET['recentItems']));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['getQueryTypes']) && $auth) {
|
||||
$data = array_merge($data, getIpvType());
|
||||
}
|
||||
|
||||
if (isset($_GET['getForwardDestinations']) && $auth) {
|
||||
$data = array_merge($data, getForwardDestinations());
|
||||
}
|
||||
|
||||
if (isset($_GET['getQuerySources']) && $auth) {
|
||||
$data = array_merge($data, getQuerySources());
|
||||
}
|
||||
|
||||
if (isset($_GET['getAllQueries']) && $auth) {
|
||||
$data = array_merge($data, getAllQueries($_GET['getAllQueries']));
|
||||
}
|
||||
|
||||
if (isset($_GET['getGravityDomains'])) {
|
||||
$data = array_merge($data, getGravity());
|
||||
}
|
||||
|
||||
function filterArray(&$inArray) {
|
||||
$outArray = array();
|
||||
foreach ($inArray as $key=>$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);
|
||||
?>
|
||||
+74
-21
@@ -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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
?>
|
||||
<!-- Title -->
|
||||
<div class="page-header">
|
||||
<h1>Update list of ad-serving domains / blacklist / whitelist</h1>
|
||||
<h1>Update Gravity (list of blocked domains)</h1>
|
||||
</div>
|
||||
|
||||
<!-- Alerts -->
|
||||
@@ -22,7 +22,7 @@
|
||||
Success!
|
||||
</div>
|
||||
|
||||
<button class="btn btn-lg btn-primary btn-block" id="gravityBtn">Update Lists</button>
|
||||
<button class="btn btn-lg btn-primary btn-block" id="gravityBtn">Update</button>
|
||||
<pre id="output" style="width: 100%; height: 100%;" hidden="true"></pre>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="col-md-12">
|
||||
<h2>White- / Blacklist</h2>
|
||||
<p>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.</p>
|
||||
<p>Wildcard blacklisting is supported (entering <samp>something.de</samp> will block this domain including all subdomains like <samp>a.bb.c.999.something.de</samp>). Note that wildcard whitelisting is <em>not</em> supported.</p>
|
||||
<p>Regex blacklisting is supported (entering <samp>^example</samp> will block any domain starting with <samp>example</samp>, see also our <a href="https://docs.pi-hole.net/ftldns/regex/" target="_blank">Regex documentation</a>). You can still whitelist specific domains even if they fall under a regex pattern.</p>
|
||||
<p>You can white-/blacklist multiple entries at a time if you separate the domains by spaces.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,14 +82,14 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Tools → Update Lists</h2>
|
||||
<p>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).</p>
|
||||
<h2>Tools → Update Gravity</h2>
|
||||
<p>Will download any updates from the third-party blocklists that we source. By default, this command runs once a week via cron (Sunday).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>Tools → Query adlists</h2>
|
||||
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 <samp>apple.com</samp> and <samp>microsoft.com</samp> to their block list.</p>
|
||||
<h2>Tools → Query Lists</h2>
|
||||
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 <samp>apple.com</samp> and <samp>microsoft.com</samp> to their block list.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
@@ -102,26 +102,20 @@
|
||||
<div class="col-md-12">
|
||||
<h2>Settings</h2>
|
||||
Change settings for the Pi-hole
|
||||
<h4>Networking</h4>
|
||||
Displays information about the interfaces of the Pi-hole. No changes possible.
|
||||
<h4>Pi-hole DHCP Server</h4>
|
||||
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.
|
||||
<h4>Upstream DNS Servers</h4>
|
||||
<h4>System</h4>
|
||||
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.
|
||||
<h4>Blocklists</h4>
|
||||
View and edit the blocklists sourced for blocked domains.
|
||||
<h4>DNS</h4>
|
||||
Customize used upstream DNS servers + advanced settings for DNS servers. Note that any number of DNS servers may be enabled at a time.
|
||||
<h4>Query Logging</h4>
|
||||
Enabled/disable query logging on your Pi-hole + provide option to flush the log
|
||||
<h4>API</h4>
|
||||
Change settings which apply to the API as well as the web UI
|
||||
<ul>
|
||||
<li>Show permitted domain entries: Toogle permitted queries in Query Log + Top Domains on Main Page</li>
|
||||
<li>Show blockes domain entries: Toogle blocked queries in Query Log + Top Ads on Main Page</li>
|
||||
<li>Privacy mode: Replace IPs in query log with "hidden"</li>
|
||||
</ul>
|
||||
<h4>Web User Interface</h4>
|
||||
Other settings which affect the webUI but not the API of Pi-hole
|
||||
<h4>System Administration</h4>
|
||||
Apply system-wide actions like restarting of the server
|
||||
</div>
|
||||
<h4>DHCP</h4>
|
||||
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.
|
||||
<h4>API / Web Interface</h4>
|
||||
Change settings which apply to the API as well as the web interface
|
||||
<h4>Privacy</h4>
|
||||
Set the privacy level for queries. Note that decreasing the privacy level will not disclose previously hidden query data.
|
||||
<h4>Teleporter</h4>
|
||||
Import and export Pi-hole settings.
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
@@ -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");
|
||||
?>
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-xs-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-green">
|
||||
<div class="small-box bg-green" id="total_queries" title="only A + AAAA queries">
|
||||
<div class="inner">
|
||||
<p>Total queries (<span id="unique_clients">-</span> clients)</p>
|
||||
<h3 class="statistic"><span id="dns_queries_today">---</span></h3>
|
||||
@@ -48,27 +49,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$gravitylist = "/etc/pihole/gravity.list";
|
||||
if (file_exists($gravitylist))
|
||||
{
|
||||
$gravitydiff = date_diff(date_create("@".filemtime($gravitylist)),date_create("now"));
|
||||
if($gravitydiff->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";
|
||||
}
|
||||
?>
|
||||
<!-- ./col -->
|
||||
<div class="col-lg-3 col-xs-12">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-red" title="<?php echo $gravitydate; ?>">
|
||||
<div class="small-box bg-red" title="<?php echo gravity_last_update(); ?>">
|
||||
<div class="inner">
|
||||
<p>Domains on Blocklist</p>
|
||||
<h3 class="statistic"><span id="domains_being_blocked">---</span></h3>
|
||||
@@ -114,7 +98,7 @@ else
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="chart">
|
||||
<canvas id="clientsChart" width="800" height="140"></canvas>
|
||||
<canvas id="clientsChart" width="800" height="140" class="extratooltipcanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay">
|
||||
@@ -129,11 +113,14 @@ else
|
||||
<div class="col-md-12 col-lg-6">
|
||||
<div class="box" id="query-types-pie">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Query Types (integrated)</h3>
|
||||
<h3 class="box-title">Query Types</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="chart">
|
||||
<canvas id="queryTypePieChart" width="400" height="150"></canvas>
|
||||
<div class="float-left" style="width:50%">
|
||||
<canvas id="queryTypePieChart" width="120" height="120"></canvas>
|
||||
</div>
|
||||
<div class="float-left" style="width:50%">
|
||||
<div id="query-types-legend" class="chart-legend"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay">
|
||||
@@ -145,11 +132,14 @@ else
|
||||
<div class="col-md-12 col-lg-6">
|
||||
<div class="box" id="forward-destinations-pie">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Forward Destinations (integrated)</h3>
|
||||
<h3 class="box-title">Queries answered by</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="chart">
|
||||
<canvas id="forwardDestinationPieChart" width="400" height="150"></canvas>
|
||||
<div class="float-left" style="width:50%">
|
||||
<canvas id="forwardDestinationPieChart" width="120" height="120"></canvas>
|
||||
</div>
|
||||
<div class="float-left" style="width:50%">
|
||||
<div id="forward-destinations-legend" class="chart-legend"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay">
|
||||
@@ -223,18 +213,18 @@ else
|
||||
<?php
|
||||
if($boxedlayout)
|
||||
{
|
||||
$tablelayout = "col-md-6";
|
||||
$tablelayout = "col-md-6";
|
||||
}
|
||||
else
|
||||
{
|
||||
$tablelayout = "col-md-6 col-lg-4";
|
||||
$tablelayout = "col-md-6 col-lg-6";
|
||||
}
|
||||
?>
|
||||
<div class="row">
|
||||
<div class="<?php echo $tablelayout; ?>">
|
||||
<div class="box" id="domain-frequency">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Top Domains</h3>
|
||||
<h3 class="box-title">Top Permitted Domains</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
@@ -284,11 +274,41 @@ else
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- /.col -->
|
||||
<div class="<?php echo $tablelayout; ?>">
|
||||
<div class="box" id="client-frequency">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Top Clients</h3>
|
||||
<h3 class="box-title">Top Clients (total)</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Client</th>
|
||||
<th>Requests</th>
|
||||
<th>Frequency</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay">
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<!-- /.col -->
|
||||
<div class="<?php echo $tablelayout; ?>">
|
||||
<div class="box" id="client-frequency-blocked">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Top Clients (blocked only)</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php /*
|
||||
<?php /*
|
||||
* 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.
|
||||
@@ -30,7 +30,6 @@ function getFullName() {
|
||||
<div class="page-header">
|
||||
<h1><?php getFullName(); ?></h1>
|
||||
</div>
|
||||
<?php if($list == "white"){ ?><p>Note that the ad list domains are automatically added to the whitelist so that a list can never get blocked by another list.</p><?php } ?>
|
||||
|
||||
<!-- Domain Input -->
|
||||
<div class="form-group input-group">
|
||||
@@ -39,16 +38,13 @@ function getFullName() {
|
||||
<?php if($list === "black") { ?>
|
||||
<button id="btnAdd" class="btn btn-default" type="button">Add (exact)</button>
|
||||
<button id="btnAddWildcard" class="btn btn-default" type="button">Add (wildcard)</button>
|
||||
<button id="btnAddRegex" class="btn btn-default" type="button">Add (regex)</button>
|
||||
<?php }else{ ?>
|
||||
<button id="btnAdd" class="btn btn-default" type="button">Add</button>
|
||||
<?php } ?>
|
||||
<button id="btnRefresh" class="btn btn-default" type="button"><i class="fa fa-refresh"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<?php if($list === "white") { ?>
|
||||
<p>Note: Whitelisting a subdomain of a wildcard blocked domain is not possible.</p>
|
||||
<p>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 <a href="https://github.com/pi-hole/pi-hole/blob/master/adlists.default" target="_blank">here</a> for the default set of adlists.</p>
|
||||
<?php } ?>
|
||||
|
||||
<!-- Alerts -->
|
||||
<div id="alInfo" class="alert alert-info alert-dismissible fade in" role="alert" hidden="true">
|
||||
@@ -71,8 +67,8 @@ function getFullName() {
|
||||
<?php } ?>
|
||||
<ul class="list-group" id="list"></ul>
|
||||
<?php if($list === "black") { ?>
|
||||
<h3>Wildcard blocking</h3>
|
||||
<ul class="list-group" id="list-wildcard"></ul>
|
||||
<h3><a href="https://docs.pi-hole.net/ftldns/regex/overview/" target="_blank" title="Click for Pi-hole Regex documentation">Regex</a> & Wildcard blocking</h3>
|
||||
<ul class="list-group" id="list-regex"></ul>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
|
||||
+17
-13
@@ -19,47 +19,49 @@ if(isset($setupVars["API_QUERY_LOG_SHOW"]))
|
||||
{
|
||||
if($setupVars["API_QUERY_LOG_SHOW"] === "all")
|
||||
{
|
||||
$showing = "showing all queries";
|
||||
$showing = "showing";
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "permittedonly")
|
||||
{
|
||||
$showing = "showing permitted queries only";
|
||||
$showing = "showing permitted";
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "blockedonly")
|
||||
{
|
||||
$showing = "showing blocked queries only";
|
||||
$showing = "showing blocked";
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "nothing")
|
||||
{
|
||||
$showing = "showing no queries at all";
|
||||
$showing = "showing no queries (due to setting)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If filter variable is not set, we
|
||||
// automatically show all queries
|
||||
$showing = "showing all queries";
|
||||
$showing = "showing";
|
||||
}
|
||||
|
||||
$showall = false;
|
||||
if(isset($_GET["all"]))
|
||||
{
|
||||
$showing .= " within the Pi-hole log";
|
||||
$showing .= " all queries within the Pi-hole log";
|
||||
}
|
||||
else if(isset($_GET["client"]))
|
||||
{
|
||||
$showing .= " for client ".htmlentities($_GET["client"]);
|
||||
$showing .= " queries for client ".htmlentities($_GET["client"]);
|
||||
}
|
||||
else if(isset($_GET["domain"]))
|
||||
{
|
||||
$showing .= " for domain ".htmlentities($_GET["domain"]);
|
||||
$showing .= " queries for domain ".htmlentities($_GET["domain"]);
|
||||
}
|
||||
else if(isset($_GET["from"]) && isset($_GET["until"]))
|
||||
else if(isset($_GET["from"]) || isset($_GET["until"]))
|
||||
{
|
||||
$showing .= " within limited time interval";
|
||||
$showing .= " queries within specified time interval";
|
||||
}
|
||||
else
|
||||
{
|
||||
$showing .= " within recent 10 minutes, <a href=\"?all\">show all</a>";
|
||||
$showing .= " up to 100 queries";
|
||||
$showall = true;
|
||||
}
|
||||
|
||||
if(isset($setupVars["API_PRIVACY_MODE"]))
|
||||
@@ -74,6 +76,8 @@ if(isset($setupVars["API_PRIVACY_MODE"]))
|
||||
if(strlen($showing) > 0)
|
||||
{
|
||||
$showing = "(".$showing.")";
|
||||
if($showall)
|
||||
$showing .= ", <a href=\"?all\">show all</a>";
|
||||
}
|
||||
?>
|
||||
<!-- Send PHP info to JS -->
|
||||
@@ -135,7 +139,7 @@ if(strlen($showing) > 0)
|
||||
<th>Domain</th>
|
||||
<th>Client</th>
|
||||
<th>Status</th>
|
||||
<th>DNSSEC</th>
|
||||
<th>Reply</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -146,7 +150,7 @@ if(strlen($showing) > 0)
|
||||
<th>Domain</th>
|
||||
<th>Client</th>
|
||||
<th>Status</th>
|
||||
<th>DNSSEC</th>
|
||||
<th>Reply</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
?>
|
||||
<!-- Title -->
|
||||
<div class="page-header">
|
||||
<h1>Find Ad Domain In Lists</h1>
|
||||
<h1>Find Blocked Domain In Lists</h1>
|
||||
</div>
|
||||
<!-- Domain Input -->
|
||||
<div class="form-group input-group">
|
||||
|
||||
@@ -161,16 +161,16 @@ var reloadCallback = function()
|
||||
statistics[3]++;
|
||||
}
|
||||
}
|
||||
$("h3#dns_queries").text(statistics[0]);
|
||||
$("h3#ads_blocked_exact").text(statistics[2]);
|
||||
$("h3#ads_wildcard_blocked").text(statistics[3]);
|
||||
$("h3#dns_queries").text(statistics[0].toLocaleString());
|
||||
$("h3#ads_blocked_exact").text(statistics[2].toLocaleString());
|
||||
$("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString());
|
||||
|
||||
var percent = 0.0;
|
||||
if(statistics[2] + statistics[3] > 0)
|
||||
{
|
||||
percent = 100.0*(statistics[2] + statistics[3]) / statistics[0];
|
||||
}
|
||||
$("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1)+" %");
|
||||
$("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1).toLocaleString()+" %");
|
||||
};
|
||||
|
||||
function refreshTableData() {
|
||||
|
||||
+200
-19
@@ -29,6 +29,94 @@ function objectToArray(p){
|
||||
return [idx,arr];
|
||||
}
|
||||
|
||||
var lastTooltipTime = 0;
|
||||
|
||||
var customTooltips = function(tooltip) {
|
||||
// Tooltip Element
|
||||
var tooltipEl = document.getElementById("chartjs-tooltip");
|
||||
if (!tooltipEl) {
|
||||
tooltipEl = document.createElement("div");
|
||||
tooltipEl.id = "chartjs-tooltip";
|
||||
document.body.appendChild(tooltipEl);
|
||||
$(tooltipEl).html("<table></table>");
|
||||
}
|
||||
// Hide if no tooltip
|
||||
if (tooltip.opacity === 0) {
|
||||
tooltipEl.style.opacity = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit rendering to once every 50ms. This gives the DOM time to react,
|
||||
// and avoids "lag" caused by not giving the DOM time to reapply CSS.
|
||||
var now = Date.now();
|
||||
if(now - lastTooltipTime < 50) {
|
||||
return;
|
||||
}
|
||||
lastTooltipTime = now;
|
||||
|
||||
// Set caret Position
|
||||
tooltipEl.classList.remove("above", "below", "no-transform");
|
||||
if (tooltip.yAlign) {
|
||||
tooltipEl.classList.add(tooltip.yAlign);
|
||||
} else {
|
||||
tooltipEl.classList.add("above");
|
||||
}
|
||||
function getBody(bodyItem) {
|
||||
return bodyItem.lines;
|
||||
}
|
||||
// Set Text
|
||||
if (tooltip.body) {
|
||||
var titleLines = tooltip.title || [];
|
||||
var bodyLines = tooltip.body.map(getBody);
|
||||
var innerHtml = "<table><thead>";
|
||||
titleLines.forEach(function(title) {
|
||||
innerHtml += "<tr><th>" + title + "</th></tr>";
|
||||
});
|
||||
innerHtml += "</thead><tbody>";
|
||||
var printed = 0;
|
||||
bodyLines.forEach(function(body, i) {
|
||||
var colors = tooltip.labelColors[i];
|
||||
var style = "background:" + colors.backgroundColor;
|
||||
style += "; border-color:" + colors.borderColor;
|
||||
style += "; border-width: 2px";
|
||||
var span = "<span class=\"chartjs-tooltip-key\" style=\"" + style + "\"></span>";
|
||||
var num = body[0].split(": ");
|
||||
if(num[1] > 0)
|
||||
{
|
||||
innerHtml += "<tr><td>" + span + body + "</td></tr>";
|
||||
printed++;
|
||||
}
|
||||
});
|
||||
if(printed < 1)
|
||||
{
|
||||
innerHtml += "<tr><td>No activity recorded</td></tr>";
|
||||
}
|
||||
innerHtml += "</tbody></table>";
|
||||
$(tooltipEl).html(innerHtml);
|
||||
}
|
||||
|
||||
// Display, position, and set styles for font
|
||||
var position = this._chart.canvas.getBoundingClientRect();
|
||||
var width = tooltip.caretX;
|
||||
// Prevent compression of the tooltip at the right edge of the screen
|
||||
if($(document).width() - tooltip.caretX < 400)
|
||||
{
|
||||
width = $(document).width()-400;
|
||||
}
|
||||
// Prevent tooltip disapearing behind the sidebar
|
||||
if(tooltip.caretX < 100)
|
||||
{
|
||||
width = 100;
|
||||
}
|
||||
tooltipEl.style.opacity = 1;
|
||||
tooltipEl.style.left = position.left + width + "px";
|
||||
tooltipEl.style.top = position.top + tooltip.caretY + window.scrollY + "px";
|
||||
tooltipEl.style.fontFamily = tooltip._bodyFontFamily;
|
||||
tooltipEl.style.fontSize = tooltip.bodyFontSize + "px";
|
||||
tooltipEl.style.fontStyle = tooltip._bodyFontStyle;
|
||||
tooltipEl.style.padding = tooltip.yPadding + "px " + tooltip.xPadding + "px";
|
||||
};
|
||||
|
||||
// Functions to update data in page
|
||||
|
||||
var failures = 0;
|
||||
@@ -178,6 +266,23 @@ function updateQueryTypesPie() {
|
||||
queryTypePieChart.update();
|
||||
// Don't use rotation animation for further updates
|
||||
queryTypePieChart.options.animation.duration=0;
|
||||
// Generate legend in separate div
|
||||
$("#query-types-legend").html(queryTypePieChart.generateLegend());
|
||||
$("#query-types-legend > ul > li").on("click",function(e){
|
||||
$(this).toggleClass("strike");
|
||||
var index = $(this).index();
|
||||
var ci = e.view.queryTypePieChart;
|
||||
var meta = ci.data.datasets[0]._meta;
|
||||
for(let i in meta)
|
||||
{
|
||||
if ({}.hasOwnProperty.call(meta, i))
|
||||
{
|
||||
var curr = meta[i].data[index];
|
||||
curr.hidden = !curr.hidden;
|
||||
}
|
||||
}
|
||||
ci.update();
|
||||
});
|
||||
}).done(function() {
|
||||
// Reload graph after minute
|
||||
setTimeout(updateQueryTypesPie, 60000);
|
||||
@@ -266,7 +371,6 @@ function updateForwardedOverTime() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function updateClientsOverTime() {
|
||||
$.getJSON("api.php?overTimeDataClients&getClientNames", function(data) {
|
||||
|
||||
@@ -277,6 +381,13 @@ function updateClientsOverTime() {
|
||||
|
||||
// convert received objects to arrays
|
||||
data.over_time = objectToArray(data.over_time);
|
||||
|
||||
// Remove graph if there are no results (e.g. privacy mode enabled)
|
||||
if(jQuery.isEmptyObject(data.over_time))
|
||||
{
|
||||
$("#clients").parent().remove();
|
||||
return;
|
||||
}
|
||||
// remove last data point since it not representative
|
||||
data.over_time[0].splice(-1,1);
|
||||
var timestamps = data.over_time[0];
|
||||
@@ -286,12 +397,16 @@ function updateClientsOverTime() {
|
||||
for (key in data.clients)
|
||||
{
|
||||
if (!{}.hasOwnProperty.call(data.clients, key)) continue;
|
||||
if(key.indexOf("|") > -1)
|
||||
var clientname;
|
||||
if(data.clients[key].name.length > 0)
|
||||
{
|
||||
var idx = key.indexOf("|");
|
||||
key = key.substr(0, idx);
|
||||
clientname = data.clients[key].name;
|
||||
}
|
||||
labels.push(key);
|
||||
else
|
||||
{
|
||||
clientname = data.clients[key].ip;
|
||||
}
|
||||
labels.push(clientname);
|
||||
}
|
||||
// Get colors from AdminLTE
|
||||
var colors = [];
|
||||
@@ -349,7 +464,7 @@ function updateClientsOverTime() {
|
||||
}
|
||||
|
||||
function updateForwardDestinationsPie() {
|
||||
$.getJSON("api.php?getForwardDestinations=unsorted", function(data) {
|
||||
$.getJSON("api.php?getForwardDestinations", function(data) {
|
||||
|
||||
if("FTLnotrunning" in data)
|
||||
{
|
||||
@@ -370,9 +485,6 @@ function updateForwardDestinationsPie() {
|
||||
values.push([key, value, colors.shift()]);
|
||||
});
|
||||
|
||||
// Sort data ASC accorwing to 2nd column, keep already assigned labels and colors
|
||||
values = values.sort(function(a,b) { return b[1] - a[1]; });
|
||||
|
||||
// Split data into individual arrays for the graphs
|
||||
$.each(values, function(key , value) {
|
||||
k.push(value[0]);
|
||||
@@ -392,6 +504,23 @@ function updateForwardDestinationsPie() {
|
||||
forwardDestinationPieChart.update();
|
||||
// Don't use rotation animation for further updates
|
||||
forwardDestinationPieChart.options.animation.duration=0;
|
||||
// Generate legend in separate div
|
||||
$("#forward-destinations-legend").html(forwardDestinationPieChart.generateLegend());
|
||||
$("#forward-destinations-legend > ul > li").on("click",function(e){
|
||||
$(this).toggleClass("strike");
|
||||
var index = $(this).index();
|
||||
var ci = e.view.forwardDestinationPieChart;
|
||||
var meta = ci.data.datasets[0]._meta;
|
||||
for(let i in meta)
|
||||
{
|
||||
if ({}.hasOwnProperty.call(meta, i))
|
||||
{
|
||||
var curr = meta[i].data[index];
|
||||
curr.hidden = !curr.hidden;
|
||||
}
|
||||
}
|
||||
ci.update();
|
||||
});
|
||||
}).done(function() {
|
||||
// Reload graph after one minute
|
||||
setTimeout(updateForwardDestinationsPie, 60000);
|
||||
@@ -412,7 +541,7 @@ function escapeHtml(text) {
|
||||
}
|
||||
|
||||
function updateTopClientsChart() {
|
||||
$.getJSON("api.php?summaryRaw&getQuerySources", function(data) {
|
||||
$.getJSON("api.php?summaryRaw&getQuerySources&topClientsBlocked", function(data) {
|
||||
|
||||
if("FTLnotrunning" in data)
|
||||
{
|
||||
@@ -421,8 +550,8 @@ function updateTopClientsChart() {
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#client-frequency td").parent().remove();
|
||||
var clienttable = $("#client-frequency").find("tbody:last");
|
||||
var client, percentage, clientname, clientip;
|
||||
var clienttable = $("#client-frequency").find("tbody:last");
|
||||
var client, percentage, clientname, clientip, idx, url;
|
||||
for (client in data.top_sources) {
|
||||
|
||||
if ({}.hasOwnProperty.call(data.top_sources, client)){
|
||||
@@ -435,7 +564,7 @@ function updateTopClientsChart() {
|
||||
client = escapeHtml(client);
|
||||
if(client.indexOf("|") > -1)
|
||||
{
|
||||
var idx = client.indexOf("|");
|
||||
idx = client.indexOf("|");
|
||||
clientname = client.substr(0, idx);
|
||||
clientip = client.substr(idx+1, client.length-idx);
|
||||
}
|
||||
@@ -445,16 +574,61 @@ function updateTopClientsChart() {
|
||||
clientip = client;
|
||||
}
|
||||
|
||||
var url = "<a href=\"queries.php?client="+clientip+"\" title=\""+clientip+"\">"+clientname+"</a>";
|
||||
url = "<a href=\"queries.php?client="+clientip+"\" title=\""+clientip+"\">"+clientname+"</a>";
|
||||
percentage = data.top_sources[client] / data.dns_queries_today * 100;
|
||||
clienttable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_sources[client] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"% of " + data.dns_queries_today + "\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#client-frequency-blocked td").parent().remove();
|
||||
var clientblockedtable = $("#client-frequency-blocked").find("tbody:last");
|
||||
for (client in data.top_sources_blocked) {
|
||||
|
||||
if ({}.hasOwnProperty.call(data.top_sources_blocked, client)){
|
||||
// Sanitize client
|
||||
if(escapeHtml(client) !== client)
|
||||
{
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_sources_blocked[escapeHtml(client)] = data.top_sources_blocked[client];
|
||||
}
|
||||
client = escapeHtml(client);
|
||||
if(client.indexOf("|") > -1)
|
||||
{
|
||||
idx = client.indexOf("|");
|
||||
clientname = client.substr(0, idx);
|
||||
clientip = client.substr(idx+1, client.length-idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientname = client;
|
||||
clientip = client;
|
||||
}
|
||||
|
||||
url = "<a href=\"queries.php?client="+clientip+"\" title=\""+clientip+"\">"+clientname+"</a>";
|
||||
percentage = data.top_sources_blocked[client] / data.ads_blocked_today * 100;
|
||||
clientblockedtable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_sources_blocked[client] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"% of " + data.dns_queries_today + "\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove table if there are no results (e.g. privacy mode enabled)
|
||||
if(jQuery.isEmptyObject(data.top_sources))
|
||||
{
|
||||
$("#client-frequency").parent().remove();
|
||||
}
|
||||
|
||||
// Remove table if there are no results (e.g. privacy mode enabled)
|
||||
if(jQuery.isEmptyObject(data.top_sources_blocked))
|
||||
{
|
||||
$("#client-frequency-blocked").parent().remove();
|
||||
}
|
||||
|
||||
$("#client-frequency .overlay").hide();
|
||||
$("#client-frequency-blocked .overlay").hide();
|
||||
// Update top clients list data every ten seconds
|
||||
setTimeout(updateTopClientsChart, 10000);
|
||||
});
|
||||
@@ -578,6 +752,11 @@ function updateSummaryData(runOnce) {
|
||||
$("span#" + today).addClass("glow");
|
||||
});
|
||||
|
||||
if(data.hasOwnProperty("dns_queries_all_types"))
|
||||
{
|
||||
$("#total_queries").prop("title", "only A + AAAA queries (" + data["dns_queries_all_types"] + " in total)");
|
||||
}
|
||||
|
||||
window.setTimeout(function() {
|
||||
["ads_blocked_today", "dns_queries_today", "domains_being_blocked", "ads_percentage_today", "unique_clients"].forEach(function(header, idx) {
|
||||
var textData = (idx === 3 && data[header] !== "to") ? data[header] + "%" : data[header];
|
||||
@@ -792,8 +971,12 @@ $(document).ready(function() {
|
||||
},
|
||||
options: {
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
mode: "x-axis",
|
||||
custom: customTooltips,
|
||||
itemSort: function(a, b) {
|
||||
return b.yLabel - a.yLabel;
|
||||
},
|
||||
callbacks: {
|
||||
title: function(tooltipItem, data) {
|
||||
var label = tooltipItem[0].xLabel;
|
||||
@@ -960,8 +1143,7 @@ $(document).ready(function() {
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: "right"
|
||||
display: false
|
||||
},
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
@@ -998,8 +1180,7 @@ $(document).ready(function() {
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: "right"
|
||||
display: false
|
||||
},
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
|
||||
+44
-33
@@ -13,13 +13,14 @@ var listType = $("#list-type").html();
|
||||
var fullName = listType === "white" ? "Whitelist" : "Blacklist";
|
||||
|
||||
function sub(index, entry, arg) {
|
||||
var domain = $("#"+index);
|
||||
var domain = $("#list #"+index);
|
||||
var locallistType = listType;
|
||||
domain.hide("highlight");
|
||||
if(arg === "wild")
|
||||
if(arg === "regex")
|
||||
{
|
||||
locallistType = "wild";
|
||||
locallistType = "regex";
|
||||
domain = $("#list-regex #"+index);
|
||||
}
|
||||
domain.hide("highlight");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/sub.php",
|
||||
method: "post",
|
||||
@@ -42,7 +43,7 @@ function refresh(fade) {
|
||||
var list = $("#list");
|
||||
if(listType === "black")
|
||||
{
|
||||
listw = $("#list-wildcard");
|
||||
listw = $("#list-regex");
|
||||
}
|
||||
if(fade) {
|
||||
list.fadeOut(100);
|
||||
@@ -61,7 +62,7 @@ function refresh(fade) {
|
||||
{
|
||||
listw.html("");
|
||||
}
|
||||
var data = JSON.parse(response).sort();
|
||||
var data = JSON.parse(response);
|
||||
|
||||
if(data.length === 0) {
|
||||
$("h3").hide();
|
||||
@@ -74,37 +75,40 @@ function refresh(fade) {
|
||||
list.html("<div class=\"alert alert-info\" role=\"alert\">Your " + fullName + " is empty!</div>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
$("h3").show();
|
||||
data.forEach(function (entry, index) {
|
||||
if(entry.substr(0,1) === "*")
|
||||
{
|
||||
// Wildcard entry
|
||||
// remove leading *
|
||||
entry = entry.substr(1, entry.length - 1);
|
||||
data[0] = data[0].sort();
|
||||
data[0].forEach(function (entry, index) {
|
||||
// Whitelist entry or Blacklist (exact entry) are in the zero-th
|
||||
// array returned by get.php
|
||||
list.append(
|
||||
"<li id=\"" + index + "\" class=\"list-group-item clearfix\">" + entry +
|
||||
"<button class=\"btn btn-danger btn-xs pull-right\" type=\"button\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></button></li>");
|
||||
// Handle button
|
||||
$("#list #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry, "exact");
|
||||
});
|
||||
});
|
||||
|
||||
// Add regex domains if present in returned list data
|
||||
if(data.length === 2)
|
||||
{
|
||||
data[1] = data[1].sort();
|
||||
data[1].forEach(function (entry, index) {
|
||||
// Whitelist entry or Blacklist (exact entry) are in the zero-th
|
||||
// array returned by get.php
|
||||
listw.append(
|
||||
"<li id=\"" + index + "\" class=\"list-group-item clearfix\">" + entry +
|
||||
"<button class=\"btn btn-danger btn-xs pull-right\" type=\"button\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></button></li>");
|
||||
// Handle button
|
||||
$("#list-wildcard #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry, "wild");
|
||||
$("#list-regex #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry, "regex");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal entry
|
||||
list.append(
|
||||
"<li id=\"" + index + "\" class=\"list-group-item clearfix\">" + entry +
|
||||
"<button class=\"btn btn-danger btn-xs pull-right\" type=\"button\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></button></li>");
|
||||
// Handle button
|
||||
$("#list #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry, "exact");
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
list.fadeIn(100);
|
||||
if(listw)
|
||||
@@ -123,12 +127,14 @@ window.onload = refresh(false);
|
||||
function add(arg) {
|
||||
var locallistType = listType;
|
||||
var domain = $("#domain");
|
||||
var wild = false;
|
||||
if(domain.val().length === 0){
|
||||
return;
|
||||
}
|
||||
if(arg === "wild")
|
||||
if(arg === "wild" || arg === "regex")
|
||||
{
|
||||
locallistType = "wild";
|
||||
locallistType = arg;
|
||||
wild = true;
|
||||
}
|
||||
|
||||
var alInfo = $("#alInfo");
|
||||
@@ -143,7 +149,8 @@ function add(arg) {
|
||||
method: "post",
|
||||
data: {"domain":domain.val().trim(), "list":locallistType, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("] Pi-hole blocking is ") === -1) {
|
||||
if (!wild && response.indexOf("] Pi-hole blocking is ") === -1 ||
|
||||
wild && response.length > 1) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(4000).fadeOut(2000, function() {
|
||||
@@ -196,6 +203,10 @@ $("#btnAddWildcard").on("click", function() {
|
||||
add("wild");
|
||||
});
|
||||
|
||||
$("#btnAddRegex").on("click", function() {
|
||||
add("regex");
|
||||
});
|
||||
|
||||
$("#btnRefresh").on("click", function() {
|
||||
refresh(true);
|
||||
});
|
||||
|
||||
@@ -82,7 +82,7 @@ function add(domain,list) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Reset Modal after it has faded out
|
||||
alertModal.one("hidden.bs.modal", function() {
|
||||
alProcessing.show();
|
||||
@@ -136,41 +136,66 @@ $(document).ready(function() {
|
||||
{
|
||||
APIstring += "&domain="+GETDict["domain"];
|
||||
}
|
||||
// If we don't ask filtering and also not for all queries, just request the most recent 100 queries
|
||||
else if(!("all" in GETDict))
|
||||
{
|
||||
var timestamp = Math.floor(Date.now() / 1000);
|
||||
APIstring += "&from="+(timestamp - 600);
|
||||
APIstring += "&until="+(timestamp + 100);
|
||||
APIstring += "=100";
|
||||
}
|
||||
|
||||
tableApi = $("#all-queries").DataTable( {
|
||||
"rowCallback": function( row, data, index ){
|
||||
var blocked = false;
|
||||
|
||||
var dnssec_status = "";
|
||||
if (data[5] === "1")
|
||||
{
|
||||
dnssec_status = "<br><span style=\"color:green\">SECURE</span>";
|
||||
}
|
||||
else if (data[5] === "2")
|
||||
{
|
||||
dnssec_status = "<br><span style=\"color:orange\">INSECURE</span>";
|
||||
}
|
||||
else if (data[5] === "3")
|
||||
{
|
||||
dnssec_status = "<br><span style=\"color:red\">BOGUS</span>";
|
||||
}
|
||||
else if (data[5] === "4")
|
||||
{
|
||||
dnssec_status = "<br><span style=\"color:red\">ABANDONED</span>";
|
||||
}
|
||||
else if (data[5] === "5")
|
||||
{
|
||||
dnssec_status = "<br><span style=\"color:red\">?</span>";
|
||||
}
|
||||
if (data[4] === "1")
|
||||
{
|
||||
blocked = true;
|
||||
$(row).css("color","red");
|
||||
$("td:eq(4)", row).html( "Pi-holed" );
|
||||
$("td:eq(4)", row).html( "Pi-holed"+dnssec_status );
|
||||
$("td:eq(6)", row).html( "<button style=\"color:green; white-space: nowrap;\"><i class=\"fa fa-pencil-square-o\"></i> Whitelist</button>" );
|
||||
}
|
||||
else if (data[4] === "2")
|
||||
{
|
||||
$(row).css("color","green");
|
||||
$("td:eq(4)", row).html( "OK <br class='hidden-lg'>(forwarded)" );
|
||||
$("td:eq(4)", row).html( "OK <br class='hidden-lg'>(forwarded)"+dnssec_status );
|
||||
$("td:eq(6)", row).html( "<button style=\"color:red; white-space: nowrap;\"><i class=\"fa fa-ban\"></i> Blacklist</button>" );
|
||||
}
|
||||
else if (data[4] === "3")
|
||||
{
|
||||
$(row).css("color","green");
|
||||
$("td:eq(4)", row).html( "OK <br class='hidden-lg'>(cached)" );
|
||||
$("td:eq(4)", row).html( "OK <br class='hidden-lg'>(cached)"+dnssec_status );
|
||||
$("td:eq(6)", row).html( "<button style=\"color:red; white-space: nowrap;\"><i class=\"fa fa-ban\"></i> Blacklist</button>" );
|
||||
}
|
||||
else if (data[4] === "4")
|
||||
{
|
||||
blocked = true;
|
||||
$(row).css("color","red");
|
||||
$("td:eq(4)", row).html( "Pi-holed <br class='hidden-lg'>(wildcard)" );
|
||||
$("td:eq(4)", row).html( "Pi-holed <br class='hidden-lg'>(wildcard)");
|
||||
$("td:eq(6)", row).html( "" );
|
||||
}
|
||||
else if (data[4] === "5")
|
||||
{
|
||||
blocked = true;
|
||||
$(row).css("color","red");
|
||||
$("td:eq(4)", row).html( "Pi-holed <br class='hidden-lg'>(blacklist)" );
|
||||
$("td:eq(6)", row).html( "<button style=\"color:green; white-space: nowrap;\"><i class=\"fa fa-pencil-square-o\"></i> Whitelist</button>" );
|
||||
@@ -180,36 +205,47 @@ $(document).ready(function() {
|
||||
$("td:eq(4)", row).html( "Unknown" );
|
||||
$("td:eq(6)", row).html( "" );
|
||||
}
|
||||
if (data[5] === "1")
|
||||
|
||||
// Check for existance of sixth column and display only if not Pi-holed
|
||||
if(data.length > 6 && !blocked)
|
||||
{
|
||||
$("td:eq(5)", row).css("color","green");
|
||||
$("td:eq(5)", row).html( "SECURE" );
|
||||
}
|
||||
else if (data[5] === "2")
|
||||
{
|
||||
$("td:eq(5)", row).css("color","orange");
|
||||
$("td:eq(5)", row).html( "INSECURE" );
|
||||
}
|
||||
else if (data[5] === "3")
|
||||
{
|
||||
$("td:eq(5)", row).css("color","red");
|
||||
$("td:eq(5)", row).html( "BOGUS" );
|
||||
}
|
||||
else if (data[5] === "4")
|
||||
{
|
||||
$("td:eq(5)", row).css("color","red");
|
||||
$("td:eq(5)", row).html( "ABANDONED" );
|
||||
}
|
||||
else if (data[5] === "5")
|
||||
{
|
||||
$("td:eq(5)", row).css("color","red");
|
||||
$("td:eq(5)", row).html( "?" );
|
||||
$("td:eq(5)", row).css("color","black");
|
||||
if (data[6] === "0")
|
||||
{
|
||||
$("td:eq(5)", row).html("N/A");
|
||||
}
|
||||
else if (data[6] === "1")
|
||||
{
|
||||
$("td:eq(5)", row).html("NODATA");
|
||||
}
|
||||
else if (data[6] === "2")
|
||||
{
|
||||
$("td:eq(5)", row).html("NXDOMAIN");
|
||||
}
|
||||
else if (data[6] === "3")
|
||||
{
|
||||
$("td:eq(5)", row).html("CNAME");
|
||||
}
|
||||
else if (data[6] === "4")
|
||||
{
|
||||
$("td:eq(5)", row).html("IP");
|
||||
}
|
||||
else
|
||||
{
|
||||
$("td:eq(5)", row).html("? ("+data[6]+")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$("td:eq(5)", row).css("color","black");
|
||||
$("td:eq(5)", row).html( "-" );
|
||||
$("td:eq(5)", row).html("-");
|
||||
}
|
||||
if(data.length > 7 && data[7] > 0)
|
||||
{
|
||||
var content = $("td:eq(5)", row).html();
|
||||
$("td:eq(5)", row).html(content + " (" + (0.1*data[7]).toFixed(1)+"ms)");
|
||||
}
|
||||
|
||||
},
|
||||
dom: "<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
@@ -221,14 +257,32 @@ $(document).ready(function() {
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "15%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");}else{return data;} }},
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "37%", "render": $.fn.dataTable.render.text() },
|
||||
{ "width" : "4%" },
|
||||
{ "width" : "36%", "render": $.fn.dataTable.render.text() },
|
||||
{ "width" : "8%", "render": $.fn.dataTable.render.text() },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "5%" },
|
||||
{ "width" : "10%" }
|
||||
{ "width" : "14%", "orderData": 4 },
|
||||
{ "width" : "8%", "orderData": 6 },
|
||||
{ "width" : "10%", "orderData": 4 }
|
||||
],
|
||||
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
|
||||
"stateSave": true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// Store current state in client's local storage area
|
||||
localStorage.setItem("query_log_table", JSON.stringify(data));
|
||||
},
|
||||
stateLoadCallback: function(settings) {
|
||||
// Receive previous state from client's local storage area
|
||||
var data = localStorage.getItem("query_log_table");
|
||||
// Return if not available
|
||||
if(data === null){ return null; }
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data["start"] = 0;
|
||||
// Always start with empty search field
|
||||
data["search"]["search"] = "";
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
"columnDefs": [ {
|
||||
"targets": -1,
|
||||
"data": null,
|
||||
|
||||
@@ -68,7 +68,7 @@ $(".confirm-restartdns").confirm({
|
||||
});
|
||||
|
||||
$(".confirm-flushlogs").confirm({
|
||||
text: "By default, the log is flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful. Note that your statistics will be reset and you lose the statistics up to this point. Are you sure you want to flush your logs?",
|
||||
text: "Are you sure you want to flush your logs?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#flushlogsform").submit();
|
||||
@@ -85,7 +85,7 @@ $(".confirm-flushlogs").confirm({
|
||||
});
|
||||
|
||||
$(".confirm-disablelogging").confirm({
|
||||
text: "Note that disabling query logging will render graphs on the web user interface useless. Are you sure you want to disable logging and flush your Pi-hole logs?",
|
||||
text: "Are you sure you want to disable logging and flush your Pi-hole logs?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#disablelogsform").submit();
|
||||
@@ -102,7 +102,7 @@ $(".confirm-disablelogging").confirm({
|
||||
});
|
||||
|
||||
$(".confirm-disablelogging-noflush").confirm({
|
||||
text: "Note that disabling query logging will render graphs on the web user interface useless after this point. Are you sure you want to disable logging?",
|
||||
text: "Are you sure you want to disable logging?",
|
||||
title: "Confirmation required",
|
||||
confirm(button) {
|
||||
$("#disablelogsform-noflush").submit();
|
||||
@@ -209,16 +209,11 @@ $(".nav-tabs a").on("shown.bs.tab", function (e) {
|
||||
window.scrollTo(0, 0);
|
||||
});
|
||||
|
||||
// Auto dismissal for info and error notifications
|
||||
// Auto dismissal for info notifications
|
||||
$(document).ready(function(){
|
||||
var alInfo = $("#alInfo");
|
||||
var alError = $("#alError");
|
||||
if(alInfo.length)
|
||||
{
|
||||
alInfo.delay(3000).fadeOut(2000, function() { alInfo.hide(); });
|
||||
}
|
||||
if(alError.length)
|
||||
{
|
||||
alError.delay(3000).fadeOut(2000, function() { alError.hide(); });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,14 +14,15 @@ function reloadData(){
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL&offset="+offset, function (data)
|
||||
{
|
||||
offset = data["offset"];
|
||||
pre.append(data["lines"]);
|
||||
|
||||
if(scrolling && offset !== data["offset"]) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
|
||||
offset = data["offset"];
|
||||
});
|
||||
|
||||
if(scrolling)
|
||||
{
|
||||
window.scrollTo(0,document.body.scrollHeight);
|
||||
}
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,15 @@ function reloadData(){
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?offset="+offset, function (data)
|
||||
{
|
||||
offset = data["offset"];
|
||||
pre.append(data["lines"]);
|
||||
|
||||
if(scrolling && offset !== data["offset"]) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
|
||||
offset = data["offset"];
|
||||
});
|
||||
|
||||
if(scrolling)
|
||||
{
|
||||
window.scrollTo(0,document.body.scrollHeight);
|
||||
}
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
|
||||
+10
-94
@@ -6,30 +6,8 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
function testFTL($address)
|
||||
function connectFTL($address, $port=4711)
|
||||
{
|
||||
if($address === "127.0.0.1")
|
||||
{
|
||||
$ret = shell_exec("pidof pihole-FTL");
|
||||
return intval($ret);
|
||||
}
|
||||
// We cannot relly test for a distant FTL instance
|
||||
// in the same way, so for any other IP address
|
||||
// we simply return true here and rely on the API
|
||||
// socket connection itself to fail if there is nothing
|
||||
// on that address
|
||||
return true;
|
||||
}
|
||||
|
||||
function connectFTL($address, $port=4711, $quiet=true)
|
||||
{
|
||||
$timeout = 3;
|
||||
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "Attempting to connect to '$address' on port '$port'...\n";
|
||||
}
|
||||
|
||||
if($address == "127.0.0.1")
|
||||
{
|
||||
// Read port
|
||||
@@ -38,104 +16,42 @@ function connectFTL($address, $port=4711, $quiet=true)
|
||||
$port = intval($portfile);
|
||||
}
|
||||
|
||||
// Create a TCP/IP socket
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
|
||||
or die("socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n");
|
||||
|
||||
socket_set_nonblock($socket) or die("Unable to set nonblock on socket\n");
|
||||
|
||||
$time = time();
|
||||
while (!@socket_connect($socket, $address, $port))
|
||||
{
|
||||
$err = socket_last_error($socket);
|
||||
if ($err == 115 || $err == 114)
|
||||
{
|
||||
if ((time() - $time) >= $timeout)
|
||||
{
|
||||
socket_close($socket);
|
||||
die("Connection timed out.\n");
|
||||
}
|
||||
// Wait for 1 millisecond
|
||||
usleep(1000);
|
||||
continue;
|
||||
}
|
||||
die(socket_strerror($err) . "\n");
|
||||
}
|
||||
|
||||
socket_set_block($socket) or die("Unable to set block on socket\n");
|
||||
|
||||
// Set timeout to 3 seconds
|
||||
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec'=>$timeout, 'usec'=>0]);
|
||||
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ['sec'=>$timeout, 'usec'=>0]);
|
||||
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "Success!\n\n";
|
||||
}
|
||||
// Open Internet socket connection
|
||||
$socket = @fsockopen($address, $port, $errno, $errstr, 1.0);
|
||||
|
||||
return $socket;
|
||||
}
|
||||
function sendRequestFTL($requestin, $quiet=true)
|
||||
function sendRequestFTL($requestin)
|
||||
{
|
||||
global $socket;
|
||||
|
||||
$request = ">".$requestin;
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "Sending request (".$request.")...\n";
|
||||
}
|
||||
|
||||
socket_write($socket, $request, strlen($request)) or die("Could not send data to server\n");
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "OK.\n";
|
||||
}
|
||||
fwrite($socket, $request) or die("Could not send data to server\n");
|
||||
}
|
||||
|
||||
function getResponseFTL($quiet=true)
|
||||
function getResponseFTL()
|
||||
{
|
||||
global $socket;
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "Reading response:\n";
|
||||
}
|
||||
|
||||
$response = [];
|
||||
|
||||
while(true)
|
||||
{
|
||||
$out = socket_read($socket, 2048, PHP_NORMAL_READ);
|
||||
if(!$quiet)
|
||||
{
|
||||
echo $out;
|
||||
}
|
||||
$out = fgets($socket);
|
||||
if(strrpos($out,"---EOM---") !== false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
$out = rtrim($out);
|
||||
if(strlen($out) > 0)
|
||||
{
|
||||
$response[] = $out;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function disconnectFTL($quiet=true)
|
||||
function disconnectFTL()
|
||||
{
|
||||
global $socket;
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "Closing socket...";
|
||||
}
|
||||
|
||||
socket_close($socket);
|
||||
|
||||
if(!$quiet)
|
||||
{
|
||||
echo "OK.\n\n";
|
||||
}
|
||||
fclose($socket);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -34,13 +34,14 @@ switch($type) {
|
||||
}
|
||||
break;
|
||||
case "wild":
|
||||
if(!isset($_POST["auditlog"]))
|
||||
echo exec("sudo pihole -wild -q ${_POST['domain']}");
|
||||
else
|
||||
{
|
||||
echo exec("sudo pihole -wild -q -n ${_POST['domain']}");
|
||||
echo exec("sudo pihole -a audit ${_POST['domain']}");
|
||||
}
|
||||
// Escape "." so it won't be interpreted as the wildcard character
|
||||
$domain = str_replace(".","\.",$_POST['domain']);
|
||||
// Add regex filter for legacy wildcard behavior
|
||||
add_regex("(^|\.)".$domain."$");
|
||||
break;
|
||||
case "regex":
|
||||
add_regex($_POST['domain']);
|
||||
break;
|
||||
case "audit":
|
||||
echo exec("sudo pihole -a audit ${_POST['domain']}");
|
||||
break;
|
||||
|
||||
@@ -11,6 +11,9 @@ if($auth)
|
||||
require_once("../../vendor/qrcode.php");
|
||||
$qr = QRCode::getMinimumQRCode($pwhash, QR_ERROR_CORRECT_LEVEL_Q);
|
||||
$qr->printHTML("10px");
|
||||
print("Raw API Token: ");
|
||||
print($pwhash);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ $ERRORLOG = getenv('PHP_ERROR_LOG');
|
||||
if (empty($ERRORLOG)) {
|
||||
$ERRORLOG = '/var/log/lighttpd/error.log';
|
||||
}
|
||||
$regexfile = "/etc/pihole/regex.list";
|
||||
|
||||
function pi_log($message) {
|
||||
error_log(date('Y-m-d H:i:s') . ': ' . $message . "\n", 3, $GLOBALS['ERRORLOG']);
|
||||
@@ -133,6 +134,14 @@ function list_verify($type) {
|
||||
{
|
||||
log_and_die("Not allowed!");
|
||||
}
|
||||
check_domain();
|
||||
|
||||
// Don't check if the added item is a
|
||||
// valid domain for regex expressions
|
||||
// Regex filters are validated by FTL
|
||||
// on import and skipped if invalid
|
||||
if($_POST['list'] !== "regex")
|
||||
{
|
||||
check_domain();
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,822 +0,0 @@
|
||||
<?php
|
||||
/* 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. */
|
||||
|
||||
$log = array();
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
|
||||
$hosts = file_exists("/etc/hosts") ? file("/etc/hosts") : array();
|
||||
|
||||
// Check if pihole.log exists and is readable
|
||||
$logListName = checkfile("/var/log/pihole.log");
|
||||
$log = new \SplFileObject($logListName);
|
||||
|
||||
// Check if preEventHorizon exists and is readable
|
||||
$gravityListName = checkfile("/etc/pihole/list.preEventHorizon");
|
||||
$gravity = new \SplFileObject($gravityListName);
|
||||
|
||||
// whitelist.txt is optional and might not be there
|
||||
$whiteListFile = checkfile("/etc/pihole/whitelist.txt");
|
||||
$whitelist = new \SplFileObject($whiteListFile);
|
||||
|
||||
// blacklist.txt is optional and might not be there
|
||||
$blackListFile = checkfile("/etc/pihole/blacklist.txt");
|
||||
$blacklist = new \SplFileObject($blackListFile);
|
||||
|
||||
if(isset($setupVars["API_PRIVACY_MODE"]))
|
||||
{
|
||||
$privacyMode = $setupVars["API_PRIVACY_MODE"];
|
||||
}
|
||||
else
|
||||
{
|
||||
$privacyMode = false;
|
||||
}
|
||||
|
||||
// Check if time zone is set
|
||||
// https://github.com/pi-hole/AdminLTE/pull/394
|
||||
if (!date_default_timezone_get("date.timezone")) {
|
||||
date_default_timezone_set("UTC");
|
||||
}
|
||||
|
||||
/******* Public Members ********/
|
||||
function getSummaryData() {
|
||||
$domains_being_blocked = gravityCount();
|
||||
|
||||
$dns_queries_today = countDnsQueries();
|
||||
|
||||
$ads_blocked_today = countBlockedQueries();
|
||||
|
||||
$ads_percentage_today = $dns_queries_today > 0 ? ($ads_blocked_today / $dns_queries_today * 100) : 0;
|
||||
|
||||
return array(
|
||||
'domains_being_blocked' => $domains_being_blocked,
|
||||
'dns_queries_today' => $dns_queries_today,
|
||||
'ads_blocked_today' => $ads_blocked_today,
|
||||
'ads_percentage_today' => $ads_percentage_today,
|
||||
);
|
||||
}
|
||||
|
||||
function getOverTimeData() {
|
||||
global $log;
|
||||
|
||||
// Get log lines
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Bin log entries separated into Domains and Ads in 1 hour intervals
|
||||
list($domains_over_time, $ads_over_time) = overTime($dns_queries, $gravity_domains);
|
||||
|
||||
// Align arrays
|
||||
alignTimeArrays($ads_over_time, $domains_over_time);
|
||||
|
||||
// Provide a minimal valid array if there have are no blocked
|
||||
// queries at all. Otherwise the output of the API is inconsistent.
|
||||
if(count($ads_over_time) == 0)
|
||||
{
|
||||
$ads_over_time = [1 => 0];
|
||||
}
|
||||
|
||||
return Array(
|
||||
'domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time,
|
||||
);
|
||||
}
|
||||
|
||||
function getOverTimeData10mins() {
|
||||
global $log;
|
||||
|
||||
// Get log lines
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Bin log entries separated into Domains and Ads in 10 minute intervals
|
||||
list($domains_over_time, $ads_over_time) = overTime10mins($dns_queries, $gravity_domains);
|
||||
|
||||
// Align arrays (in case there have been hours without ad queries)
|
||||
alignTimeArrays($ads_over_time, $domains_over_time);
|
||||
|
||||
// Provide a minimal valid array if there have are no blocked
|
||||
// queries at all. Otherwise the output of the API is inconsistent.
|
||||
if(count($ads_over_time) == 0)
|
||||
{
|
||||
$ads_over_time = [1 => 0];
|
||||
}
|
||||
|
||||
return Array(
|
||||
'domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time,
|
||||
);
|
||||
}
|
||||
|
||||
// Test if variable exists and is positive
|
||||
function ispositive(&$arg)
|
||||
{
|
||||
if(isset($arg))
|
||||
{
|
||||
if($arg > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTopItems($argument) {
|
||||
global $log,$setupVars,$privacyMode;
|
||||
|
||||
// Process log file
|
||||
$dns_domains = getDnsQueryDomains($log);
|
||||
// Get list of ad domains
|
||||
$gravity_domains = getGravity();
|
||||
|
||||
// Exclude domains the user doesn't want to see
|
||||
if(isset($setupVars["API_EXCLUDE_DOMAINS"]))
|
||||
{
|
||||
excludeFromList($dns_domains, "API_EXCLUDE_DOMAINS");
|
||||
}
|
||||
|
||||
// Sort array in descending order
|
||||
arsort($dns_domains);
|
||||
|
||||
// Prepare arrays and counters for Top Items
|
||||
$topDomains = []; $domaincounter = 0;
|
||||
$topAds = []; $adcounter = 0;
|
||||
|
||||
// Default number of Top Items to show is 10
|
||||
$qty = 10;
|
||||
|
||||
// If argument is numeric, the user may want to
|
||||
// see a different number of entries
|
||||
if(is_numeric($argument))
|
||||
{
|
||||
$qty = intval($argument);
|
||||
}
|
||||
|
||||
// Process sorted domain names
|
||||
foreach ($dns_domains as $key => $value) {
|
||||
if(ispositive($gravity_domains[$key]) && $adcounter < $qty)
|
||||
{
|
||||
// New entry for Top Ads
|
||||
$topAds[$key] = $value;
|
||||
$adcounter++;
|
||||
}
|
||||
else if($domaincounter < $qty && !$privacyMode)
|
||||
{
|
||||
// New entry for Top Domains
|
||||
$topDomains[$key] = $value;
|
||||
$domaincounter++;
|
||||
}
|
||||
elseif($domaincounter >= $qty && $adcounter >= $qty)
|
||||
{
|
||||
// Already collected enough entries for both lists
|
||||
// Exit loop early
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Array(
|
||||
'top_queries' => $topDomains,
|
||||
'top_ads' => $topAds,
|
||||
);
|
||||
}
|
||||
|
||||
function getRecentItems($qty) {
|
||||
global $log;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
return Array(
|
||||
'recent_queries' => getRecent($dns_queries, $qty)
|
||||
);
|
||||
}
|
||||
|
||||
function getIpvType() {
|
||||
global $log;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$queryTypes = array();
|
||||
|
||||
foreach($dns_queries as $query) {
|
||||
$info = trim(explode(": ", $query)[1]);
|
||||
$queryType = explode(" ", $info)[0];
|
||||
if (isset($queryTypes[$queryType])) {
|
||||
$queryTypes[$queryType]++;
|
||||
}
|
||||
else {
|
||||
$queryTypes[$queryType] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $queryTypes;
|
||||
}
|
||||
|
||||
function resolveIPs(&$array) {
|
||||
$hostarray = [];
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$hostname = gethostbyaddr($key);
|
||||
// If we found a hostname for the IP, replace it
|
||||
if($hostname)
|
||||
{
|
||||
// Generate HOST entry
|
||||
$hostarray["$hostname|$key"] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate IP entry
|
||||
$hostarray[$key] = $value;
|
||||
}
|
||||
}
|
||||
$array = $hostarray;
|
||||
|
||||
// Sort new array
|
||||
arsort($array);
|
||||
}
|
||||
|
||||
function getForwardDestinations() {
|
||||
global $log, $setupVars;
|
||||
$forwards = getForwards($log);
|
||||
$destinations = array();
|
||||
foreach ($forwards as $forward) {
|
||||
$exploded = explode(" ", trim($forward));
|
||||
$dest = $exploded[count($exploded) - 1];
|
||||
if (isset($destinations[$dest])) {
|
||||
$destinations[$dest]++;
|
||||
}
|
||||
else {
|
||||
$destinations[$dest] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(istrue($setupVars["API_GET_UPSTREAM_DNS_HOSTNAME"]))
|
||||
{
|
||||
resolveIPs($destinations);
|
||||
}
|
||||
|
||||
return $destinations;
|
||||
|
||||
}
|
||||
|
||||
// Check for existance of variable
|
||||
// and test it only if it exists
|
||||
function istrue(&$argument) {
|
||||
$ret = false;
|
||||
if(isset($argument))
|
||||
{
|
||||
if($argument)
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function getQuerySources() {
|
||||
global $log, $setupVars;
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$sources = array();
|
||||
foreach($dns_queries as $query) {
|
||||
$exploded = explode(" ", $query);
|
||||
$ip = trim($exploded[count($exploded)-1]);
|
||||
if (isset($sources[$ip])) {
|
||||
$sources[$ip]++;
|
||||
}
|
||||
else {
|
||||
$sources[$ip] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
global $setupVars;
|
||||
if(isset($setupVars["API_EXCLUDE_CLIENTS"]))
|
||||
{
|
||||
excludeFromList($sources, "API_EXCLUDE_CLIENTS");
|
||||
}
|
||||
|
||||
arsort($sources);
|
||||
$sources = array_slice($sources, 0, 10);
|
||||
|
||||
if(istrue($setupVars["API_GET_CLIENT_HOSTNAME"]))
|
||||
{
|
||||
resolveIPs($sources);
|
||||
}
|
||||
|
||||
return Array(
|
||||
'top_sources' => $sources
|
||||
);
|
||||
}
|
||||
|
||||
$showBlocked = false;
|
||||
$showPermitted = false;
|
||||
|
||||
function setShowBlockedPermitted()
|
||||
{
|
||||
global $showBlocked, $showPermitted, $setupVars;
|
||||
if(isset($setupVars["API_QUERY_LOG_SHOW"]))
|
||||
{
|
||||
if($setupVars["API_QUERY_LOG_SHOW"] === "all")
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "permittedonly")
|
||||
{
|
||||
$showBlocked = false;
|
||||
$showPermitted = true;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "blockedonly")
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = false;
|
||||
}
|
||||
elseif($setupVars["API_QUERY_LOG_SHOW"] === "nothing")
|
||||
{
|
||||
$showBlocked = false;
|
||||
$showPermitted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid settings, show everything
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$showBlocked = true;
|
||||
$showPermitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function getAllQueries($orderBy) {
|
||||
global $log,$showBlocked,$showPermitted,$privacyMode,$setupVars;
|
||||
$allQueries = array("data" => array());
|
||||
$dns_queries = getDnsQueries($log);
|
||||
|
||||
$hostnames=array();
|
||||
|
||||
// Create empty array for gravity
|
||||
$gravity_domains = getGravity();
|
||||
$wildcard_domains = getWildcardListContent();
|
||||
|
||||
if(isset($_GET["from"]))
|
||||
{
|
||||
$from = new DateTime($_GET["from"]);
|
||||
}
|
||||
if(isset($_GET["until"]))
|
||||
{
|
||||
$until = new DateTime($_GET["until"]);
|
||||
}
|
||||
|
||||
setShowBlockedPermitted();
|
||||
|
||||
// Privacy mode?
|
||||
if($privacyMode)
|
||||
{
|
||||
$showPermitted = false;
|
||||
}
|
||||
|
||||
if(!$showBlocked && !$showPermitted)
|
||||
{
|
||||
// Nothing to do for us here
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($dns_queries as $query) {
|
||||
$time = new DateTime(substr($query, 0, 16));
|
||||
|
||||
// Check if we want to restrict the time where we want to show queries
|
||||
if(isset($from))
|
||||
{
|
||||
if($time <= $from)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(isset($until))
|
||||
{
|
||||
if($time >= $until)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// print_r([$time->getTimestamp(),$_GET["from"],$_GET["until"]]);
|
||||
|
||||
$exploded = explode(" ", trim($query));
|
||||
$domain = $exploded[count($exploded)-3];
|
||||
|
||||
$status = "";
|
||||
|
||||
if(isset($gravity_domains[$domain]))
|
||||
{
|
||||
if($gravity_domains[$domain] > 0)
|
||||
{
|
||||
// Exact matching gravity domain
|
||||
$status = "Pi-holed (exact)";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Explicitly whitelisted
|
||||
$status = "OK (whitelisted)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test for wildcard blocking
|
||||
foreach ($wildcard_domains as $entry) {
|
||||
if(strpos($domain, $entry) !== false)
|
||||
{
|
||||
$status = "Pi-holed (wildcard)";
|
||||
}
|
||||
}
|
||||
if(!strlen($status))
|
||||
{
|
||||
$status = "OK";
|
||||
}
|
||||
}
|
||||
if((substr($status,0,2) === "Pi" && $showBlocked) || (substr($status,0,2) === "OK" && $showPermitted))
|
||||
{
|
||||
$type = substr($exploded[count($exploded)-4], 6, -1);
|
||||
|
||||
if(istrue($setupVars["API_GET_CLIENT_HOSTNAME"])) {
|
||||
$ip = $exploded[count($exploded) - 1];
|
||||
|
||||
if (isset($hostnames[$ip])) {
|
||||
$client = $hostnames[$ip];
|
||||
} else {
|
||||
$hostnames[$ip] = gethostbyaddr($ip);
|
||||
$client = $hostnames[$ip];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$client = $exploded[count($exploded)-1];
|
||||
}
|
||||
|
||||
if($orderBy == "orderByClientDomainTime"){
|
||||
$allQueries['data'][hasHostName($client)][$domain][$time->format('Y-m-d T H:i:s')] = $status;
|
||||
}elseif ($orderBy == "orderByClientTimeDomain"){
|
||||
$allQueries['data'][hasHostName($client)][$time->format('Y-m-d T H:i:s')][$domain] = $status;
|
||||
}elseif ($orderBy == "orderByTimeClientDomain"){
|
||||
$allQueries['data'][$time->format('Y-m-d T H:i:s')][hasHostName($client)][$domain] = $status;
|
||||
}elseif ($orderBy == "orderByTimeDomainClient"){
|
||||
$allQueries['data'][$time->format('Y-m-d T H:i:s')][$domain][hasHostName($client)] = $status;
|
||||
}elseif ($orderBy == "orderByDomainClientTime"){
|
||||
$allQueries['data'][$domain][hasHostName($client)][$time->format('Y-m-d T H:i:s')] = $status;
|
||||
}elseif ($orderBy == "orderByDomainTimeClient"){
|
||||
$allQueries['data'][$domain][$time->format('Y-m-d T H:i:s')][hasHostName($client)] = $status;
|
||||
}else{
|
||||
array_push($allQueries['data'], array(
|
||||
$time->format('Y-m-d T H:i:s'),
|
||||
$type,
|
||||
$domain,
|
||||
hasHostName($client),
|
||||
$status,
|
||||
""
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $allQueries;
|
||||
}
|
||||
|
||||
function tailPiholeLog($param) {
|
||||
// Not using SplFileObject here, since direct
|
||||
// usage of f-streams will be much faster for
|
||||
// files as large as the pihole.log
|
||||
global $logListName;
|
||||
$file = fopen($logListName,"r");
|
||||
$offset = intval($param);
|
||||
if($offset > 0)
|
||||
{
|
||||
// Seeks on the file pointer where we want to continue reading is known
|
||||
fseek($file, $offset);
|
||||
$lines = [];
|
||||
while (!feof($file)) {
|
||||
array_push($lines,fgets($file));
|
||||
}
|
||||
return ["offset" => ftell($file), "lines" => $lines];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Locate the current position of the file read/write pointer
|
||||
fseek($file, -1, SEEK_END);
|
||||
// Add one to skip the very last "\n" in the log file
|
||||
return ["offset" => ftell($file)+1];
|
||||
}
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
/******** Private Members ********/
|
||||
function gravityCount() {
|
||||
global $gravityListName,$blackListFile;
|
||||
$preEventHorizon = exec("grep -c ^ $gravityListName");
|
||||
$blacklist = exec("grep -c ^ $blackListFile");
|
||||
return ($preEventHorizon + $blacklist);
|
||||
}
|
||||
|
||||
function getDnsQueries(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function getDnsQueryDomains(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$domains = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") !== false) {
|
||||
$exploded = explode(" ", $line);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
if (isset($domains[$domain])) {
|
||||
$domains[$domain]++;
|
||||
}
|
||||
else {
|
||||
$domains[$domain] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $domains;
|
||||
}
|
||||
|
||||
function countDnsQueries() {
|
||||
global $logListName;
|
||||
return intval(exec("grep -c \": query\\[A\" $logListName"));
|
||||
}
|
||||
|
||||
function getDnsQueriesAll(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": query[A") || strpos($line, "gravity.list") || strpos($line, ": forwarded") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function getDomains($file, &$array, $action){
|
||||
$file->rewind();
|
||||
foreach ($file as $line) {
|
||||
// Strip newline (and possibly carriage return) from end of key
|
||||
$key = rtrim($line);
|
||||
// if $action = true -> we want that domain to be ADDED to the list
|
||||
// doesn't harm to do this if it has already been set before
|
||||
// (e.g. once in gravity list, once in blacklist)
|
||||
if($action && strlen($key) > 0)
|
||||
{
|
||||
// $action is true (we want to add) *and* key is not empty
|
||||
$array[$key] = 1;
|
||||
}
|
||||
elseif(!$action && isset($array[$key]))
|
||||
{
|
||||
// $action is false (we want to remove) *and* key is set
|
||||
$array[$key] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getWildcardListContent() {
|
||||
$rawList = file_get_contents(checkfile("/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 array_unique($list);
|
||||
|
||||
}
|
||||
|
||||
function getGravity() {
|
||||
global $gravity,$whitelist,$blacklist;
|
||||
$domains = [];
|
||||
|
||||
// ADD (true) preEventHorizon domains
|
||||
getDomains($gravity, $domains, true);
|
||||
|
||||
// ADD (true) blacklist domains
|
||||
getDomains($blacklist, $domains, true);
|
||||
|
||||
// REMOVE (false) whitelist domains
|
||||
getDomains($whitelist, $domains, false);
|
||||
|
||||
return $domains;
|
||||
}
|
||||
|
||||
function getBlockedQueries(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
$exploded = explode(" ", str_replace(" "," ",$line));
|
||||
if(count($exploded) == 8 || count($exploded) == 10) {
|
||||
// Structure of data is currently like:
|
||||
// Array
|
||||
// (
|
||||
// [0] => Dec
|
||||
// [1] => 19
|
||||
// [2] => 11:21:51
|
||||
// [3] => dnsmasq[2584]:
|
||||
// [4] => /etc/pihole/gravity.list
|
||||
// [5] => doubleclick.com
|
||||
// [6] => is
|
||||
// [7] => ip.of.pi.hole
|
||||
// )
|
||||
// with extra logging enabled
|
||||
// Array
|
||||
// (
|
||||
// [0] => Dec
|
||||
// [1] => 19
|
||||
// [2] => 11:21:51
|
||||
// [3] => dnsmasq[2584]:
|
||||
// [4] => 1 (identifier)
|
||||
// [5] => 1.2.3.4/12345
|
||||
// [6] => /etc/pihole/gravity.list
|
||||
// [7] => doubleclick.com
|
||||
// [8] => is
|
||||
// [9] => ip.of.pi.hole
|
||||
// )
|
||||
$list = $exploded[count($exploded)-4];
|
||||
$is = $exploded[count($exploded)-2];
|
||||
// Consider only gravity.list as DNS source (not e.g. hostname.list)
|
||||
if(substr($list, strlen($list) - 12, 12) === "gravity.list" && $is === "is") {
|
||||
$lines[] = $line;
|
||||
};
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function countBlockedQueries() {
|
||||
global $logListName;
|
||||
// Blocked due to gravity entries (ad lists + blacklist)
|
||||
$gravityblocked = intval(exec("grep -c -e \"gravity\.list.*is\" $logListName"));
|
||||
|
||||
// Blocked due to wildcard entries
|
||||
$wildcard_domains = getWildcardListContent();
|
||||
$wildcardblocked = 0;
|
||||
foreach ($wildcard_domains as $domain) {
|
||||
$wildcardblocked += intval(exec("grep -c -e \"config.*$domain is\" $logListName"));
|
||||
}
|
||||
|
||||
return $gravityblocked +$wildcardblocked;
|
||||
}
|
||||
|
||||
function getForwards(\SplFileObject $log) {
|
||||
$log->rewind();
|
||||
$lines = [];
|
||||
foreach ($log as $line) {
|
||||
if(strpos($line, ": forwarded") !== false) {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function excludeFromList(&$array,$key)
|
||||
{
|
||||
global $setupVars;
|
||||
$domains = explode(",",$setupVars[$key]);
|
||||
foreach ($domains as $domain) {
|
||||
if(isset($array[$domain]))
|
||||
{
|
||||
unset($array[$domain]);
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
function overTime($entries, $gravity_domains) {
|
||||
$byTimeDomains = [];
|
||||
$byTimeAds = [];
|
||||
foreach ($entries as $entry) {
|
||||
$time = date_create(substr($entry, 0, 16));
|
||||
$hour = $time->format('G');
|
||||
|
||||
$exploded = explode(" ", $entry);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
|
||||
if(ispositive($gravity_domains[$domain]))
|
||||
{
|
||||
if (isset($byTimeAds[$time])) {
|
||||
$byTimeAds[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeAds[$time] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($byTimeDomains[$time])) {
|
||||
$byTimeDomains[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeDomains[$time] = 1;
|
||||
}
|
||||
}
|
||||
return [$byTimeDomains,$byTimeAds];
|
||||
}
|
||||
|
||||
function overTime10mins($entries, $gravity_domains=[]) {
|
||||
$byTimeDomains = [];
|
||||
$byTimeAds = [];
|
||||
foreach ($entries as $entry) {
|
||||
$time = date_create(substr($entry, 0, 16));
|
||||
$hour = $time->format('G');
|
||||
$minute = $time->format('i');
|
||||
|
||||
// 00:00 - 00:09 -> 0
|
||||
// 00:10 - 00:19 -> 1
|
||||
// ...
|
||||
// 12:00 - 12:10 -> 72
|
||||
// ...
|
||||
// 15:30 - 15:39 -> 93
|
||||
// etc.
|
||||
$time = ($minute-$minute%10)/10 + 6*$hour;
|
||||
|
||||
$exploded = explode(" ", $entry);
|
||||
$domain = trim($exploded[count($exploded) - 3]);
|
||||
|
||||
if(ispositive($gravity_domains[$domain]))
|
||||
{
|
||||
if (isset($byTimeAds[$time])) {
|
||||
$byTimeAds[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeAds[$time] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($byTimeDomains[$time])) {
|
||||
$byTimeDomains[$time]++;
|
||||
}
|
||||
else {
|
||||
$byTimeDomains[$time] = 1;
|
||||
}
|
||||
}
|
||||
return [$byTimeDomains,$byTimeAds];
|
||||
}
|
||||
|
||||
function alignTimeArrays(&$times1, &$times2) {
|
||||
if(count($times1) == 0 || count($times2) < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$max = max(array_merge(array_keys($times1), array_keys($times2)));
|
||||
$min = min(array_merge(array_keys($times1), array_keys($times2)));
|
||||
|
||||
for ($i = $min; $i <= $max; $i++) {
|
||||
if (!isset($times2[$i])) {
|
||||
$times2[$i] = 0;
|
||||
}
|
||||
if (!isset($times1[$i])) {
|
||||
$times1[$i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($times1);
|
||||
ksort($times2);
|
||||
}
|
||||
|
||||
function getRecent($queries, $qty){
|
||||
$recent = array();
|
||||
foreach (array_slice($queries, -$qty) as $query) {
|
||||
$queryArray = array();
|
||||
$exploded = explode(" ", $query);
|
||||
$time = date_create(substr($query, 0, 16));
|
||||
$queryArray['time'] = $time->format('h:i:s a');
|
||||
$queryArray['domain'] = trim($exploded[count($exploded) - 3]);
|
||||
$queryArray['ip'] = trim($exploded[count($exploded)-1]);
|
||||
array_push($recent, $queryArray);
|
||||
|
||||
}
|
||||
return array_reverse($recent);
|
||||
}
|
||||
|
||||
function hasHostName($var){
|
||||
global $hosts;
|
||||
foreach ($hosts as $host){
|
||||
$x = preg_split('/\s+/', $host);
|
||||
if ( $var == $x[0] ){
|
||||
$var = $x[1] . "($var)";
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
?>
|
||||
@@ -45,4 +45,21 @@ if(!function_exists('hash_equals')) {
|
||||
}
|
||||
}
|
||||
|
||||
function add_regex($regex, $mode=FILE_APPEND, $append="\n")
|
||||
{
|
||||
global $regexfile;
|
||||
if(file_put_contents($regexfile, $append.$regex, $mode) === FALSE)
|
||||
{
|
||||
$err = error_get_last()["message"];
|
||||
echo "Unable to add regex \"".htmlspecialchars($regex)."\" to ${regexfile}<br>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");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
+21
-30
@@ -12,51 +12,42 @@ if(!isset($_GET['list']))
|
||||
|
||||
$listtype = $_GET['list'];
|
||||
|
||||
$basedir = "/etc/pihole/";
|
||||
|
||||
require "func.php";
|
||||
|
||||
switch ($listtype) {
|
||||
case "white":
|
||||
$list = getListContent("white");
|
||||
break;
|
||||
case "white":
|
||||
$list = array(getListContent("whitelist.txt"));
|
||||
break;
|
||||
|
||||
case "black":
|
||||
$list = array_merge(getListContent("black"),getWildcardListContent());
|
||||
break;
|
||||
case "black":
|
||||
$exact = getListContent("blacklist.txt");
|
||||
$regex = getListContent("regex.list");
|
||||
$list = array($exact, $regex);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid list parameter");
|
||||
break;
|
||||
default:
|
||||
die("Invalid list parameter");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
function getListContent($type) {
|
||||
$rawList = file_get_contents(checkfile("/etc/pihole/".$type."list.txt"));
|
||||
function getListContent($listname) {
|
||||
global $basedir;
|
||||
$rawList = file_get_contents(checkfile($basedir.$listname));
|
||||
$list = explode("\n", $rawList);
|
||||
|
||||
// Get rid of empty lines
|
||||
// Get rid of empty lines and comments
|
||||
for($i = sizeof($list)-1; $i >= 0; $i--) {
|
||||
if($list[$i] == "")
|
||||
if(strlen($list[$i]) < 1 || $list[$i][0] === '#')
|
||||
unset($list[$i]);
|
||||
}
|
||||
|
||||
return $list;
|
||||
// Re-index list after possible unset() activity
|
||||
$newlist = array_values($list);
|
||||
|
||||
}
|
||||
|
||||
function getWildcardListContent() {
|
||||
$rawList = file_get_contents(checkfile("/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 array_unique($list);
|
||||
return $newlist;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/* 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. */
|
||||
|
||||
function gravity_last_update($raw = false){
|
||||
/*
|
||||
@walter-exit <walter@exclusive-it.nl> | April 23rd, 2018:
|
||||
Checks when the gravity list was last updated, if it exists at all.
|
||||
Returns the info in human-readable format for use on the dashboard,
|
||||
or raw for use by the API.
|
||||
*/
|
||||
$gravitylist = "/etc/pihole/gravity.list";
|
||||
if (file_exists($gravitylist)){
|
||||
$date_file_created_unix = filemtime($gravitylist);
|
||||
$date_file_created = date_create("@".$date_file_created_unix);
|
||||
$date_now = date_create("now");
|
||||
$gravitydiff = date_diff($date_file_created,$date_now);
|
||||
if($raw){
|
||||
$output = array(
|
||||
"file_exists"=> true,
|
||||
"absolute" => $date_file_created_unix,
|
||||
"relative" => array(
|
||||
"days" => $gravitydiff->format("%a"),
|
||||
"hours" => $gravitydiff->format("%H"),
|
||||
"minutes" => $gravitydiff->format("%I"),
|
||||
)
|
||||
);
|
||||
}else{
|
||||
if($gravitydiff->d > 1){
|
||||
$output = $gravitydiff->format("Blocking list updated %a days, %H:%I ago");
|
||||
}elseif($gravitydiff->d == 1){
|
||||
$output = $gravitydiff->format("Blocking list updated one day, %H:%I ago");
|
||||
}else{
|
||||
$output = $gravitydiff->format("Blocking list updated %H:%I ago");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if($raw){
|
||||
$output = array("file_exists"=>false);
|
||||
}else{
|
||||
$output = "Blocking list not found";
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -167,6 +167,7 @@
|
||||
<title>Pi-hole Admin Console</title>
|
||||
<!-- Usually browsers proactively perform domain name resolution on links that the user may choose to follow. We disable DNS prefetching here -->
|
||||
<meta http-equiv="x-dns-prefetch-control" content="off">
|
||||
<meta http-equiv="cache-control" content="max-age=60,private">
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
|
||||
@@ -188,10 +189,6 @@
|
||||
<link href="style/vendor/skin-blue.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="style/pi-hole.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="icon" type="image/png" sizes="160x160" href="img/logo.svg" />
|
||||
<style type="text/css">
|
||||
.glow { text-shadow: 0px 0px 5px #fff; }
|
||||
.small-box span { transition-duration: 500ms }
|
||||
</style>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="scripts/vendor/html5shiv.min.js"></script>
|
||||
@@ -445,7 +442,7 @@ if($auth) {
|
||||
<!-- Whitelist -->
|
||||
<li<?php if($scriptname === "whitelist"){ ?> class="active"<?php } ?>>
|
||||
<a href="list.php?l=white">
|
||||
<i class="fa fa-pencil-square-o"></i> <span>Whitelist</span>
|
||||
<i class="fa fa-check-circle-o "></i> <span>Whitelist</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Blacklist -->
|
||||
@@ -461,7 +458,7 @@ if($auth) {
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-down pull-right" style="padding-right: 5px;"></i>
|
||||
</span>
|
||||
<i class="fa fa-stop"></i> <span>Disable</span> <span id="flip-status-disable"></span>
|
||||
<i class="fa fa-stop"></i> <span>Disable <span id="flip-status-disable"></span></span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li>
|
||||
@@ -493,7 +490,7 @@ if($auth) {
|
||||
<!-- <a href="#" id="flip-status"><i class="fa fa-stop"></i> <span>Disable</span></a> -->
|
||||
</li>
|
||||
<li id="pihole-enable" class="treeview"<?php if ($pistatus == "1") { ?> hidden="true"<?php } ?>>
|
||||
<a href="#"><i class="fa fa-play"></i> <span id="enableLabel">Enable</span> <span id="flip-status-enable"></span></a>
|
||||
<a href="#"><i class="fa fa-play"></i> <span id="enableLabel">Enable <span id="flip-status-enable"></span></span></a>
|
||||
</li>
|
||||
<!-- Tools -->
|
||||
<li class="treeview <?php if(in_array($scriptname, array("gravity.php", "queryads.php", "auditlog.php", "taillog.php", "taillog-FTL.php", "debug.php"))){ ?>active<?php } ?>">
|
||||
@@ -507,13 +504,13 @@ if($auth) {
|
||||
<!-- Run gravity.sh -->
|
||||
<li<?php if($scriptname === "gravity.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="gravity.php">
|
||||
<i class="fa fa-arrow-circle-down"></i> <span>Update Lists</span>
|
||||
<i class="fa fa-arrow-circle-down"></i> <span>Update Gravity</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Query adlists -->
|
||||
<!-- Query Lists -->
|
||||
<li<?php if($scriptname === "queryads.php"){ ?> class="active"<?php } ?>>
|
||||
<a href="queryads.php">
|
||||
<i class="fa fa-search"></i> <span>Query adlists</span>
|
||||
<i class="fa fa-search"></i> <span>Query Lists</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Audit log -->
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<div class="form-group">
|
||||
<div class="checkbox pull-right"><label><input type="checkbox" id="logincookie" name="persistentlogin">Remember me for 7 days</label></div>
|
||||
</div>
|
||||
<button type="submit" href="#" class="btn btn-primary pull-right"><i class="glyphicon glyphicon-log-in"></i> Log in</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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!<br>";
|
||||
}
|
||||
elseif(!is_numeric($port))
|
||||
{
|
||||
$error .= "Port (".htmlspecialchars($port).") is invalid!<br>";
|
||||
}
|
||||
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.<br>";
|
||||
}
|
||||
@@ -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!<br>";
|
||||
}
|
||||
|
||||
// Validate conditional forwarding domain name
|
||||
if(!validDomain($_POST["conditionalForwardingDomain"]))
|
||||
{
|
||||
$error .= "Conditional forwarding domain name (".htmlspecialchars($_POST["conditionalForwardingDomain"]).") is invalid!<br>";
|
||||
}
|
||||
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)."<br>";
|
||||
$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!<br>";
|
||||
}
|
||||
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:
|
||||
|
||||
@@ -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}<br>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}<br>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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<br>\n";
|
||||
echo "Processing blacklist.txt (".count($blacklist)." entries)<br>\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<br>\n";
|
||||
echo "Processing whitelist.txt (".count($whitelist)." entries)<br>\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<br>\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)<br>\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)<br>\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"
|
||||
|
||||
+153
-64
@@ -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.<br>Debugging information:<br>PHP error (".htmlspecialchars($last_error["type"])."): ".htmlspecialchars($last_error["message"])." in ".htmlspecialchars($last_error["file"]).":".htmlspecialchars($last_error["line"]);
|
||||
}
|
||||
|
||||
?>
|
||||
<style type="text/css">
|
||||
.tooltip-inner {
|
||||
max-width: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@-webkit-keyframes Pulse {
|
||||
from {
|
||||
color: #630030;
|
||||
-webkit-text-shadow: 0 0 9px #333;
|
||||
}
|
||||
50% {
|
||||
color: #e33100;
|
||||
-webkit-text-shadow: 0 0 18px #e33100;
|
||||
}
|
||||
to {
|
||||
color: #630030;
|
||||
-webkit-text-shadow: 0 0 9px #333;
|
||||
}
|
||||
}
|
||||
|
||||
p.lookatme {
|
||||
-webkit-animation-name: Pulse;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
}
|
||||
.tooltip-inner {
|
||||
max-width: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php // Check if ad lists should be updated after saving ...
|
||||
@@ -119,13 +114,13 @@ $i = 1;
|
||||
while (isset($setupVars["PIHOLE_DNS_" . $i])) {
|
||||
if (isinserverlist($setupVars["PIHOLE_DNS_" . $i])) {
|
||||
array_push($DNSactive, $setupVars["PIHOLE_DNS_" . $i]);
|
||||
} elseif (strpos($setupVars["PIHOLE_DNS_" . $i], ".")) {
|
||||
} elseif (strpos($setupVars["PIHOLE_DNS_" . $i], ".") !== false) {
|
||||
if (!isset($custom1)) {
|
||||
$custom1 = $setupVars["PIHOLE_DNS_" . $i];
|
||||
} else {
|
||||
$custom2 = $setupVars["PIHOLE_DNS_" . $i];
|
||||
}
|
||||
} elseif (strpos($setupVars["PIHOLE_DNS_" . $i], ":")) {
|
||||
} elseif (strpos($setupVars["PIHOLE_DNS_" . $i], ":") !== false) {
|
||||
if (!isset($custom3)) {
|
||||
$custom3 = $setupVars["PIHOLE_DNS_" . $i];
|
||||
} else {
|
||||
@@ -176,6 +171,13 @@ if (isset($setupVars["DNSMASQ_LISTENING"])) {
|
||||
} else {
|
||||
$DNSinterface = "single";
|
||||
}
|
||||
if (isset($setupVars["CONDITIONAL_FORWARDING"]) && ($setupVars["CONDITIONAL_FORWARDING"] == 1)) {
|
||||
$conditionalForwarding = true;
|
||||
$conditionalForwardingDomain = $setupVars["CONDITIONAL_FORWARDING_DOMAIN"];
|
||||
$conditionalForwardingIP = $setupVars["CONDITIONAL_FORWARDING_IP"];
|
||||
} else {
|
||||
$conditionalForwarding = false;
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
@@ -223,7 +225,7 @@ if (isset($setupVars["API_PRIVACY_MODE"])) {
|
||||
?>
|
||||
|
||||
<?php
|
||||
if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists", "dns", "piholedhcp", "api", "teleporter"))) {
|
||||
if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists", "dns", "piholedhcp", "api", "privacy", "teleporter"))) {
|
||||
$tab = $_GET['tab'];
|
||||
} else {
|
||||
$tab = "sysadmin";
|
||||
@@ -234,10 +236,11 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<li<?php if($tab === "sysadmin"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#sysadmin">System</a></li>
|
||||
<li<?php if($tab === "blocklists"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#blocklists">Block Lists</a></li>
|
||||
<li<?php if($tab === "blocklists"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#blocklists">Blocklists</a></li>
|
||||
<li<?php if($tab === "dns"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#dns">DNS</a></li>
|
||||
<li<?php if($tab === "piholedhcp"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#piholedhcp">DHCP</a></li>
|
||||
<li<?php if($tab === "api"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#api">API / Web interface</a></li>
|
||||
<li<?php if($tab === "privacy"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#privacy">Privacy</a></li>
|
||||
<li<?php if($tab === "teleporter"){ ?> class="active"<?php } ?>><a data-toggle="tab" href="#teleporter">Teleporter</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
@@ -248,7 +251,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<div class="col-md-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Lists used to generate Pi-hole's Gravity</h3>
|
||||
<h3 class="box-title">Blocklists used to generate Pi-hole's Gravity: <?php echo count($adlist); ?></h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="table-responsive">
|
||||
@@ -281,7 +284,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
</table>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea name="newuserlists" class="form-control" rows="1" placeholder="Enter one URL per line to add new ad lists"></textarea>
|
||||
<textarea name="newuserlists" class="form-control" rows="1" placeholder="Enter one URL per line to add new blocklists"></textarea>
|
||||
</div>
|
||||
<input type="hidden" name="field" value="adlists">
|
||||
<input type="hidden" name="token" value="<?php echo $token ?>">
|
||||
@@ -555,7 +558,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<tr data-placement="auto" data-container="body" data-toggle="tooltip"
|
||||
title="Lease type: IPv<?php echo $lease["type"]; ?><br/>Remaining lease time: <?php echo $lease["TIME"]; ?><br/>DHCP UID: <?php echo $lease["clid"]; ?>">
|
||||
<td id="MAC"><?php echo $lease["hwaddr"]; ?></td>
|
||||
<td id="IP"><?php echo $lease["IP"]; ?></td>
|
||||
<td id="IP" data-order="<?php echo bin2hex(inet_pton($lease["IP"])); ?>"><?php echo $lease["IP"]; ?></td>
|
||||
<td id="HOST"><?php echo $lease["host"]; ?></td>
|
||||
<td>
|
||||
<button class="btn btn-warning btn-xs" type="button" id="button" data-static="alert">
|
||||
@@ -584,7 +587,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<?php foreach ($dhcp_static_leases as $lease) { ?>
|
||||
<tr>
|
||||
<td><?php echo $lease["hwaddr"]; ?></td>
|
||||
<td><?php echo $lease["IP"]; ?></td>
|
||||
<td data-order="<?php echo bin2hex(inet_pton($lease["IP"])); ?>"><?php echo $lease["IP"]; ?></td>
|
||||
<td><?php echo $lease["host"]; ?></td>
|
||||
<td><?php if (strlen($lease["hwaddr"]) > 0) { ?>
|
||||
<button class="btn btn-danger btn-xs" type="submit" name="removestatic"
|
||||
@@ -694,7 +697,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<?php if (isset($custom1)){ ?>checked<?php } ?>>
|
||||
</div>
|
||||
<input type="text" name="custom1val" class="form-control"
|
||||
data-inputmask="'alias': 'ip'" data-mask
|
||||
<?php if (isset($custom1)){ ?>value="<?php echo $custom1; ?>"<?php } ?>>
|
||||
</div>
|
||||
<label>Custom 2 (IPv4)</label>
|
||||
@@ -704,7 +706,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<?php if (isset($custom2)){ ?>checked<?php } ?>>
|
||||
</div>
|
||||
<input type="text" name="custom2val" class="form-control"
|
||||
data-inputmask="'alias': 'ip'" data-mask
|
||||
<?php if (isset($custom2)){ ?>value="<?php echo $custom2; ?>"<?php } ?>>
|
||||
</div>
|
||||
<label>Custom 3 (IPv6)</label>
|
||||
@@ -714,7 +715,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<?php if (isset($custom3)){ ?>checked<?php } ?>>
|
||||
</div>
|
||||
<input type="text" name="custom3val" class="form-control"
|
||||
data-inputmask="'alias': 'ipv6'" data-mask
|
||||
<?php if (isset($custom3)){ ?>value="<?php echo $custom3; ?>"<?php } ?>>
|
||||
</div>
|
||||
<label>Custom 4 (IPv6)</label>
|
||||
@@ -724,7 +724,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
<?php if (isset($custom4)){ ?>checked<?php } ?>>
|
||||
</div>
|
||||
<input type="text" name="custom4val" class="form-control"
|
||||
data-inputmask="'alias': 'ipv6'" data-mask
|
||||
<?php if (isset($custom4)){ ?>value="<?php echo $custom4; ?>"<?php } ?>>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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
|
||||
<a href="http://dnssec.vs.uni-due.de/" target="_blank">here</a>.</p>
|
||||
<label>Conditional Forwarding</label>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>Note: The local domain name must match the domain name specified
|
||||
in your router, likely found within the DHCP settings.</p>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="conditionalForwarding" value="conditionalForwarding"
|
||||
<?php if(isset($conditionalForwarding) && ($conditionalForwarding == true)){ ?>checked<?php }
|
||||
?>>Use Conditional Forwarding</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>IP of your router</th>
|
||||
<th>Local domain name</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<div class="input-group">
|
||||
<td>
|
||||
<input type="text" name="conditionalForwardingIP" class="form-control" data-inputmask="'alias': 'ip'" data-mask
|
||||
<?php if(isset($conditionalForwardingIP)){ ?>value="<?php echo $conditionalForwardingIP; ?>"<?php } ?>>
|
||||
</td>
|
||||
<td><input type="text" name="conditionalForwardingDomain" class="form-control" data-mask
|
||||
<?php if(isset($conditionalForwardingDomain)){ ?>value="<?php echo $conditionalForwardingDomain; ?>"<?php } ?>>
|
||||
</td>
|
||||
</div>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 = "";
|
||||
}
|
||||
?>
|
||||
<div id="api" class="tab-pane fade<?php if($tab === "api"){ ?> in active<?php } ?>">
|
||||
<div class="row">
|
||||
@@ -869,39 +910,19 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>Privacy settings (Statistics / Query Log)</h4>
|
||||
<div class="col-md-12">
|
||||
<h4>Query Log</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="querylog-permitted"
|
||||
<?php if ($queryLog === "permittedonly" || $queryLog === "all"){ ?>checked<?php }
|
||||
?>>Show permitted domain entries</label>
|
||||
</div>
|
||||
<div class="checkbox"><label><input type="checkbox" name="querylog-permitted" <?php if($queryLog === "permittedonly" || $queryLog === "all"){ ?>checked<?php } ?>> Show permitted domain entries</label></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="querylog-blocked"
|
||||
<?php if ($queryLog === "blockedonly" || $queryLog === "all"){ ?>checked<?php }
|
||||
?>>Show blocked domain entries</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>Privacy mode</h4>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="privacyMode"
|
||||
<?php if ($privacyMode){ ?>checked<?php }
|
||||
?>>Don't show origin of DNS requests in query log</label>
|
||||
</div>
|
||||
<div class="checkbox"><label><input type="checkbox" name="querylog-blocked" <?php if($queryLog === "blockedonly" || $queryLog === "all"){ ?>checked<?php } ?>> Show blocked domain entries</label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -950,6 +971,13 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
?>>Fahrenheit</label>
|
||||
</div>
|
||||
</div>
|
||||
<h4>Administrator Email Address</h4>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="adminemail"
|
||||
value="<?php echo htmlspecialchars($adminemail); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="field" value="webUI">
|
||||
<input type="hidden" name="token" value="<?php echo $token ?>">
|
||||
</div>
|
||||
@@ -963,6 +991,67 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ######################################################### Privacy (may be expanded further later on) ######################################################### -->
|
||||
<?php
|
||||
// Get privacy level from piholeFTL config array
|
||||
if (isset($piholeFTLConf["PRIVACYLEVEL"])) {
|
||||
$privacylevel = intval($piholeFTLConf["PRIVACYLEVEL"]);
|
||||
} else {
|
||||
$privacylevel = 0;
|
||||
}
|
||||
?>
|
||||
<div id="privacy" class="tab-pane fade<?php if($tab === "privacy"){ ?> in active<?php } ?>">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<form role="form" method="post">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Privacy settings</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4>DNS resolver privacy level</h4>
|
||||
<p>Specify if DNS queries should be anonymized, available options are:
|
||||
<div class="form-group">
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="privacylevel" value="0"
|
||||
<?php if ($privacylevel === 0){ ?>checked<?php }
|
||||
?>>Show everything and record everything<br>Gives maximum amount of statistics</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="privacylevel" value="1"
|
||||
<?php if ($privacylevel === 1){ ?>checked<?php }
|
||||
?>>Hide domains: Display and store all domains as "hidden"<br>This disables the Top Domains and Top Ads tables on the dashboard</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="privacylevel" value="2"
|
||||
<?php if ($privacylevel === 2){ ?>checked<?php }
|
||||
?>>Hide domains and clients: Display and store all domains as "hidden" and all clients as "0.0.0.0"<br>This disables all tables on the dashboard</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="privacylevel" value="3"
|
||||
<?php if ($privacylevel === 3){ ?>checked<?php }
|
||||
?>>Paranoia mode: This disables basically everything except the live anonymous stastics<br>No history is saved at all to the database, and nothing is shown in the query log. Also, there are no top item lists.</label>
|
||||
</div>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
<?php if($privacylevel > 0 && $piHoleLogging){ ?>
|
||||
<p class="lookatme">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.</p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer clearfix">
|
||||
<input type="hidden" name="field" value="privacyLevel">
|
||||
<input type="hidden" name="token" value="<?php echo $token ?>">
|
||||
<button type="submit" class="btn btn-primary pull-right">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ######################################################### Teleporter ######################################################### -->
|
||||
<div id="teleporter" class="tab-pane fade<?php if($tab === "teleporter"){ ?> in active<?php } ?>">
|
||||
<div class="row">
|
||||
@@ -1007,9 +1096,9 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "blocklists"
|
||||
Blacklist (exact)</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="wildlist" value="true"
|
||||
<label><input type="checkbox" name="regexlist" value="true"
|
||||
checked>
|
||||
Blacklist (wildcard)</label>
|
||||
Regex filters</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+61
-1
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
|
||||
<div class="checkbox"><label><input type="checkbox" name="active" checked id="chk1"> Automatic scrolling on update</label></div>
|
||||
<pre id="output" style="width: 100%; height: 100%;"></pre>
|
||||
<pre id="output" style="width: 100%; height: 100%; max-height:650px; overflow-y:scroll;"></pre>
|
||||
<div class="checkbox"><label><input type="checkbox" name="active" checked id="chk2"> Automatic scrolling on update</label></div>
|
||||
|
||||
<?php
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
|
||||
<div class="checkbox"><label><input type="checkbox" name="active" checked id="chk1"> Automatic scrolling on update</label></div>
|
||||
<pre id="output" style="width: 100%; height: 100%;"></pre>
|
||||
<pre id="output" style="width: 100%; height: 100%; max-height:650px; overflow-y:scroll;"></pre>
|
||||
<div class="checkbox"><label><input type="checkbox" name="active" checked id="chk2"> Automatic scrolling on update</label></div>
|
||||
|
||||
<?php
|
||||
|
||||
Reference in New Issue
Block a user