Merge pull request #1158 from pi-hole/development

[RELEASE] Pi-hole Core 2.12
This commit is contained in:
Mcat12 2017-01-28 19:19:18 -05:00 committed by GitHub
commit 8cb4304c13
13 changed files with 705 additions and 363 deletions

View file

@ -42,7 +42,7 @@ _If you wish to read over the script before running it, run `nano basic-install.
``` ```
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
cd Pi-hole/automated_installer/ cd Pi-hole/automated\ install/
bash basic-install.sh bash basic-install.sh
``` ```
@ -55,17 +55,11 @@ bash basic-install.sh
Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/). Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/).
## Installing the Pi-hole (Click to Watch!) ## What is Pi-hole and how do I install it?
<p align="center"> <p align="center">
<a href=https://www.youtube.com/watch?v=TzFLJqUeirA><img src="https://assets.pi-hole.net/static/global.png"></a> <a href=https://www.youtube.com/watch?v=vKWjx1AQYgs><img src="https://assets.pi-hole.net/static/global.png"></a>
</p> </p>
## Would you like to know more?
**Watch the 60-second video below to get a quick overview**
<p align="center">
<a href=https://youtu.be/9Eti3xibiho><img src="https://assets.pi-hole.net/static/blackhole_web.png"></a>
</p>
## Get Help Or Connect With Us On The Web ## Get Help Or Connect With Us On The Web

View file

@ -17,56 +17,21 @@ gravity="/etc/pihole/gravity.list"
. /etc/pihole/setupVars.conf . /etc/pihole/setupVars.conf
CalcBlockedDomains() { # Borrowed/modified from https://gist.github.com/cjus/1047794
if [ -e "${gravity}" ]; then function GetJSONValue {
# if BOTH IPV4 and IPV6 are in use, then we need to divide total domains by 2. retVal=$(echo $1 | sed 's/\\\\\//\//g' | \
if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]]; then sed 's/[{}]//g' | \
blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1/2}') awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | \
else sed 's/\"\:\"/\|/g' | \
# only one is set. sed 's/[\,]/ /g' | \
blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1}') sed 's/\"//g' | \
fi grep -w $2)
else echo ${retVal##*|}
blockedDomainsTotal="Err."
fi
}
CalcQueriesToday() {
if [ -e "${piLog}" ]; then
queriesToday=$(awk '/query\[/ {print $6}' < "${piLog}" | wc -l)
else
queriesToday="Err."
fi
}
CalcblockedToday() {
if [ -e "${piLog}" ] && [ -e "${gravity}" ];then
blockedToday=$(awk '/\/etc\/pihole\/gravity.list/ && !/address/ {print $6}' < "${piLog}" | wc -l)
else
blockedToday="Err."
fi
}
CalcPercentBlockedToday() {
if [ "${queriesToday}" != "Err." ] && [ "${blockedToday}" != "Err." ]; then
if [ "${queriesToday}" != 0 ]; then #Fixes divide by zero error :)
#scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros
percentBlockedToday=$(echo "scale=4; ${blockedToday}/${queriesToday}*100" | bc)
percentBlockedToday=$(sed 's/.\{2\}$//' <<< "${percentBlockedToday}")
else
percentBlockedToday=0
fi
fi
} }
outputJSON() { outputJSON() {
CalcQueriesToday json=$(curl -s -X GET http://127.0.0.1/admin/api.php?summaryRaw)
CalcblockedToday echo ${json}
CalcPercentBlockedToday
CalcBlockedDomains
printf '{"domains_being_blocked":"%s","dns_queries_today":"%s","ads_blocked_today":"%s","ads_percentage_today":"%s"}\n' "$blockedDomainsTotal" "$queriesToday" "$blockedToday" "$percentBlockedToday"
} }
normalChrono() { normalChrono() {
@ -87,22 +52,17 @@ normalChrono() {
# Uncomment to continually read the log file and display the current domain being blocked # Uncomment to continually read the log file and display the current domain being blocked
#tail -f /var/log/pihole.log | awk '/\/etc\/pihole\/gravity.list/ {if ($7 != "address" && $7 != "name" && $7 != "/etc/pihole/gravity.list") print $7; else;}' #tail -f /var/log/pihole.log | awk '/\/etc\/pihole\/gravity.list/ {if ($7 != "address" && $7 != "name" && $7 != "/etc/pihole/gravity.list") print $7; else;}'
#uncomment next 4 lines to use original query count calculation json=$(curl -s -X GET http://127.0.0.1/admin/api.php?summaryRaw)
#today=$(date "+%b %e")
#todaysQueryCount=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ {print $7}' | wc -l)
#todaysQueryCountV4=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[A\]/ {print $7}' | wc -l)
#todaysQueryCountV6=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[AAAA\]/ {print $7}' | wc -l)
domains=$(printf "%'.f" $(GetJSONValue ${json} "domains_being_blocked")) #add commas in
queries=$(printf "%'.f" $(GetJSONValue ${json} "dns_queries_today"))
blocked=$(printf "%'.f" $(GetJSONValue ${json} "ads_blocked_today"))
LC_NUMERIC=C percentage=$(printf "%0.2f\n" $(GetJSONValue ${json} "ads_percentage_today")) #2 decimal places
CalcQueriesToday echo "Blocking: ${domains}"
CalcblockedToday echo "Queries: ${queries}"
CalcPercentBlockedToday
CalcBlockedDomains echo "Pi-holed: ${blocked} (${percentage}%)"
echo "Blocking: ${blockedDomainsTotal}"
echo "Queries: ${queriesToday}" #same total calculation as dashboard
echo "Pi-holed: ${blockedToday} (${percentBlockedToday}%)"
sleep 5 sleep 5
done done

View file

@ -15,6 +15,7 @@ basename=pihole
piholeDir=/etc/${basename} piholeDir=/etc/${basename}
whitelist=${piholeDir}/whitelist.txt whitelist=${piholeDir}/whitelist.txt
blacklist=${piholeDir}/blacklist.txt blacklist=${piholeDir}/blacklist.txt
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
reload=false reload=false
addmode=true addmode=true
verbose=true verbose=true
@ -47,13 +48,17 @@ helpFunc() {
::: -h, --help Show this help dialog ::: -h, --help Show this help dialog
::: -l, --list Display your ${word}listed domains ::: -l, --list Display your ${word}listed domains
EOM EOM
if [[ "${letter}" == "b" ]]; then
echo "::: -wild, --wildcard Add whitecard entry (only blacklist)"
fi
exit 0 exit 0
} }
EscapeRegexp() { EscapeRegexp() {
# This way we may safely insert an arbitrary # This way we may safely insert an arbitrary
# string in our regular expressions # string in our regular expressions
echo $* | sed "s/[]\\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" # Also remove leading "." if present
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
} }
HandleOther(){ HandleOther(){
@ -61,7 +66,7 @@ HandleOther(){
domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1")
#check validity of domain #check validity of domain
validDomain=$(perl -ne "print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/" <<< "$domain") validDomain=$(echo "${domain}" | perl -lne 'print if /^(?!.*[^a-z0-9-\.].*)\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)*[a-z]{2,63}\b/')
if [ -z "${validDomain}" ]; then if [ -z "${validDomain}" ]; then
echo "::: $1 is not a valid argument or domain name" echo "::: $1 is not a valid argument or domain name"
else else
@ -89,22 +94,51 @@ AddDomain() {
list="$2" list="$2"
domain=$(EscapeRegexp "$1") domain=$(EscapeRegexp "$1")
bool=true if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
#Is the domain in the list we want to add it to?
grep -Ex -q "${domain}" ${list} > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then bool=true
#domain not found in the whitelist file, add it! #Is the domain in the list we want to add it to?
if [[ "${verbose}" == true ]]; then grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
echo "::: Adding $1 to $list..."
fi if [[ "${bool}" == false ]]; then
reload=true #domain not found in the whitelist file, add it!
# Add it to the list we want to add it to if [[ "${verbose}" == true ]]; then
echo "$1" >> ${list} echo "::: Adding $1 to $list..."
else fi
if [[ "${verbose}" == true ]]; then reload=true
echo "::: ${1} already exists in ${list}, no need to add!" # Add it to the list we want to add it to
fi echo "$1" >> "${list}"
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} already exists in ${list}, no need to add!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
source "${piholeDir}/setupVars.conf"
#Remove the /* from the end of the IPv4addr.
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
IPV6_ADDRESS=${IPV6_ADDRESS}
bool=true
#Is the domain in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
if [[ "${verbose}" == true ]]; then
echo "::: Adding $1 to wildcard blacklist..."
fi
reload=true
echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
if [[ ${#IPV6_ADDRESS} > 0 ]] ; then
echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
fi
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} already exists in wildcard blacklist, no need to add!"
fi
fi
fi fi
} }
@ -112,18 +146,38 @@ RemoveDomain() {
list="$2" list="$2"
domain=$(EscapeRegexp "$1") domain=$(EscapeRegexp "$1")
bool=true if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
#Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
grep -Ex -q "${domain}" ${list} > /dev/null 2>&1 || bool=false bool=true
if [[ "${bool}" == true ]]; then #Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
# Remove it from the other one grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
echo "::: Removing $1 from $list..." if [[ "${bool}" == true ]]; then
# /I flag: search case-insensitive # Remove it from the other one
sed -i "/${domain}/Id" ${list} echo "::: Removing $1 from $list..."
reload=true # /I flag: search case-insensitive
else sed -i "/${domain}/Id" "${list}"
if [[ "${verbose}" == true ]]; then reload=true
echo "::: ${1} does not exist in ${list}, no need to remove!" else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} does not exist in ${list}, no need to remove!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
bool=true
#Is it in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo "::: Removing $1 from $list..."
# /I flag: search case-insensitive
sed -i "/address=\/${domain}/Id" "${list}"
reload=true
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} does not exist in ${list}, no need to remove!"
fi
fi fi
fi fi
} }
@ -153,6 +207,7 @@ for var in "$@"; do
case "${var}" in case "${var}" in
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";; "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";; "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
"-wild" | "wildcard" ) listMain="${wildcardlist}";;
"-nr"| "--noreload" ) reload=false;; "-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;; "-d" | "--delmode" ) addmode=false;;
"-f" | "--force" ) force=true;; "-f" | "--force" ) force=true;;

View file

@ -122,6 +122,13 @@ version_check() {
&& log_echo -r "${light_ver}" || (log_echo "lighttpd not installed." && error_found=1) && log_echo -r "${light_ver}" || (log_echo "lighttpd not installed." && error_found=1)
local php_ver="$(php -v |& head -n1)" \ local php_ver="$(php -v |& head -n1)" \
&& log_echo -r "${php_ver}" || (log_echo "PHP not installed." && error_found=1) && log_echo -r "${php_ver}" || (log_echo "PHP not installed." && error_found=1)
(local pi_hole_branch="$(cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD)" && log_echo -r "Pi-hole branch: ${pi_hole_branch}") || log_echo "Unable to obtain Pi-hole branch"
(local pi_hole_rev="$(cd /etc/.pihole/ && git describe --long --dirty --tags)" && log_echo -r "Pi-hole rev: ${pi_hole_rev}") || log_echo "Unable to obtain Pi-hole revision"
(local admin_branch="$(cd /var/www/html/admin && git rev-parse --abbrev-ref HEAD)" && log_echo -r "AdminLTE branch: ${admin_branch}") || log_echo "Unable to obtain AdminLTE branch"
(local admin_rev="$(cd /var/www/html/admin && git describe --long --dirty --tags)" && log_echo -r "AdminLTE rev: ${admin_rev}") || log_echo "Unable to obtain AdminLTE revision"
return "${error_found}" return "${error_found}"
} }
@ -354,10 +361,21 @@ files_check "${ADLISTFILE}"
header_write "Analyzing gravity.list" header_write "Analyzing gravity.list"
gravity_length=$(wc -l "${GRAVITYFILE}") \ gravity_length=$(grep -c ^ "${GRAVITYFILE}") \
&& log_write "${GRAVITYFILE} is ${gravity_length} lines long." \ && log_write "${GRAVITYFILE} is ${gravity_length} lines long." \
|| log_echo "Warning: No gravity.list file found!" || log_echo "Warning: No gravity.list file found!"
header_write "Analyzing pihole.log"
pihole_length=$(grep -c ^ "${PIHOLELOG}") \
&& log_write "${PIHOLELOG} is ${pihole_length} lines long." \
|| log_echo "Warning: No pihole.log file found!"
pihole_size=$(du -h "${PIHOLELOG}" | awk '{ print $1 }') \
&& log_write "${PIHOLELOG} is ${pihole_size}." \
|| log_echo "Warning: No pihole.log file found!"
# Continuously append the pihole.log file to the pihole_debug.log file # Continuously append the pihole.log file to the pihole_debug.log file
dumpPiHoleLog() { dumpPiHoleLog() {
trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT

View file

@ -11,5 +11,10 @@
# (at your option) any later version. # (at your option) any later version.
echo -n "::: Flushing /var/log/pihole.log ..." echo -n "::: Flushing /var/log/pihole.log ..."
echo " " > /var/log/pihole.log # Test if logrotate is available on this system
if command -v /usr/sbin/logrotate &> /dev/null; then
/usr/sbin/logrotate --force /etc/pihole/logrotate
else
echo " " > /var/log/pihole.log
fi
echo "... done!" echo "... done!"

View file

@ -92,12 +92,17 @@ SetWebPassword(){
ProcessDNSSettings() { ProcessDNSSettings() {
source "${setupVars}" source "${setupVars}"
delete_dnsmasq_setting "server=" delete_dnsmasq_setting "server"
add_dnsmasq_setting "server" "${PIHOLE_DNS_1}"
if [[ "${PIHOLE_DNS_2}" != "" ]]; then COUNTER=1
add_dnsmasq_setting "server" "${PIHOLE_DNS_2}" while [[ 1 ]]; do
fi var=PIHOLE_DNS_${COUNTER}
if [ -z "${!var}" ]; then
break;
fi
add_dnsmasq_setting "server" "${!var}"
let COUNTER=COUNTER+1
done
delete_dnsmasq_setting "domain-needed" delete_dnsmasq_setting "domain-needed"
@ -111,31 +116,45 @@ ProcessDNSSettings() {
add_dnsmasq_setting "bogus-priv" add_dnsmasq_setting "bogus-priv"
fi fi
delete_dnsmasq_setting "dnssec"
delete_dnsmasq_setting "trust-anchor="
if [[ "${DNSSEC}" == true ]]; then
echo "dnssec
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
" >> "${dnsmasqconfig}"
fi
} }
SetDNSServers(){ SetDNSServers(){
# Save setting to file # Save setting to file
change_setting "PIHOLE_DNS_1" "${args[2]}" delete_setting "PIHOLE_DNS"
IFS=',' read -r -a array <<< "${args[2]}"
for index in "${!array[@]}"
do
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
done
if [[ "${args[3]}" != "none" ]]; then if [[ "${args[3]}" == "domain-needed" ]]; then
change_setting "PIHOLE_DNS_2" "${args[3]}"
else
change_setting "PIHOLE_DNS_2" ""
fi
if [[ "${args[4]}" == "domain-needed" ]]; then
change_setting "DNS_FQDN_REQUIRED" "true" change_setting "DNS_FQDN_REQUIRED" "true"
else else
change_setting "DNS_FQDN_REQUIRED" "false" change_setting "DNS_FQDN_REQUIRED" "false"
fi fi
if [[ "${args[4]}" == "bogus-priv" || "${args[5]}" == "bogus-priv" ]]; then if [[ "${args[4]}" == "bogus-priv" ]]; then
change_setting "DNS_BOGUS_PRIV" "true" change_setting "DNS_BOGUS_PRIV" "true"
else else
change_setting "DNS_BOGUS_PRIV" "false" change_setting "DNS_BOGUS_PRIV" "false"
fi fi
if [[ "${args[5]}" == "dnssec" ]]; then
change_setting "DNSSEC" "true"
else
change_setting "DNSSEC" "false"
fi
ProcessDNSSettings ProcessDNSSettings
# Restart dnsmasq to load new configuration # Restart dnsmasq to load new configuration
@ -213,10 +232,13 @@ dhcp-authoritative
dhcp-range=${DHCP_START},${DHCP_END},${leasetime} dhcp-range=${DHCP_START},${DHCP_END},${leasetime}
dhcp-option=option:router,${DHCP_ROUTER} dhcp-option=option:router,${DHCP_ROUTER}
dhcp-leasefile=/etc/pihole/dhcp.leases dhcp-leasefile=/etc/pihole/dhcp.leases
domain=${PIHOLE_DOMAIN}
#quiet-dhcp #quiet-dhcp
" > "${dhcpconfig}" " > "${dhcpconfig}"
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
fi
if [[ "${DHCP_IPv6}" == "true" ]]; then if [[ "${DHCP_IPv6}" == "true" ]]; then
echo "#quiet-dhcp6 echo "#quiet-dhcp6
#enable-ra #enable-ra
@ -227,7 +249,7 @@ ra-param=*,0,0
fi fi
else else
rm "${dhcpconfig}" rm "${dhcpconfig}" &> /dev/null
fi fi
} }

View file

@ -74,7 +74,9 @@ if($uri == "/")
<a class='safe33' id="whitelisting">Whitelist this page</a> <a class='safe33' id="whitelisting">Whitelist this page</a>
<a class='safe33' href='javascript:window.close()'>Close window</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">Password required!<br/> <div style="width: 98%; text-align: center; padding: 10px;" hidden="true" id="whitelistingform">
<p>Note that whitelisting domains which are blocked using the wildcard method won't work.</p>
<p>Password required!</p><br/>
<form> <form>
<input name="list" type="hidden" value="white"><br/> <input name="list" type="hidden" value="white"><br/>
Domain:<br/> Domain:<br/>
@ -88,6 +90,16 @@ if($uri == "/")
</main> </main>
<footer>Generated <?php echo date('D g:i A, M d'); ?> by Pi-hole <?php echo $piHoleVersion; ?></footer> <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> <script src="http://pi.hole/admin/scripts/vendor/jquery.min.js"></script>
<script>
// Create event for when the output is appended to
(function($) {
var origAppend = $.fn.append;
$.fn.append = function () {
return origAppend.apply(this, arguments).trigger("append");
};
})(jQuery);
</script>
<script src="http://pi.hole/admin/scripts/pi-hole/js/queryads.js"></script> <script src="http://pi.hole/admin/scripts/pi-hole/js/queryads.js"></script>
<script> <script>
function inIframe () { function inIframe () {
@ -115,6 +127,15 @@ else
$( "#whitelisting" ).on( "click", function(){ $( "#whitelistingform" ).removeAttr( "hidden" ); }); $( "#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() { function add() {
var domain = $("#domain"); var domain = $("#domain");
var pw = $("#pw"); var pw = $("#pw");

9
advanced/logrotate Normal file
View file

@ -0,0 +1,9 @@
/var/log/pihole.log {
daily
copytruncate
rotate 5
compress
delaycompress
notifempty
nomail
}

View file

@ -23,4 +23,7 @@
# Pi-hole: Flush the log daily at 00:00 so it doesn't get out of control # Pi-hole: Flush the log daily at 00:00 so it doesn't get out of control
# Stats will be viewable in the Web interface thanks to the cron job above # Stats will be viewable in the Web interface thanks to the cron job above
# The flush script will use logrotate if available
00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush 00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush
@reboot root /usr/sbin/logrotate /etc/pihole/logrotate

View file

@ -27,7 +27,8 @@ webInterfaceGitUrl="https://github.com/pi-hole/AdminLTE.git"
webInterfaceDir="/var/www/html/admin" webInterfaceDir="/var/www/html/admin"
piholeGitUrl="https://github.com/pi-hole/pi-hole.git" piholeGitUrl="https://github.com/pi-hole/pi-hole.git"
PI_HOLE_LOCAL_REPO="/etc/.pihole" PI_HOLE_LOCAL_REPO="/etc/.pihole"
PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update version) PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update version gravity uninstall webpage)
PI_HOLE_INSTALL_DIR="/opt/pihole"
useUpdateVars=false useUpdateVars=false
IPV4_ADDRESS="" IPV4_ADDRESS=""
@ -52,24 +53,32 @@ reconfigure=false
runUnattended=false runUnattended=false
# Compatibility # Compatibility
distro_check() {
if command -v apt-get &> /dev/null; then if command -v apt-get &> /dev/null; then
#Debian Family #Debian Family
############################################# #############################################
PKG_MANAGER="apt-get" PKG_MANAGER="apt-get"
UPDATE_PKG_CACHE="${PKG_MANAGER} update" UPDATE_PKG_CACHE="${PKG_MANAGER} update"
PKG_INSTALL="${PKG_MANAGER} --yes --no-install-recommends install" PKG_INSTALL=(${PKG_MANAGER} --yes --no-install-recommends install)
# grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE
PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
# ######################################### # #########################################
# fixes for dependancy differences # fixes for dependancy differences
# Debian 7 doesn't have iproute2 use iproute # Debian 7 doesn't have iproute2 use iproute
${PKG_MANAGER} install --dry-run iproute2 > /dev/null 2>&1 && IPROUTE_PKG="iproute2" || IPROUTE_PKG="iproute" if ${PKG_MANAGER} install --dry-run iproute2 > /dev/null 2>&1; then
iproute_pkg="iproute2"
else
iproute_pkg="iproute"
fi
# Prefer the php metapackage if it's there, fall back on the php5 pacakges # Prefer the php metapackage if it's there, fall back on the php5 pacakges
${PKG_MANAGER} install --dry-run php > /dev/null 2>&1 && phpVer="php" || phpVer="php5" if ${PKG_MANAGER} install --dry-run php > /dev/null 2>&1; then
phpVer="php"
else
phpVer="php5"
fi
# ######################################### # #########################################
INSTALLER_DEPS=(apt-utils debconf dhcpcd5 git whiptail) INSTALLER_DEPS=(apt-utils debconf dhcpcd5 git whiptail)
PIHOLE_DEPS=(bc cron curl dnsmasq dnsutils ${IPROUTE_PKG} iputils-ping lighttpd lsof netcat ${phpVer}-common ${phpVer}-cgi sudo unzip wget) PIHOLE_DEPS=(bc cron curl dnsmasq dnsutils ${iproute_pkg} iputils-ping lighttpd lsof netcat ${phpVer}-common ${phpVer}-cgi sudo unzip wget)
LIGHTTPD_USER="www-data" LIGHTTPD_USER="www-data"
LIGHTTPD_GROUP="www-data" LIGHTTPD_GROUP="www-data"
LIGHTTPD_CFG="lighttpd.conf.debian" LIGHTTPD_CFG="lighttpd.conf.debian"
@ -85,7 +94,7 @@ elif command -v rpm &> /dev/null; then
# Fedora and family update cache on every PKG_INSTALL call, no need for a separate update. # Fedora and family update cache on every PKG_INSTALL call, no need for a separate update.
UPDATE_PKG_CACHE=":" UPDATE_PKG_CACHE=":"
PKG_INSTALL="${PKG_MANAGER} install -y" PKG_INSTALL=(${PKG_MANAGER} install -y)
PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
INSTALLER_DEPS=(git iproute net-tools newt procps-ng) INSTALLER_DEPS=(git iproute net-tools newt procps-ng)
PIHOLE_DEPS=(bc bind-utils cronie curl dnsmasq findutils lighttpd lighttpd-fastcgi nmap-ncat php php-common php-cli sudo unzip wget) PIHOLE_DEPS=(bc bind-utils cronie curl dnsmasq findutils lighttpd lighttpd-fastcgi nmap-ncat php php-common php-cli sudo unzip wget)
@ -102,8 +111,8 @@ else
echo "OS distribution not supported" echo "OS distribution not supported"
exit exit
fi fi
}
####### FUNCTIONS ##########
is_repo() { is_repo() {
# Use git to check if directory is currently under VCS, return the value 128 # Use git to check if directory is currently under VCS, return the value 128
# if directory is not a repo. Return 1 if directory does not exist. # if directory is not a repo. Return 1 if directory does not exist.
@ -168,15 +177,19 @@ getGitFiles() {
} }
find_IPv4_information() { find_IPv4_information() {
local route
# Find IP used to route to outside world # Find IP used to route to outside world
IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}') route=$(ip route get 8.8.8.8)
IPV4_ADDRESS=$(ip route get 8.8.8.8| awk '{print $7}') IPv4dev=$(awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}' <<< "${route}")
IPv4gw=$(ip route get 8.8.8.8 | awk '{print $3}') IPv4bare=$(awk '{print $7}' <<< "${route}")
IPV4_ADDRESS=$(ip -o -f inet addr show | grep "${IPv4bare}" | awk '{print $4}' | awk 'END {print}')
IPv4gw=$(awk '{print $3}' <<< "${route}")
} }
get_available_interfaces() { get_available_interfaces() {
# Get available UP interfaces. # Get available UP interfaces.
availableInterfaces=$(ip -o link | grep "state UP" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1) availableInterfaces=$(ip -o link | grep -v "state DOWN\|lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1)
} }
welcomeDialogs() { welcomeDialogs() {
@ -235,32 +248,28 @@ chooseInterface() {
# Loop sentinel variable # Loop sentinel variable
local firstLoop=1 local firstLoop=1
if [[ $(echo "${availableInterfaces}" | wc -l) -eq 1 ]]; then
PIHOLE_INTERFACE="${availableInterfaces}"
return
fi
while read -r line; do
mode="OFF"
if [[ ${firstLoop} -eq 1 ]]; then
firstLoop=0
mode="ON"
fi
interfacesArray+=("${line}" "available" "${mode}")
done <<< "${availableInterfaces}"
# Find out how many interfaces are available to choose from # Find out how many interfaces are available to choose from
interfaceCount=$(echo "${availableInterfaces}" | wc -l) interfaceCount=$(echo "${availableInterfaces}" | wc -l)
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount})
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) if [[ ${interfaceCount} -eq 1 ]]; then
if [[ $? = 0 ]]; then PIHOLE_INTERFACE="${availableInterfaces}"
for desiredInterface in ${chooseInterfaceOptions}; do
PIHOLE_INTERFACE=${desiredInterface}
echo "::: Using interface: $PIHOLE_INTERFACE"
done
else else
echo "::: Cancel selected, exiting...." while read -r line; do
exit 1 mode="OFF"
if [[ ${firstLoop} -eq 1 ]]; then
firstLoop=0
mode="ON"
fi
interfacesArray+=("${line}" "available" "${mode}")
done <<< "${availableInterfaces}"
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount})
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
{ echo "::: Cancel selected. Exiting"; exit 1; }
for desiredInterface in ${chooseInterfaceOptions}; do
PIHOLE_INTERFACE=${desiredInterface}
echo "::: Using interface: $PIHOLE_INTERFACE"
done
fi fi
} }
@ -281,41 +290,37 @@ use4andor6() {
cmd=(whiptail --separate-output --checklist "Select Protocols (press space to select)" ${r} ${c} 2) cmd=(whiptail --separate-output --checklist "Select Protocols (press space to select)" ${r} ${c} 2)
options=(IPv4 "Block ads over IPv4" on options=(IPv4 "Block ads over IPv4" on
IPv6 "Block ads over IPv6" on) IPv6 "Block ads over IPv6" on)
choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { echo "::: Cancel selected. Exiting"; exit 1; }
if [[ $? = 0 ]];then for choice in ${choices}
for choice in ${choices} do
do case ${choice} in
case ${choice} in IPv4 ) useIPv4=true;;
IPv4 ) useIPv4=true;; IPv6 ) useIPv6=true;;
IPv6 ) useIPv6=true;; esac
esac done
done if [[ ${useIPv4} ]]; then
if [[ ${useIPv4} ]]; then find_IPv4_information
find_IPv4_information getStaticIPv4Settings
getStaticIPv4Settings setStaticIPv4
setStaticIPv4 fi
fi if [[ ${useIPv6} ]]; then
if [[ ${useIPv6} ]]; then useIPv6dialog
useIPv6dialog fi
fi echo "::: IPv4 address: ${IPV4_ADDRESS}"
echo "::: IPv4 address: ${IPV4_ADDRESS}" echo "::: IPv6 address: ${IPV6_ADDRESS}"
echo "::: IPv6 address: ${IPV6_ADDRESS}" if [ ! ${useIPv4} ] && [ ! ${useIPv6} ]; then
if [ ! ${useIPv4} ] && [ ! ${useIPv6} ]; then echo "::: Cannot continue, neither IPv4 or IPv6 selected"
echo "::: Cannot continue, neither IPv4 or IPv6 selected" echo "::: Exiting"
echo "::: Exiting"
exit 1
fi
else
echo "::: Cancel selected. Exiting..."
exit 1 exit 1
fi fi
} }
getStaticIPv4Settings() { getStaticIPv4Settings() {
local ipSettingsCorrect
# Ask if the user wants to use DHCP settings as their static IP # Ask if the user wants to use DHCP settings as their static IP
if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address? if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address?
IP address: ${IPV4_ADDRESS} IP address: ${IPV4_ADDRESS}
Gateway: ${IPv4gw}" ${r} ${c}); then Gateway: ${IPv4gw}" ${r} ${c}; then
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict. # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that. whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
@ -326,36 +331,29 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP) # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary # Start a loop to let the user enter their information with the chance to go back and edit it if necessary
until [[ ${ipSettingsCorrect} = True ]]; do until [[ ${ipSettingsCorrect} = True ]]; do
# Ask for the IPv4 address # Ask for the IPv4 address
IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r} ${c} "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r} ${c} "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \
if [[ $? = 0 ]]; then
echo "::: Your static IPv4 address: ${IPV4_ADDRESS}"
# Ask for the gateway
IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${r} ${c} "${IPv4gw}" 3>&1 1>&2 2>&3)
if [[ $? = 0 ]]; then
echo "::: Your static IPv4 gateway: ${IPv4gw}"
# Give the user a chance to review their settings before moving on
if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
IP address: ${IPV4_ADDRESS}
Gateway: ${IPv4gw}" ${r} ${c}); then
# After that's done, the loop ends and we move on
ipSettingsCorrect=True
else
# If the settings are wrong, the loop continues
ipSettingsCorrect=False
fi
else
# Cancelling gateway settings window
ipSettingsCorrect=False
echo "::: Cancel selected. Exiting..."
exit 1
fi
else
# Cancelling IPv4 settings window # Cancelling IPv4 settings window
ipSettingsCorrect=False { ipSettingsCorrect=False; echo "::: Cancel selected. Exiting..."; exit 1; }
echo "::: Cancel selected. Exiting..." echo "::: Your static IPv4 address: ${IPV4_ADDRESS}"
exit 1
fi # Ask for the gateway
IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${r} ${c} "${IPv4gw}" 3>&1 1>&2 2>&3) || \
# Cancelling gateway settings window
{ ipSettingsCorrect=False; echo "::: Cancel selected. Exiting..."; exit 1; }
echo "::: Your static IPv4 gateway: ${IPv4gw}"
# Give the user a chance to review their settings before moving on
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
IP address: ${IPV4_ADDRESS}
Gateway: ${IPv4gw}" ${r} ${c}; then
# After that's done, the loop ends and we move on
ipSettingsCorrect=True
else
# If the settings are wrong, the loop continues
ipSettingsCorrect=False
fi
done done
# End the if statement for DHCP vs. static # End the if statement for DHCP vs. static
fi fi
@ -439,95 +437,88 @@ valid_ip() {
} }
setDNS() { setDNS() {
DNSChooseCmd=(whiptail --separate-output --radiolist "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 6) local DNSSettingsCorrect
DNSChooseOptions=(Google "" on
OpenDNS "" off
Level3 "" off
Norton "" off
Comodo "" off
Custom "" off)
DNSchoices=$("${DNSChooseCmd[@]}" "${DNSChooseOptions[@]}" 2>&1 >/dev/tty)
if [[ $? = 0 ]];then
case ${DNSchoices} in
Google)
echo "::: Using Google DNS servers."
PIHOLE_DNS_1="8.8.8.8"
PIHOLE_DNS_2="8.8.4.4"
;;
OpenDNS)
echo "::: Using OpenDNS servers."
PIHOLE_DNS_1="208.67.222.222"
PIHOLE_DNS_2="208.67.220.220"
;;
Level3)
echo "::: Using Level3 servers."
PIHOLE_DNS_1="4.2.2.1"
PIHOLE_DNS_2="4.2.2.2"
;;
Norton)
echo "::: Using Norton ConnectSafe servers."
PIHOLE_DNS_1="199.85.126.10"
PIHOLE_DNS_2="199.85.127.10"
;;
Comodo)
echo "::: Using Comodo Secure servers."
PIHOLE_DNS_1="8.26.56.26"
PIHOLE_DNS_2="8.20.247.20"
;;
Custom)
until [[ ${DNSSettingsCorrect} = True ]]; do
strInvalid="Invalid"
if [ ! ${PIHOLE_DNS_1} ]; then
if [ ! ${PIHOLE_DNS_2} ]; then
prePopulate=""
else
prePopulate=", ${PIHOLE_DNS_2}"
fi
elif [ ${PIHOLE_DNS_1} ] && [ ! ${PIHOLE_DNS_2} ]; then
prePopulate="${PIHOLE_DNS_1}"
elif [ ${PIHOLE_DNS_1} ] && [ ${PIHOLE_DNS_2} ]; then
prePopulate="${PIHOLE_DNS_1}, ${PIHOLE_DNS_2}"
fi
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "${prePopulate}" 3>&1 1>&2 2>&3) DNSChooseOptions=(Google ""
OpenDNS ""
Level3 ""
Norton ""
Comodo ""
Custom "")
DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 6 \
"${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
{ echo "::: Cancel selected. Exiting"; exit 1; }
case ${DNSchoices} in
Google)
echo "::: Using Google DNS servers."
PIHOLE_DNS_1="8.8.8.8"
PIHOLE_DNS_2="8.8.4.4"
;;
OpenDNS)
echo "::: Using OpenDNS servers."
PIHOLE_DNS_1="208.67.222.222"
PIHOLE_DNS_2="208.67.220.220"
;;
Level3)
echo "::: Using Level3 servers."
PIHOLE_DNS_1="4.2.2.1"
PIHOLE_DNS_2="4.2.2.2"
;;
Norton)
echo "::: Using Norton ConnectSafe servers."
PIHOLE_DNS_1="199.85.126.10"
PIHOLE_DNS_2="199.85.127.10"
;;
Comodo)
echo "::: Using Comodo Secure servers."
PIHOLE_DNS_1="8.26.56.26"
PIHOLE_DNS_2="8.20.247.20"
;;
Custom)
until [[ ${DNSSettingsCorrect} = True ]]; do
strInvalid="Invalid"
if [ ! ${PIHOLE_DNS_1} ]; then
if [ ! ${PIHOLE_DNS_2} ]; then
prePopulate=""
else
prePopulate=", ${PIHOLE_DNS_2}"
fi
elif [ ${PIHOLE_DNS_1} ] && [ ! ${PIHOLE_DNS_2} ]; then
prePopulate="${PIHOLE_DNS_1}"
elif [ ${PIHOLE_DNS_1} ] && [ ${PIHOLE_DNS_2} ]; then
prePopulate="${PIHOLE_DNS_1}, ${PIHOLE_DNS_2}"
fi
if [[ $? = 0 ]]; then piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "${prePopulate}" 3>&1 1>&2 2>&3) || \
PIHOLE_DNS_1=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}') { echo "::: Cancel selected. Exiting"; exit 1; }
PIHOLE_DNS_2=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}') PIHOLE_DNS_1=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}')
if ! valid_ip "${PIHOLE_DNS_1}" || [ ! "${PIHOLE_DNS_1}" ]; then PIHOLE_DNS_2=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}')
PIHOLE_DNS_1=${strInvalid} if ! valid_ip "${PIHOLE_DNS_1}" || [ ! "${PIHOLE_DNS_1}" ]; then
fi PIHOLE_DNS_1=${strInvalid}
if ! valid_ip "${PIHOLE_DNS_2}" && [ "${PIHOLE_DNS_2}" ]; then fi
PIHOLE_DNS_2=${strInvalid} if ! valid_ip "${PIHOLE_DNS_2}" && [ "${PIHOLE_DNS_2}" ]; then
fi PIHOLE_DNS_2=${strInvalid}
else fi
echo "::: Cancel selected, exiting...." if [[ ${PIHOLE_DNS_1} == "${strInvalid}" ]] || [[ ${PIHOLE_DNS_2} == "${strInvalid}" ]]; then
exit 1 whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $PIHOLE_DNS_1\n DNS Server 2: ${PIHOLE_DNS_2}" ${r} ${c}
if [[ ${PIHOLE_DNS_1} == "${strInvalid}" ]]; then
PIHOLE_DNS_1=""
fi fi
if [[ ${PIHOLE_DNS_1} == "${strInvalid}" ]] || [[ ${PIHOLE_DNS_2} == "${strInvalid}" ]]; then if [[ ${PIHOLE_DNS_2} == "${strInvalid}" ]]; then
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $PIHOLE_DNS_1\n DNS Server 2: ${PIHOLE_DNS_2}" ${r} ${c} PIHOLE_DNS_2=""
if [[ ${PIHOLE_DNS_1} == "${strInvalid}" ]]; then
PIHOLE_DNS_1=""
fi
if [[ ${PIHOLE_DNS_2} == "${strInvalid}" ]]; then
PIHOLE_DNS_2=""
fi
DNSSettingsCorrect=False
else
if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $PIHOLE_DNS_1\n DNS Server 2: ${PIHOLE_DNS_2}" ${r} ${c}); then
DNSSettingsCorrect=True
else
# If the settings are wrong, the loop continues
DNSSettingsCorrect=False
fi
fi fi
done DNSSettingsCorrect=False
;; else
esac if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $PIHOLE_DNS_1\n DNS Server 2: ${PIHOLE_DNS_2}" ${r} ${c}); then
else DNSSettingsCorrect=True
echo "::: Cancel selected. Exiting..." else
exit 1 # If the settings are wrong, the loop continues
fi DNSSettingsCorrect=False
fi
fi
done
;;
esac
} }
setLogging() { setLogging() {
@ -610,35 +601,35 @@ clean_existing() {
# Clean an exiting installation to prepare for upgrade/reinstall # Clean an exiting installation to prepare for upgrade/reinstall
# ${1} Directory to clean; ${2} Array of files to remove # ${1} Directory to clean; ${2} Array of files to remove
local clean_directory="${1}" local clean_directory="${1}"
local old_files=${2} shift
local old_files=( "$@" )
for script in "${old_files[@]}"; do for script in "${old_files[@]}"; do
rm -f "${clean_directory}${script}.sh" rm -f "${clean_directory}/${script}.sh"
done done
} }
installScripts() { installScripts() {
# Install the scripts from repository to their various locations # Install the scripts from repository to their various locations
readonly install_dir="/opt/pihole/"
echo ":::" echo ":::"
echo -n "::: Installing scripts from ${PI_HOLE_LOCAL_REPO}..." echo -n "::: Installing scripts from ${PI_HOLE_LOCAL_REPO}..."
# Clear out script files from Pi-hole scripts directory. # Clear out script files from Pi-hole scripts directory.
clean_existing "${install_dir}" "${PI_HOLE_FILES}" clean_existing "${PI_HOLE_INSTALL_DIR}" "${PI_HOLE_FILES[@]}"
# Install files from local core repository # Install files from local core repository
if is_repo "${PI_HOLE_LOCAL_REPO}"; then if is_repo "${PI_HOLE_LOCAL_REPO}"; then
cd "${PI_HOLE_LOCAL_REPO}" cd "${PI_HOLE_LOCAL_REPO}"
install -o "${USER}" -Dm755 -d /opt/pihole install -o "${USER}" -Dm755 -d "${PI_HOLE_INSTALL_DIR}"
install -o "${USER}" -Dm755 -t /opt/pihole/ gravity.sh install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" gravity.sh
install -o "${USER}" -Dm755 -t /opt/pihole/ ./advanced/Scripts/*.sh install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./advanced/Scripts/*.sh
install -o "${USER}" -Dm755 -t /opt/pihole/ ./automated\ install/uninstall.sh install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./automated\ install/uninstall.sh
install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole
install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
echo " done." echo " done."
else else
echo " *** ERROR: Local repo ${core_repo} not found, exiting." echo " *** ERROR: Local repo ${PI_HOLE_LOCAL_REPO} not found, exiting."
exit 1 exit 1
fi fi
} }
@ -757,7 +748,7 @@ install_dependent_packages() {
fi fi
done done
if [[ ${#installArray[@]} -gt 0 ]]; then if [[ ${#installArray[@]} -gt 0 ]]; then
debconf-apt-progress -- ${PKG_INSTALL} "${installArray[@]}" debconf-apt-progress -- "${PKG_INSTALL[@]}" "${installArray[@]}"
return return
fi fi
return 0 return 0
@ -774,7 +765,7 @@ install_dependent_packages() {
fi fi
done done
if [[ ${#installArray[@]} -gt 0 ]]; then if [[ ${#installArray[@]} -gt 0 ]]; then
${PKG_INSTALL} "${installArray[@]}" &> /dev/null "${PKG_INSTALL[@]}" "${installArray[@]}" &> /dev/null
return return
fi fi
return 0 return 0
@ -818,21 +809,23 @@ installPiholeWeb() {
if [ -f "/var/www/html/pihole/blockingpage.css" ]; then if [ -f "/var/www/html/pihole/blockingpage.css" ]; then
echo "::: Existing blockingpage.css detected, not overwriting" echo "::: Existing blockingpage.css detected, not overwriting"
else else
echo -n "::: index.css missing, replacing... " echo -n "::: blockingpage.css missing, replacing... "
cp /etc/.pihole/advanced/blockingpage.css /var/www/html/pihole cp /etc/.pihole/advanced/blockingpage.css /var/www/html/pihole
echo " done!" echo " done!"
fi fi
else else
mkdir /var/www/html/pihole echo "::: Creating directory for blocking page"
install -d /var/www/html/pihole
install -D /etc/.pihole/advanced/{index,blockingpage}.* /var/www/html/pihole/
if [ -f /var/www/html/index.lighttpd.html ]; then if [ -f /var/www/html/index.lighttpd.html ]; then
mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig
else else
printf "\n:::\tNo default index.lighttpd.html file found... not backing up" printf "\n:::\tNo default index.lighttpd.html file found... not backing up"
fi fi
cp /etc/.pihole/advanced/index.* /var/www/html/pihole/.
echo " done!" echo " done!"
fi fi
# Install Sudoer file # Install Sudoer file
echo ":::" echo ":::"
echo -n "::: Installing sudoer file..." echo -n "::: Installing sudoer file..."
@ -878,29 +871,42 @@ runGravity() {
create_pihole_user() { create_pihole_user() {
# Check if user pihole exists and create if not # Check if user pihole exists and create if not
echo "::: Checking if user 'pihole' exists..." echo "::: Checking if user 'pihole' exists..."
id -u pihole &> /dev/null && echo "::: User 'pihole' already exists" || (echo "::: User 'pihole' doesn't exist. Creating..." && useradd -r -s /usr/sbin/nologin pihole) if id -u pihole &> /dev/null; then
echo "::: User 'pihole' already exists"
else
echo "::: User 'pihole' doesn't exist. Creating..."
useradd -r -s /usr/sbin/nologin pihole
fi
} }
configureFirewall() { configureFirewall() {
# Allow HTTP and DNS traffic # Allow HTTP and DNS traffic
if firewall-cmd --state &> /dev/null; then if firewall-cmd --state &> /dev/null; then
echo "::: Configuring FirewallD for httpd and dnsmasq.." whiptail --title "Firewall in use" --yesno "We have detected a running firewall\n\nPi-hole currently requires HTTP and DNS port access.\n\n\n\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
{ echo -e ":::\n::: Not installing firewall rulesets."; return 0; }
echo -e ":::\n:::\n Configuring FirewallD for httpd and dnsmasq."
firewall-cmd --permanent --add-port=80/tcp --add-port=53/tcp --add-port=53/udp firewall-cmd --permanent --add-port=80/tcp --add-port=53/tcp --add-port=53/udp
firewall-cmd --reload firewall-cmd --reload
return 0
# Check for proper kernel modules to prevent failure # Check for proper kernel modules to prevent failure
elif modinfo ip_tables &> /dev/null; then elif modinfo ip_tables &> /dev/null && command -v iptables &> /dev/null; then
# If chain Policy is not ACCEPT or last Rule is not ACCEPT # If chain Policy is not ACCEPT or last Rule is not ACCEPT
# then check and insert our Rules above the DROP/REJECT Rule. # then check and insert our Rules above the DROP/REJECT Rule.
if iptables -S INPUT | head -n1 | grep -qv '^-P.*ACCEPT$' || iptables -S INPUT | tail -n1 | grep -qv '^-\(A\|P\).*ACCEPT$'; then if iptables -S INPUT | head -n1 | grep -qv '^-P.*ACCEPT$' || iptables -S INPUT | tail -n1 | grep -qv '^-\(A\|P\).*ACCEPT$'; then
whiptail --title "Firewall in use" --yesno "We have detected a running firewall\n\nPi-hole currently requires HTTP and DNS port access.\n\n\n\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
{ echo -e ":::\n::: Not installing firewall rulesets."; return 0; }
echo -e ":::\n::: Installing new IPTables firewall rulesets."
# Check chain first, otherwise a new rule will duplicate old ones # Check chain first, otherwise a new rule will duplicate old ones
echo "::: Configuring iptables for httpd and dnsmasq.."
iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT
iptables -C INPUT -p udp -m udp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT iptables -C INPUT -p udp -m udp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT
return 0
fi fi
else else
echo "::: No active firewall detected.. skipping firewall configuration." echo -e ":::\n::: No active firewall detected.. skipping firewall configuration."
return 0
fi fi
echo -e ":::\n::: Skipping firewall configuration."
} }
finalExports() { finalExports() {
@ -930,6 +936,24 @@ finalExports() {
fi fi
} }
installLogrotate() {
# Install the logrotate script
echo ":::"
echo -n "::: Installing latest logrotate script..."
cp /etc/.pihole/advanced/logrotate /etc/pihole/logrotate
# Different operating systems have different user / group
# settings for logrotate that makes it impossible to create
# a static logrotate file that will work with e.g.
# Rasbian and Ubuntu at the same time. Hence, we have to
# customize the logrotate script here in order to reflect
# the local properties of the /var/log directory
logusergroup="$(stat -c '%U %G' /var/log)"
if [[ ! -z $logusergroup ]]; then
echo "su ${logusergroup}" >> /etc/pihole/logrotate
fi
echo " done!"
}
installPihole() { installPihole() {
# Install base files and web interface # Install base files and web interface
create_pihole_user create_pihole_user
@ -949,6 +973,7 @@ installPihole() {
CreateLogFile CreateLogFile
installPiholeWeb installPiholeWeb
installCron installCron
installLogrotate
configureFirewall configureFirewall
finalExports finalExports
runGravity runGravity
@ -972,14 +997,14 @@ accountForRefactor() {
updatePihole() { updatePihole() {
accountForRefactor accountForRefactor
# Source ${setupVars} for use in the rest of the functions. # Source ${setupVars} for use in the rest of the functions.
. ${setupVars} source ${setupVars}
# Install base files and web interface # Install base files and web interface
installScripts installScripts
installConfigs installConfigs
CreateLogFile CreateLogFile
installPiholeWeb installPiholeWeb
installCron installCron
configureFirewall installLogrotate
finalExports #re-export setupVars.conf to account for any new vars added in new versions finalExports #re-export setupVars.conf to account for any new vars added in new versions
runGravity runGravity
} }
@ -993,15 +1018,11 @@ checkSelinux() {
enforceMode=$(getenforce) enforceMode=$(getenforce)
echo "${enforceMode}" echo "${enforceMode}"
if [[ "${enforceMode}" == "Enforcing" ]]; then if [[ "${enforceMode}" == "Enforcing" ]]; then
if (whiptail --title "SELinux Enforcing Detected" --yesno "SELinux is being Enforced on your system!\n\nPi-hole currently does not support SELinux, but you may still continue with the installation.\n\nNote: Admin UI Will not function fully without setting your policies correctly\n\nContinue installing Pi-hole?" ${r} ${c}); then whiptail --title "SELinux Enforcing Detected" --yesno "SELinux is being Enforced on your system!\n\nPi-hole currently does not support SELinux, but you may still continue with the installation.\n\nNote: Admin UI Will not function fully without setting your policies correctly\n\nContinue installing Pi-hole?" ${r} ${c} || \
echo ":::" { echo ":::"; echo "::: Not continuing install after SELinux Enforcing detected."; exit 1; }
echo "::: Continuing installation with SELinux Enforcing." echo ":::"
echo "::: Please refer to official SELinux documentation to create a custom policy." echo "::: Continuing installation with SELinux Enforcing."
else echo "::: Please refer to official SELinux documentation to create a custom policy."
echo ":::"
echo "::: Not continuing install after SELinux Enforcing detected."
exit 1
fi
fi fi
fi fi
} }
@ -1037,23 +1058,19 @@ update_dialogs() {
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options: \n($strAdd)" ${r} ${c} 2 \ UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options: \n($strAdd)" ${r} ${c} 2 \
"${opt1a}" "${opt1b}" \ "${opt1a}" "${opt1b}" \
"${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3) "${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3) || \
{ echo "::: Cancel selected. Exiting"; exit 1; }
if [[ $? = 0 ]];then case ${UpdateCmd} in
case ${UpdateCmd} in ${opt1a})
${opt1a}) echo "::: ${opt1a} option selected."
echo "::: ${opt1a} option selected." useUpdateVars=true
useUpdateVars=true ;;
;; ${opt2a})
${opt2a}) echo "::: ${opt2a} option selected"
echo "::: ${opt2a} option selected" useUpdateVars=false
useUpdateVars=false ;;
;;
esac esac
else
echo "::: Cancel selected. Exiting..."
exit 1
fi
} }
main() { main() {
@ -1072,7 +1089,7 @@ main() {
if command -v sudo &> /dev/null; then if command -v sudo &> /dev/null; then
echo "::: Utility sudo located." echo "::: Utility sudo located."
exec curl -sSL https://install.pi-hole.net | sudo bash "$@" exec curl -sSL https://raw.githubusercontent.com/pi-hole/pi-hole/master/automated%20install/basic-install.sh | sudo bash "$@"
exit $? exit $?
else else
echo "::: sudo is needed for the Web interface to run pihole commands. Please run this script as root and it will be automatically installed." echo "::: sudo is needed for the Web interface to run pihole commands. Please run this script as root and it will be automatically installed."
@ -1080,6 +1097,9 @@ main() {
fi fi
fi fi
# Check for supported distribution
distro_check
# Check arguments for the undocumented flags # Check arguments for the undocumented flags
for var in "$@"; do for var in "$@"; do
case "$var" in case "$var" in
@ -1170,11 +1190,11 @@ main() {
pw="" pw=""
if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then
pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8) pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
pihole -a -p ${pw} /usr/local/bin/pihole -a -p "${pw}"
fi fi
if [[ "${useUpdateVars}" == false ]]; then if [[ "${useUpdateVars}" == false ]]; then
displayFinalMessage ${pw} displayFinalMessage "${pw}"
fi fi
echo "::: Restarting services..." echo "::: Restarting services..."

View file

@ -76,7 +76,7 @@ gravity_collapse() {
#custom file found, use this instead of default #custom file found, use this instead of default
echo -n "::: Custom adList file detected. Reading..." echo -n "::: Custom adList file detected. Reading..."
sources=() sources=()
while read -r line; do while IFS= read -r line || [[ -n "$line" ]]; do
#Do not read commented out or blank lines #Do not read commented out or blank lines
if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then
echo "" > /dev/null echo "" > /dev/null
@ -89,7 +89,7 @@ gravity_collapse() {
#no custom file found, use defaults! #no custom file found, use defaults!
echo -n "::: No custom adlist file detected, reading from default file..." echo -n "::: No custom adlist file detected, reading from default file..."
sources=() sources=()
while read -r line; do while IFS= read -r line || [[ -n "$line" ]]; do
#Do not read commented out or blank lines #Do not read commented out or blank lines
if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then
echo "" > /dev/null echo "" > /dev/null
@ -388,7 +388,7 @@ if [[ "${forceGrav}" == true ]]; then
fi fi
#Overwrite adlists.default from /etc/.pihole in case any changes have been made. Changes should be saved in /etc/adlists.list #Overwrite adlists.default from /etc/.pihole in case any changes have been made. Changes should be saved in /etc/adlists.list
#cp /etc/.pihole/adlists.default /etc/pihole/adlists.default cp /etc/.pihole/adlists.default /etc/pihole/adlists.default
gravity_collapse gravity_collapse
gravity_spinup gravity_spinup
if [[ "${skipDownload}" == false ]]; then if [[ "${skipDownload}" == false ]]; then

53
pihole
View file

@ -11,6 +11,7 @@
# (at your option) any later version. # (at your option) any later version.
PI_HOLE_SCRIPT_DIR="/opt/pihole" PI_HOLE_SCRIPT_DIR="/opt/pihole"
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
# Must be root to use this tool # Must be root to use this tool
if [[ ! $EUID -eq 0 ]];then if [[ ! $EUID -eq 0 ]];then
if [ -x "$(command -v sudo)" ];then if [ -x "$(command -v sudo)" ];then
@ -38,6 +39,11 @@ blacklistFunc() {
exit 0 exit 0
} }
wildcardFunc() {
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
exit 0
}
debugFunc() { debugFunc() {
"${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
exit 0 exit 0
@ -63,11 +69,6 @@ updateGravityFunc() {
exit 0 exit 0
} }
setupLCDFunction() {
"${PI_HOLE_SCRIPT_DIR}"/setupLCD.sh
exit 0
}
scanList(){ scanList(){
domain="${1}" domain="${1}"
list="${2}" list="${2}"
@ -79,19 +80,52 @@ scanList(){
fi fi
} }
processWildcards() {
IFS="." read -r -a array <<< "${1}"
for (( i=${#array[@]}-1; i>=0; i-- )); do
ar=""
for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do
if [[ $j == $((${#array[@]}-1)) ]]; then
ar="${array[$j]}"
else
ar="${array[$j]}.${ar}"
fi
done
echo "${ar}"
done
}
queryFunc() { queryFunc() {
domain="${2}" domain="${2}"
method="${3}" method="${3}"
lists=( /etc/pihole/list.* /etc/pihole/blacklist.txt) lists=( /etc/pihole/list.* /etc/pihole/blacklist.txt)
for list in ${lists[@]}; do for list in ${lists[@]}; do
result=$(scanList ${domain} ${list} ${method}) if [ -e "${list}" ]; then
result=$(scanList ${domain} ${list} ${method})
# Remove empty lines before couting number of results
count=$(sed '/^\s*$/d' <<< "$result" | wc -l)
echo "::: ${list} (${count} results)"
if [[ ${count} > 0 ]]; then
echo "${result}"
fi
echo ""
else
echo "::: ${list} does not exist"
echo ""
fi
done
# Scan for possible wildcard matches
local wildcards=($(processWildcards "${domain}"))
for domain in ${wildcards[@]}; do
result=$(scanList "\/${domain}\/" ${wildcardlist})
# Remove empty lines before couting number of results # Remove empty lines before couting number of results
count=$(sed '/^\s*$/d' <<< "$result" | wc -l) count=$(sed '/^\s*$/d' <<< "$result" | wc -l)
echo "::: ${list} (${count} results)"
if [[ ${count} > 0 ]]; then if [[ ${count} > 0 ]]; then
echo "::: Wildcard blocking ${domain} (${count} results)"
echo "${result}" echo "${result}"
echo ""
fi fi
echo ""
done done
exit 0 exit 0
} }
@ -248,7 +282,6 @@ helpFunc() {
::: -up, updatePihole Update Pi-hole ::: -up, updatePihole Update Pi-hole
::: -r, reconfigure Reconfigure or Repair Pi-hole ::: -r, reconfigure Reconfigure or Repair Pi-hole
::: -g, updateGravity Update the list of ad-serving domains ::: -g, updateGravity Update the list of ad-serving domains
::: -s, setupLCD Automatically configures the Pi to use the 2.8 LCD screen to display stats on it
::: -c, chronometer Calculates stats and displays to an LCD ::: -c, chronometer Calculates stats and displays to an LCD
::: -h, help Show this help dialog ::: -h, help Show this help dialog
::: -v, version Show current versions ::: -v, version Show current versions
@ -275,12 +308,12 @@ fi
case "${1}" in case "${1}" in
"-w" | "whitelist" ) whitelistFunc "$@";; "-w" | "whitelist" ) whitelistFunc "$@";;
"-b" | "blacklist" ) blacklistFunc "$@";; "-b" | "blacklist" ) blacklistFunc "$@";;
"-wild" | "wildcard" ) wildcardFunc "$@";;
"-d" | "debug" ) debugFunc;; "-d" | "debug" ) debugFunc;;
"-f" | "flush" ) flushFunc;; "-f" | "flush" ) flushFunc;;
"-up" | "updatePihole" ) updatePiholeFunc;; "-up" | "updatePihole" ) updatePiholeFunc;;
"-r" | "reconfigure" ) reconfigurePiholeFunc;; "-r" | "reconfigure" ) reconfigurePiholeFunc;;
"-g" | "updateGravity" ) updateGravityFunc "$@";; "-g" | "updateGravity" ) updateGravityFunc "$@";;
"-s" | "setupLCD" ) setupLCDFunction;;
"-c" | "chronometer" ) chronometerFunc "$@";; "-c" | "chronometer" ) chronometerFunc "$@";;
"-h" | "help" ) helpFunc;; "-h" | "help" ) helpFunc;;
"-v" | "version" ) versionFunc "$@";; "-v" | "version" ) versionFunc "$@";;

View file

@ -64,35 +64,237 @@ def test_setupVars_saved_to_file(Pihole):
for k,v in SETUPVARS.iteritems(): for k,v in SETUPVARS.iteritems():
assert "{}={}".format(k, v) in output assert "{}={}".format(k, v) in output
def test_configureFirewall_firewalld_no_errors(Pihole): def test_configureFirewall_firewalld_running_no_errors(Pihole):
''' confirms firewalld rules are applied when appopriate ''' ''' confirms firewalld rules are applied when firewallD is running '''
mock_command('firewall-cmd', '0', Pihole) # firewallD returns 'running' as status
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
# Whiptail dialog returns Ok for user prompt
mock_command('whiptail', {'*':('', 0)}, Pihole)
configureFirewall = Pihole.run(''' configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
configureFirewall configureFirewall
''') ''')
expected_stdout = '::: Configuring FirewallD for httpd and dnsmasq.' expected_stdout = 'Configuring FirewallD for httpd and dnsmasq.'
assert expected_stdout in configureFirewall.stdout assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout
assert 'firewall-cmd --state' in firewall_calls assert 'firewall-cmd --state' in firewall_calls
assert 'firewall-cmd --permanent --add-port=80/tcp --add-port=53/tcp --add-port=53/udp' in firewall_calls assert 'firewall-cmd --permanent --add-port=80/tcp --add-port=53/tcp --add-port=53/udp' in firewall_calls
assert 'firewall-cmd --reload' in firewall_calls assert 'firewall-cmd --reload' in firewall_calls
def test_configureFirewall_firewalld_disabled_no_errors(Pihole):
''' confirms firewalld rules are not applied when firewallD is not running '''
# firewallD returns non-running status
mock_command('firewall-cmd', {'*':('not running', '1')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'No active firewall detected.. skipping firewall configuration.'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
''' confirms firewalld rules are not applied when firewallD is running, user declines ruleset '''
# firewallD returns running status
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', 1)}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Not installing firewall rulesets.'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_no_firewall(Pihole):
''' confirms firewall skipped no daemon is running '''
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'No active firewall detected'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
''' confirms IPTables rules are not applied when IPTables is running, user declines ruleset '''
# iptables command exists
mock_command('iptables', {'*':('', '0')}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '1')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Not installing firewall rulesets.'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_IPTables_enabled_rules_exist_no_errors(Pihole):
''' confirms IPTables rules are not applied when IPTables is running and rules exist '''
# iptables command exists and returns 0 on calls (should return 0 on iptables -C)
mock_command('iptables', {'-S':('-P INPUT DENY', '0')}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '0')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Installing new IPTables firewall rulesets'
assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' not in firewall_calls
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' not in firewall_calls
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' not in firewall_calls
def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
''' confirms IPTables rules are applied when IPTables is running and rules do not exist '''
# iptables command and returns 0 on calls (should return 1 on iptables -C)
mock_command('iptables', {'-S':('-P INPUT DENY', '0'), '-C':('', 1), '-I':('', 0)}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '0')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Installing new IPTables firewall rulesets'
assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' in firewall_calls
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' in firewall_calls
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' in firewall_calls
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed on a fresh build '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
def test_installPiholeWeb_empty_directory_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed in an emtpy directory '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
mkdir -p /var/www/html/pihole
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
assert 'index.php missing, replacing...' in installWeb.stdout
assert 'index.js missing, replacing...' in installWeb.stdout
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
def test_installPiholeWeb_index_php_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed when necessary '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
mkdir -p /var/www/html/pihole
touch /var/www/html/pihole/index.php
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
assert 'Existing index.php detected, not overwriting' in installWeb.stdout
assert 'index.js missing, replacing...' in installWeb.stdout
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
def test_installPiholeWeb_index_js_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed when necessary '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
mkdir -p /var/www/html/pihole
touch /var/www/html/pihole/index.js
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
assert 'index.php missing, replacing...' in installWeb.stdout
assert 'Existing index.js detected, not overwriting' in installWeb.stdout
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
def test_installPiholeWeb_blockingpage_css_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed when necessary '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
mkdir -p /var/www/html/pihole
touch /var/www/html/pihole/blockingpage.css
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
assert 'index.php missing, replacing...' in installWeb.stdout
assert 'index.js missing, replacing...' in installWeb.stdout
assert 'Existing blockingpage.css detected, not overwriting' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
def test_installPiholeWeb_already_populated_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed when necessary '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
mkdir -p /var/www/html/pihole
touch /var/www/html/pihole/index.php
touch /var/www/html/pihole/index.js
touch /var/www/html/pihole/blockingpage.css
installPiholeWeb
''')
assert 'Installing pihole custom index page...' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
assert 'Existing index.php detected, not overwriting' in installWeb.stdout
assert 'index.php missing, replacing...' not in installWeb.stdout
assert 'Existing index.js detected, not overwriting' in installWeb.stdout
assert 'index.js missing, replacing...' not in installWeb.stdout
assert 'Existing blockingpage.css detected, not overwriting' in installWeb.stdout
assert 'blockingpage.css missing, replacing... ' not in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'index.js' in web_directory
assert 'blockingpage.css' in web_directory
# Helper functions # Helper functions
def mock_command(script, result, container): def mock_command(script, args, container):
''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' ''' Allows for setup of commands we don't really want to have to run for real in unit tests '''
''' TODO: support array of results that enable the results to change over multiple executions of a command '''
full_script_path = '/usr/local/bin/{}'.format(script) full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent('''\ mock_script = dedent('''\
#!/bin/bash -e #!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script} echo "\$0 \$@" >> /var/log/{script}
exit {retcode} case "\$1" in'''.format(script=script))
'''.format(script=script, retcode=result)) for k, v in args.iteritems():
case = dedent('''
{arg})
echo {res}
exit {retcode}
;;'''.format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent('''
esac''')
container.run(''' container.run('''
cat <<EOF> {script}\n{content}\nEOF cat <<EOF> {script}\n{content}\nEOF
chmod +x {script} chmod +x {script}
'''.format(script=full_script_path, content=mock_script)) rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script))
def run_script(Pihole, script): def run_script(Pihole, script):
result = Pihole.run(script) result = Pihole.run(script)