1
0
mirror of https://github.com/pi-hole/pi-hole synced 2025-01-09 15:40:54 +00:00

Merge pull request #1416 from WaLLy3K/blockpage2

Block Page 2.0
This commit is contained in:
WaLLy3K 2017-09-14 20:39:45 +10:00 committed by GitHub
commit e7ae62ba76
3 changed files with 647 additions and 305 deletions

View File

@ -1,136 +1,384 @@
/* CSS Reset */ /* Pi-hole: A black hole for Internet advertisements
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } * (c) 2017 Pi-hole, LLC (https://pi-hole.net)
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } * Network-wide ad blocking via your own hardware.
body { line-height: 1; } *
ol, ul { list-style: none; } * This file is copyright under the latest version of the EUPL.
blockquote, q { quotes: none; } * Please see LICENSE file for your rights under this license. */
blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
table { border-collapse: collapse; border-spacing: 0; }
html { height: 100%; overflow-x: hidden; }
/* General Style */ /* Text Customisation Options ======> */
a { color: rgba(0,60,120,0.95); text-decoration: none; } /* 1E3C5A */ .title:before { content: "Website Blocked"; }
a:hover { color: rgba(210,120,0,0.95); transition-duration: .2s; } /* 255, 128, 0 */ .altBtn:before { content: "Why am I here?"; }
divs a { border-bottom: 1px dashed rgba(30,60,90,0.3); } .linkPH:before { content: "About Pi-hole"; }
b { font-weight: bold; } .linkEmail:before { content: "Contact Admin"; }
i { font-style: italic; }
footer, pre, td { font-family: monospace; padding-left: 15px; } #bpOutput.add:before { content: "Info"; }
/*body, header { background: #E1E1E1; }*/ #bpOutput.add:after { content: "The domain is being whitelisted..."; }
#bpOutput.error:before, .unhandled:before { content: "Error"; }
#bpOutput.unhandled:after { content: "An unhandled exception occured. This may happen when your browser is unable to load jQuery, or when the webserver is denying access to the Pi-hole API."; }
#bpOutput.success:before { content: "Success"; }
#bpOutput.success:after { content: "Website has been whitelisted! You may need to flush your DNS cache"; }
.recentwl:before { content: "This site has been whitelisted. Please flush your DNS cache and/or restart your browser."; }
.unknown:before { content: "This website is not found in any of Pi-hole's blacklists. The reason you have arrived here is unknown."; }
.cname:before { content: "This site is an alias for "; } /* <a href="http://cname.com">cname.com</a> */
.cname:after { content: ", which may be blocked by Pi-hole."; }
.blacklist:before { content: "Manually Blacklisted"; }
.wildcard:before { content: "Manually Blacklisted by Wildcard"; }
.noblock:before { content: "Not found on any Blacklist"; }
#bpBlock:before { content: "Access to the following website has been denied:"; }
#bpFlag:before { content: "This is primarily due to being flagged as:"; }
#bpHelpTxt:before { content: "If you have an ongoing use for this website, please "; }
#bpHelpTxt a:before, #bpHelpTxt span:before { content: "ask the administrator"; }
#bpHelpTxt:after{ content: " of the Pi-hole on this network to have it whitelisted"; }
#bpBack:before { content: "Back to safety"; }
#bpInfo:before { content: "Technical Info"; }
#bpFoundIn:before { content: "This site is found in "; }
#bpFoundIn span:after { content: " of "; }
#bpFoundIn:after { content: " lists:"; }
#bpWhitelist:before { content: "Whitelist"; }
footer span:before { content: "Page generated on "; }
/* Hide whitelisting form entirely */
/* #bpWLButtons { display: none; } */
/* Text Customisation Options <=============================== */
/* http://necolas.github.io/normalize.css ======> */
html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
body { margin: 0; }
article, aside, footer, header, nav, section { display: block; }
h1 { font-size: 2em; margin: 0.67em 0; }
figcaption, figure, main { display: block; }
figure { margin: 1em 40px; }
hr { box-sizing: content-box; height: 0; overflow: visible; }
pre { font-family: monospace, monospace; font-size: 1em; }
a { background-color: transparent; -webkit-text-decoration-skip: objects; }
a:active, a:hover { outline-width: 0; }
abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted; }
b, strong { font-weight: inherit; }
b, strong { font-weight: bolder; }
code, kbd, samp { font-family: monospace, monospace; font-size: 1em; }
dfn { font-style: italic; }
mark { background-color: #ff0; color: #000; }
small { font-size: 80%; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sub { bottom: -0.25em; }
sup { top: -0.5em; }
audio, video { display: inline-block; }
audio:not([controls]) { display: none; height: 0; }
img { border-style: none; }
svg:not(:root) { overflow: hidden; }
button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0; }
button, input { overflow: visible; }
button, select { text-transform: none; }
button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; }
button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; }
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal; }
progress { display: inline-block; vertical-align: baseline; }
textarea { overflow: auto; }
[type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; }
[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; }
[type="search"] { -webkit-appearance: textfield; outline-offset: -2px; }
[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
details, menu { display: block; }
summary { display: list-item; }
canvas { display: inline-block; }
template { display: none; }
[hidden] { display: none; }
/* Normalize.css <=============================== */
html { font-size: 62.5%; }
a { color: #3c8dbc; text-decoration: none; }
a:hover { color: #72afda; text-decoration: underline; }
b { color: rgb(68,68,68); }
p { margin: 0; }
label, .buttons a {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
label, .buttons *:not([disabled]) { cursor: pointer; }
/* Touch device dark tap highlight */
header h1 a, label, .buttons * { -webkit-tap-highlight-color: transparent; }
/* Webkit Focus Glow */
textarea, input, button { outline: none; }
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
src: local("Source Sans Pro"), local("SourceSansPro-Regular"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Regular.ttf") format("truetype");
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 700;
src: local("Source Sans Pro Bold"), local("SourceSansPro-Bold"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Bold.ttf") format("truetype");
}
body { body {
background-image: -webkit-linear-gradient(top, rgba(240,240,240,0.95), rgba(190,190,190,0.95)); background: #dbdbdb url("/admin/img/boxed-bg.jpg") repeat fixed;
background-image: linear-gradient(to bottom, rgba(240,240,240,0.95), rgba(190,190,190,0.95)); color: #333;
background-attachment: fixed; font: 1.4rem "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
color: rgba(64,64,64,0.95); line-height: 2.2rem;
font: 14px, sans-serif; }
line-height: 1em;
/* User is greeted with a splash page when browsing to Pi-hole IP address */
#splashpage { background: #222; color: rgba(255,255,255,0.7); text-align: center; }
#splashpage img { margin: 5px; width: 256px; }
#splashpage b { color: inherit; }
#bpWrapper {
margin: 0 auto;
max-width: 1250px;
box-shadow: 0 0 8px rgba(0,0,0,0.5);
} }
header { header {
min-width: 320px; background: #3c8dbc;
width: 100%;
text-shadow: 0 1px rgba(255,255,255,0.6);
display: table; display: table;
table-layout: fixed; position: relative;
border: 1px solid rgba(0,0,0,0.25);
border-top-color: rgba(255,255,255,0.85);
border-style: solid none;
background-image: -webkit-linear-gradient(top, rgba(240,240,240,0.95), rgba(220,220,220,0.95));
background-image: linear-gradient(to bottom, rgba(240,240,240,0.95), rgba(220,220,220,0.95));
box-shadow: 0 0 1px 1px rgba(0,0,0,0.04);
}
header h1, header div {
display: table-cell;
color: inherit;
font-weight: bold;
vertical-align: middle;
white-space: nowrap;
overflow: hidden;
box-sizing: border-box;
}
header h1 {
font-size: 22px;
font-weight: bold;
width: 100%; width: 100%;
padding: 8px 0;
text-indent: 32px;
background: url("http://pi.hole/admin/img/logo.svg") left no-repeat;
background-size: 30px 22px;
} }
header h1 a, h1 a:hover { color: inherit; } header h1, header h1 a, header .spc, header #bpAlt label {
header .alt { width: 85px; font-size: 0.8em; padding-right: 4px; text-align: right; line-height: 1.25em; } display: table-cell;
.active { color: green; } color: #fff;
.inactive { color: red; } white-space: nowrap;
vertical-align: middle;
height: 50px; /* Must match #bpAbout top value */
}
h1 a {
background-color: rgba(0,0,0,0.1);
font-family: "Helvetica Neue", Helvetica, Arial ,sans-serif;
font-size: 2rem;
font-weight: normal;
min-width: 230px;
text-align: center;
}
h1 a:hover, header #bpAlt:hover { background-color: rgba(0,0,0,0.12); color: inherit; text-decoration: none; }
header .spc { width: 100%; }
header #bpAlt label {
background: url("/admin/img/logo.svg") no-repeat center left 15px;
background-size: 15px 23px;
padding: 0 15px;
text-indent: 30px;
}
[type=checkbox][id$="Toggle"] { display: none; }
[type=checkbox][id$="Toggle"]:checked ~ #bpAbout,
[type=checkbox][id$="Toggle"]:checked ~ #bpMoreInfo {
display: block; }
/* Click anywhere else on screen to hide #bpAbout */
#bpAboutToggle:checked {
display: block;
height: 300px; /* VH Fallback */
height: 100vh;
left: 0;
top: 0;
opacity: 0;
position: absolute;
width: 100%;
}
#bpAbout {
background: #3c8dbc;
border-bottom-left-radius: 5px;
border: 1px solid #FFF;
border-right-width: 0;
box-shadow: -1px 1px 1px rgba(0,0,0,0.12);
box-sizing: border-box;
display: none;
font-size: 1.7rem;
top: 50px;
position: absolute;
right: 0;
width: 280px;
z-index: 1;
}
.aboutPH {
box-sizing: border-box;
color: rgba(255,255,255,0.8);
display: block;
padding: 10px;
width: 100%;
text-align: center;
}
.aboutImg {
background: url("/admin/img/logo.svg") no-repeat center;
background-size: 90px 90px;
border: 3px solid rgba(255,255,255,0.2);
height: 90px;
margin: 0 auto;
padding: 2px;
width: 90px;
}
.aboutPH p { margin: 10px 0; }
.aboutPH small { display: block; font-size: 1.2rem; }
.aboutLink {
background: #fff;
border-top: 1px solid #ddd;
display: table;
font-size: 1.4rem;
text-align: center;
width: 100%;
}
.aboutLink a {
display: table-cell;
padding: 14px;
min-width: 50%;
}
main { main {
display: block; background: #ecf0f5;
width: 80%; font-size: 1.65rem;
padding: 10px; padding: 10px;
font-size: 1em;
background-color: rgba(255,255,255,0.85);
margin: 8px auto;
box-sizing: border-box;
border: 1px solid rgba(0,0,0,0.25);
box-shadow: 4px 4px rgba(0,0,0,0.1);
line-height: 1.2em;
border-radius: 8px;
} }
h2 { /* Rgba is shared with .transparent th */ #bpOutput {
font: 1.15em sans-serif; background: #00c0ef;
background-color: rgba(255,0,0,0.4); border-radius: 3px;
text-shadow: none; border: 1px solid rgba(0,0,0,0.1);
line-height: 1.1em; color: #fff;
padding-bottom: 1px; font-size: 1.4rem;
margin-top: 8px; margin-bottom: 10px;
margin-bottom: 4px; margin-top: 5px;
background: -webkit-linear-gradient(left, rgba(0,0,0,0.25), transparent 80%) no-repeat; padding: 15px;
background: linear-gradient(to right, rgba(0,0,0,0.25), transparent 80%) no-repeat;
background-size: 100% 1px;
background-position: 0 17px;
} }
h2:first-child { margin-top: 0; } #bpOutput:before {
h2 ~ *:not(h2) { margin-left: 4px; } background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='14' viewBox='0 0 7 14'%3E%3Cpath fill='%23fff' d='M6,11a1.371,1.371,0,0,1,1,1v1a1.371,1.371,0,0,1-1,1H1a1.371,1.371,0,0,1-1-1V12a1.371,1.371,0,0,1,1-1H2V8H1A1.371,1.371,0,0,1,0,7V6A1.371,1.371,0,0,1,1,5H4A1.371,1.371,0,0,1,5,6v5H6ZM3.5,0A1.5,1.5,0,1,1,2,1.5,1.5,1.5,0,0,1,3.5,0Z'/%3E%3C/svg%3E") no-repeat center left;
li { padding: 2px 0; } display: block;
li::before { content: "\00BB\00a0"; } font-size: 1.8rem;
li a { position: relative; top: 1px; } /* Center bullet-point arrows */ text-indent: 15px;
}
/* Button Style */ #bpOutput.hidden { display: none; }
.buttons a, button, input, .transparent th a { /* Swapped rgba is shared with input[type='url'] */ #bpOutput.success { background: #00a65a; }
display: inline-block; #bpOutput.error { background: #dd4b39; }
color: rgba(32,32,32,0.9);
font-weight: bold; .blockMsg, .flagMsg {
font: bold 1.8rem Consolas, Courier, monospace;
padding: 5px 10px 10px 10px;
text-indent: 15px;
}
#bpHelpTxt { padding-bottom: 10px; }
.buttons {
border-spacing: 5px 0;
display: table;
width: 100%;
}
.buttons * {
-moz-appearance: none;
-webkit-appearance: none;
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.1);
box-sizing: content-box;
display: table-cell;
font-size: 1.65rem;
margin-right: 5px;
min-height: 20px;
padding: 6px 12px;
position: relative;
text-align: center; text-align: center;
cursor: pointer; vertical-align: top;
text-shadow: 0 1px rgba(255,255,255,0.2); white-space: nowrap;
line-height: 0.86em; width: auto;
font-size: 1em;
padding: 4px 8px;
background: #FAFAFA;
background-image: -webkit-linear-gradient(top, rgba(255,255,255,0.05), rgba(0,0,0,0.05));
background-image: linear-gradient(to bottom, rgba(255,255,255,0.05), rgba(0,0,0,0.05));
border: 1px solid rgba(0,0,0,0.25);
border-radius: 4px;
box-shadow: 0 1px 0 rgba(0,0,0,0.04);
} }
.buttons { white-space: nowrap; width: 100%; display: table; } .buttons a:hover { text-decoration: none; }
.buttons33 { white-space: nowrap; width: 33.333%; display: table; text-align: center; margin-left: 33.333% }
.mini a { width: 50%; }
a.safe { background-color: rgba(0,220,0,0.5); }
button.safe { background-color: rgba(0,220,0,0.5); }
a.warn { background-color: rgba(220,0,0,0.5); }
.blocked a, .mini a { display: table-cell; } /* Button hover dark overlay */
.blocked a.safe50 { width: 50%; background-color: rgba(0,220,0,0.5); } .buttons *:not(input):not([disabled]):hover {
.blocked a.safe33 { width: 33.333%; background-color: rgba(0,220,0,0.5); } background-image: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.1));
color: #FFF;
}
/* Types of text */ /* Button active shadow inset */
.msg { white-space: pre; overflow: auto; -webkit-overflow-scrolling: touch; display: block; line-height: 1.2em; font-weight: bold; font-size: 1.15em; margin: 4px 8px 8px 8px; white-space: pre-line; } .buttons *:not([disabled]):not(input):active {
box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
}
footer { font-size: 0.8em; text-align: center; width: 87%; margin: 4px auto; } /* Input border colour */
.buttons *:not([disabled]):hover, .buttons input:focus {
border-color: rgba(0,0,0,0.25);
}
#bpButtons * { width: 50%; color: #FFF; }
#bpBack { background-color: #00a65a; }
#bpInfo { background-color: #3c8dbc; }
#bpWhitelist { background-color: #dd4b39; }
#blockpage .buttons [type=password][disabled] { color: rgba(0,0,0,1); }
#blockpage .buttons [disabled] { color: rgba(0,0,0,0.55); background-color: #e3e3e3; }
#blockpage .buttons [type=password]:-ms-input-placeholder { color: rgba(51,51,51,0.8); }
input[type=password] { font-size: 1.5rem; }
@keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
#bpMoreToggle:checked ~ #bpMoreInfo { display: block; margin-top: 8px; animation: slidein 0.05s linear; }
#bpMoreInfo { display: none; margin-top: 10px; }
#bpQueryOutput {
font-size: 1.2rem;
line-height: 1.65rem;
margin: 5px 0 0 0;
overflow: auto;
padding: 0 5px;
-webkit-overflow-scrolling: touch;
}
#bpQueryOutput span { margin-right: 4px; }
#bpWLButtons { width: auto; margin-top: 10px; }
#bpWLButtons * { display: inline-block; }
#bpWLDomain { display: none; }
#bpWLPassword { width: 160px; }
#bpWhitelist { color: #fff; }
footer {
background: #fff;
border-top: 1px solid #d2d6de;
color: #444;
font: 1.2rem Consolas, Courier, monospace;
padding: 8px;
}
/* Responsive Content */
@media only screen and (max-width: 500px) {
h1 a { font-size: 1.8rem; min-width: 170px; }
footer span:before { content: "Generated "; }
footer span { display: block; }
}
@media only screen and (min-width: 1251px) {
#bpWrapper, footer { border-radius: 0 0 5px 5px; }
#bpAbout { border-right-width: 1px; }
}

View File

@ -1 +1 @@
var x = "Pi-hole: A black hole for Internet advertisements." var x = ""

View File

@ -1,225 +1,319 @@
<?php <?php
/* Detailed Pi-hole Block Page: Show "Website Blocked" if user browses to site, but not to image/file requests based on the work of WaLLy3K for DietPi & Pi-Hole */ /* 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 validIP($address){ // Sanitise HTTP_HOST output
if (preg_match('/[.:0]/', $address) && !preg_match('/[1-9a-f]/', $address)) { $serverName = htmlspecialchars($_SERVER["HTTP_HOST"]);
// Test if address contains either `:` or `0` but not 1-9 or a-f
return false; // Get values from setupVars.conf
if (is_file("/etc/pihole/setupVars.conf")) {
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
$svFQDN = $setupVars["FQDN"];
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
unset($setupVars);
} else {
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
}
// Set landing page location, found within /var/www/html/
$landPage = "../landing.php";
// Set empty array for hostnames to be accepted as self address for splash page
$authorizedHosts = [];
// Append FQDN to $authorizedHosts
if (!empty($svFQDN)) array_push($authorizedHosts, $svFQDN);
// Append virtual hostname to $authorizedHosts
if (!empty($_SERVER["VIRTUAL_HOST"])) {
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
}
// Set which extension types render as Block Page (Including "" for index.wxyz)
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
// Get extension of current URL
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
// Set mobile friendly viewport
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>';
// Set response header
function setHeader($type = "x") {
header("X-Pi-hole: A black hole for Internet advertisements.");
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
}
// Determine block page redirect type
if ($serverName === "pi.hole") {
exit(header("Location: /admin"));
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
// Set Splash Page output
$splashPage = "
<html><head>
$viewPort
<link rel='stylesheet' href='/pihole/blockingpage.css' type='text/css'/>
</head><body id='splashpage'><img src='/admin/img/logo.svg'/><br/>Pi-<b>hole</b>: Your black hole for Internet advertisements</body></html>
";
// Render splash page or landing page when directly browsing via IP or auth'd hostname
$renderPage = is_file(getcwd()."/$landPage") ? include $landPage : "$splashPage";
unset($serverName, $svFQDN, $svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt, $viewPort);
exit($renderPage);
} elseif ($currentUrlExt === "js") {
// Serve dummy Javascript for blocked domains
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER (e.g: an iframe of a blocked domain)
exit(setHeader().'<html>
<head><script>window.close();</script></head>
<body><img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="></body>
</html>');
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
// Serve SVG upon receiving non $validExtTypes URL extension or query string (e.g: not an iframe of a blocked domain)
$blockImg = '<a href="/"><svg xmlns="http://www.w3.org/2000/svg" width="110" height="16"><defs><style>a {text-decoration: none;} circle {stroke: rgba(152,2,2,0.5); fill: none; stroke-width: 2;} rect {fill: rgba(152,2,2,0.5);} text {opacity: 0.3; font: 11px Arial;}</style></defs><circle cx="8" cy="8" r="7"/><rect x="10.3" y="-6" width="2" height="12" transform="rotate(45)"/><text x="19.3" y="12">Blocked by Pi-hole</text></svg></a>';
exit(setHeader()."<html>
<head>$viewPort</head>
<body>$blockImg</body>
</html>");
}
/* Start processing Block Page from here */
// Determine placeholder text based off $svPasswd presence
$wlPlaceHolder = empty($svPasswd) ? "No admin password set" : "Javascript disabled";
// Define admin email address text
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
// Determine if at least one block list has been generated
if (empty(glob("/etc/pihole/list.0.*.domains")))
die("[ERROR] There are no domain lists generated lists within <code>/etc/pihole/</code>! Please update gravity by running <code>pihole -g</code>, or repair Pi-hole using <code>pihole -r</code>.");
// Set location of adlists file
if (is_file("/etc/pihole/adlists.list")) {
$adLists = "/etc/pihole/adlists.list";
} elseif (is_file("/etc/pihole/adlists.default")) {
$adLists = "/etc/pihole/adlists.default";
} else {
die("[ERROR] File not found: <code>/etc/pihole/adlists.list</code>");
}
// Get all URLs starting with "http" or "www" from adlists and re-index array numerically
$adlistsUrls = array_values(preg_grep("/(^http)|(^www)/i", file($adLists, FILE_IGNORE_NEW_LINES)));
if (empty($adlistsUrls))
die("[ERROR]: There are no adlist URL's found within <code>$adLists</code>");
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
$adlistsCount = count($adlistsUrls) + 3;
// Get results of queryads.php exact search
ini_set("default_socket_timeout", 3);
function queryAds($serverName) {
// Determine the time it takes while querying adlists
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
$queryAds = file("http://127.0.0.1/admin/scripts/pi-hole/php/queryads.php?domain=$serverName&bp", FILE_IGNORE_NEW_LINES);
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
// Exception Handling
try {
if ($queryTime >= ini_get("default_socket_timeout")) {
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
} elseif (!strpos($queryAds[0], ".") !== false) {
if (strpos($queryAds[0], "No exact results") !== FALSE) return array("0" => "none");
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
} }
return !filter_var($address, FILTER_VALIDATE_IP) === false; return $queryAds;
} catch (Exception $e) {
return array("0" => "error", "1" => $e->getMessage());
}
} }
$uri = escapeshellcmd($_SERVER['REQUEST_URI']); $queryAds = queryAds($serverName);
$serverName = escapeshellcmd($_SERVER['SERVER_NAME']);
// If the server name is 'pi.hole', it's likely a user trying to get to the admin panel. if ($queryAds[0] === "error") {
// Let's be nice and redirect them. die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
if ($serverName === 'pi.hole') } else {
{ $featuredTotal = count($queryAds);
header('HTTP/1.1 301 Moved Permanently');
header("Location: /admin/"); // Place results into key => value array
$queryResults = null;
foreach ($queryAds as $str) {
$value = explode(" ", $str);
@$queryResults[$value[0]] .= "$value[1]";
}
} }
// Retrieve server URI extension (EG: jpg, exe, php) // Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
// strtok($uri, '\?') splits the querystring from the path (if there is a querystring) if (strpos($queryAds[0], "blacklist") !== FALSE) {
ini_set('pcre.recursion_limit',100); $notableFlagClass = "blacklist";
$uriExt = pathinfo(strtok($uri,'\?'), PATHINFO_EXTENSION); $adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
$notableFlagClass = "noblock";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
$wlInfo = "recentwl";
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
$notableFlagClass = "wildcard";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif ($queryAds[0] === "none") {
$featuredTotal = "0";
$notableFlagClass = "noblock";
// Define which URL extensions get rendered as "Website Blocked" // Determine appropriate info message if CNAME exists
$webExt = array('asp', 'htm', 'html', 'php', 'rss', 'xml'); $dnsRecord = dns_get_record("$serverName")[0];
if (array_key_exists("target", $dnsRecord)) {
// Get IPv4 and IPv6 addresses from setupVars.conf (if available) $wlInfo = $dnsRecord['target'];
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf"); } else {
$ipv4 = isset($setupVars["IPV4_ADDRESS"]) ? explode("/", $setupVars["IPV4_ADDRESS"])[0] : $_SERVER['SERVER_ADDR']; $wlInfo = "unknown";
$ipv6 = isset($setupVars["IPV6_ADDRESS"]) ? explode("/", $setupVars["IPV6_ADDRESS"])[0] : $_SERVER['SERVER_ADDR']; }
$AUTHORIZED_HOSTNAMES = array(
$ipv4,
$ipv6,
str_replace(array("[","]"), array("",""), $_SERVER["SERVER_ADDR"]),
"pi.hole",
"localhost");
// Allow user set virtual hostnames
$virtual_host = getenv('VIRTUAL_HOST');
if (!empty($virtual_host))
array_push($AUTHORIZED_HOSTNAMES, $virtual_host);
// Immediately quit since we didn't block this page (the IP address or pi.hole is explicitly requested)
if(validIP($serverName) || in_array($serverName,$AUTHORIZED_HOSTNAMES))
{
http_response_code(404);
die();
} }
if(in_array($uriExt, $webExt) || empty($uriExt)) // Set #bpOutput notification
{ $wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
// Requested resource has an extension listed in $webExt $wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
// or no extension (index access to some folder incl. the root dir)
$showPage = true;
}
else
{
// Something else
$showPage = false;
}
// Handle incoming URI types // Get Pi-hole Core version
if (!$showPage) $phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
{
?>
<html>
<head>
<script>window.close();</script></head>
<body>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
</body>
</html>
<?php
die();
}
// Get Pi-hole version
$piHoleVersion = exec('cd /etc/.pihole/ && git describe --tags --abbrev=0');
// Don't show the URI if it is the root directory
if($uri == "/")
{
$uri = "";
}
// Print $execTime on development branches
// Marginally faster than "git rev-parse --abbrev-ref HEAD"
if (explode("-", $phVersion)[1] != "0")
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<!-- 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. -->
<html> <html>
<head> <head>
<meta charset='UTF-8'/> <meta charset="UTF-8">
<title>Website Blocked</title> <?=$viewPort ?>
<link rel='stylesheet' href='http://pi.hole/pihole/blockingpage.css'/> <?=setHeader() ?>
<link rel='shortcut icon' href='http://pi.hole/admin/img/favicon.png' type='image/png'/> <meta name="robots" content="noindex,nofollow"/>
<meta name='viewport' content='width=device-width,initial-scale=1.0,maximum-scale=1.0, user-scalable=no'/> <meta http-equiv="x-dns-prefetch-control" content="off">
<meta name='robots' content='noindex,nofollow'/> <link rel="shortcut icon" href="http://pi.hole/admin/img/favicon.png" type="image/x-icon"/>
<link rel="stylesheet" href="http://pi.hole/pihole/blockingpage.css" type="text/css"/>
<title> <?=$serverName ?></title>
<script src="http://pi.hole/admin/scripts/vendor/jquery.min.js"></script>
<script>
window.onload = function () {
<?php
// Remove href fallback from "Back to safety" button
if ($featuredTotal > 0) echo '$("#bpBack").removeAttr("href");';
// Enable whitelisting if $svPasswd is present & JS is available
if (!empty($svPasswd) && $featuredTotal > 0) {
echo '$("#bpWLPassword, #bpWhitelist").prop("disabled", false);';
echo '$("#bpWLPassword").attr("placeholder", "Password");';
}
?>
}
</script>
</head> </head>
<body id="body"> <body id="blockpage"><div id="bpWrapper">
<header> <header>
<h1><a href='/'>Website Blocked</a></h1> <h1 id="bpTitle">
</header> <a class="title" href="/"><?php //Website Blocked ?></a>
<main> </h1>
<div>Access to the following site has been blocked:<br/> <div class="spc"></div>
<span class='pre msg'><?php echo $serverName.$uri; ?></span></div>
<div>If you have an ongoing use for this website, please ask the owner of the Pi-hole in your network to have it whitelisted.</div> <input id="bpAboutToggle" type="checkbox"/>
<input id="domain" type="hidden" value="<?php echo $serverName; ?>"> <div id="bpAbout">
<input id="quiet" type="hidden" value="yes"> <div class="aboutPH">
<button id="btnSearch" class="buttons blocked" type="button" style="visibility: hidden;"></button> <div class="aboutImg"/></div>
This page is blocked because it is explicitly contained within the following block list(s): <p>Open Source Ad Blocker
<pre id="output" style="width: 100%; height: 100%;" hidden="true"></pre><br/> <small>Designed for Raspberry Pi</small>
<div class='buttons blocked'> </p>
<a class='safe33' href='javascript:history.back()'>Go back</a>
<a class='safe33' id="whitelisting">Whitelist this page</a>
<a class='safe33' href='javascript:window.close()'>Close window</a>
</div> </div>
<div style="width: 98%; text-align: center; padding: 10px;" hidden="true" id="whitelistingform"> <div class="aboutLink">
<p>Note that whitelisting domains which are blocked using the wildcard method won't work.</p> <a class="linkPH" href="https://github.com/pi-hole/pi-hole/wiki/What-is-Pi-hole%3F-A-simple-explanation"><?php //About PH ?></a>
<p>Password required!</p><br/> <?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
<form> </div>
<input name="list" type="hidden" value="white"><br/> </div>
Domain:<br/>
<input name="domain" value="<?php echo $serverName ?>" disabled><br/><br/> <div id="bpAlt">
Password:<br/> <label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
<input type="password" id="pw" name="pw"><br/><br/> </div>
<button class="buttons33 safe" id="btnAdd" type="button">Whitelist</button> </header>
</form><br/>
<pre id="whitelistingoutput" style="width: 100%; height: 100%; padding: 5px;" hidden="true"></pre><br/> <main>
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
<div id="bpBlock">
<p class="blockMsg"><?=$serverName ?></p>
</div>
<?php if(isset($notableFlagClass)) { ?>
<div id="bpFlag">
<p class="flagMsg <?=$notableFlagClass ?>"></p>
</div>
<?php } ?>
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
<div id="bpButtons" class="buttons">
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
</div>
<input id="bpMoreToggle" type="checkbox">
<div id="bpMoreInfo">
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
<form id="bpWLButtons" class="buttons">
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled/>
<input id="bpWLPassword" type="password" placeholder="<?=$wlPlaceHolder ?>" disabled/><button id="bpWhitelist" type="button" disabled></button>
</form>
</div> </div>
</main> </main>
<footer>Generated <?php echo date('D g:i A, M d'); ?> by Pi-hole <?php echo $piHoleVersion; ?></footer>
<script src="http://pi.hole/admin/scripts/vendor/jquery.min.js"></script> <footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
</div>
<script> <script>
// Create event for when the output is appended to function add() {
(function($) { $("#bpOutput").removeClass("hidden error exception");
var origAppend = $.fn.append; $("#bpOutput").addClass("add");
var domain = "<?=$serverName ?>";
$.fn.append = function () { var pw = $("#bpWLPassword");
return origAppend.apply(this, arguments).trigger("append"); if(domain.length === 0) {
};
})(jQuery);
</script>
<script src="http://pi.hole/admin/scripts/pi-hole/js/queryads.js"></script>
<script>
function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
// Try to detect if page is loaded within iframe
if(inIframe())
{
// Within iframe
// hide content of page
$('#body').hide();
// remove background
document.body.style.backgroundImage = "none";
}
else
{
// Query adlists
$( "#btnSearch" ).click();
}
$( "#whitelisting" ).on( "click", function(){ $( "#whitelistingform" ).removeAttr( "hidden" ); });
// Remove whitelist functionality if the domain was blocked because of a wildcard
$( "#output" ).bind("append", function(){
if($( "#output" ).contents()[0].data.indexOf("Wildcard blocking") !== -1)
{
$( "#whitelisting" ).hide();
$( "#whitelistingform" ).hide();
}
});
function add() {
var domain = $("#domain");
var pw = $("#pw");
if(domain.val().length === 0){
return; return;
} }
$.ajax({ $.ajax({
url: "/admin/scripts/pi-hole/php/add.php", url: "/admin/scripts/pi-hole/php/add.php",
method: "post", method: "post",
data: {"domain":domain.val(), "list":"white", "pw":pw.val()}, data: {"domain":domain, "list":"white", "pw":pw.val()},
success: function(response) { success: function(response) {
$( "#whitelistingoutput" ).removeAttr( "hidden" ); if(response.indexOf("Pi-hole blocking") !== -1) {
if(response.indexOf("Pi-hole blocking") !== -1) setTimeout(function(){window.location.reload(1);}, 10000);
{ $("#bpOutput").removeClass("add");
// Reload page after 5 seconds $("#bpOutput").addClass("success");
setTimeout(function(){window.location.reload(1);}, 5000); } else {
$( "#whitelistingoutput" ).html("---> Success <---<br/>You may have to flush your DNS cache"); $("#bpOutput").removeClass("add");
$("#bpOutput").addClass("error");
$("#bpOutput").html(""+response+"");
} }
else
{
$( "#whitelistingoutput" ).html("---> "+response+" <---");
}
}, },
error: function(jqXHR, exception) { error: function(jqXHR, exception) {
$( "#whitelistingoutput" ).removeAttr( "hidden" ); $("#bpOutput").removeClass("add");
$( "#whitelistingoutput" ).html("---> Unknown Error <---"); $("#bpOutput").addClass("exception");
} }
}); });
} }
// Handle enter button for adding domains <?php if ($featuredTotal > 0) { ?>
$(document).keypress(function(e) { $(document).keypress(function(e) {
if(e.which === 13 && $("#pw").is(":focus")) { if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
add(); add();
} }
}); });
$("#bpWhitelist").on("click", function() {
// Handle buttons
$("#btnAdd").on("click", function() {
add(); add();
}); });
<?php } ?>
</script> </script>
</body> </body></html>
</html>