-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 79a710fd..00000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 79ee123c..00000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 06f541f4..b993cfe9 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,9 @@
-The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
+The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content without installing any client-side software.
-- **Easy-to-install**: our versatile installer walks you through the process, and takes less than ten minutes
+- **Easy-to-install**: our versatile installer walks you through the process and takes less than ten minutes
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://docs.pi-hole.net/main/prerequisites/)
@@ -22,7 +22,7 @@ The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) th
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring *all* your devices are protected automatically
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
- **Modern**: blocks ads over both IPv4 and IPv6
-- **Free**: open source software which helps ensure _you_ are the sole person in control of your privacy
+- **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
-----
@@ -57,21 +57,21 @@ Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-h
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole 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) which ensures that all devices connecting to your network will have content blocked without any further intervention.
-If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); just be sure to disable DHCP on your router first (if it has that feature available).
+If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
-As a last resort, you can always manually set each device to use Pi-hole as their DNS server.
+As a last resort, you can manually set each device to use Pi-hole as their DNS server.
-----
-## Pi-hole is free, but powered by your support
+## Pi-hole is free but powered by your support
-There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained.
+There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
Make no mistake: **your support is absolutely vital to help keep us innovating!**
### [Donations](https://pi-hole.net/donate)
-Sending a donation using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses and rewarding our dedicated development team:
+Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
### Alternative support
@@ -83,13 +83,13 @@ If you'd rather not donate (_which is okay!_), there are other ways you can help
- [Digital Ocean](https://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
- [Amazon US](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
-- Spreading the word about our software, and how you have benefited from it
+- Spreading the word about our software and how you have benefited from it
### Contributing via GitHub
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
-If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions that it asks will help the volunteers quickly understand what you're aiming to achieve.
+If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions it asks will help the volunteers quickly understand what you're aiming to achieve.
You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) and the [debug script](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/piholeDebug.sh) have an abundance of comments, which will help you better understand how Pi-hole works. They're also a valuable resource to those who want to learn how to write scripts or code a program! We encourage anyone who likes to tinker to read through it and submit a pull request for us to review.
@@ -97,9 +97,9 @@ You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/ma
## Getting in touch with us
-While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on a variety of social media outlets.
+While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on various social media outlets.
-**Please be sure to check the FAQ's** before starting a new discussion. Many user questions already have answers and can be solved without any additional assistance.
+**Please be sure to check the FAQs** before starting a new discussion, as we do not have the spare time to reply to every request for assistance.
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes)
@@ -125,15 +125,15 @@ Some of the statistics you can integrate include:
- Queries cached
- Unique clients
-The API can be accessed via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
+Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
### The Command Line Interface
-The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to be able to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
+The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
Some notable features include:
-- [Whitelisting, Blacklisting and Regex](https://docs.pi-hole.net/core/pihole-command/#whitelisting-blacklisting-and-regex)
+- [Whitelisting, Blacklisting, and Regex](https://docs.pi-hole.net/core/pihole-command/#whitelisting-blacklisting-and-regex)
- [Debugging utility](https://docs.pi-hole.net/core/pihole-command/#debugger)
- [Viewing the live log file](https://docs.pi-hole.net/core/pihole-command/#tail)
- [Updating Ad Lists](https://docs.pi-hole.net/core/pihole-command/#gravity)
@@ -149,7 +149,7 @@ This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to vie
Some notable features include:
-- Mobile friendly interface
+- Mobile-friendly interface
- Password protection
- Detailed graphs and doughnut charts
- Top lists of domains and clients
diff --git a/advanced/01-pihole.conf b/advanced/01-pihole.conf
index e243e91a..02bc93bf 100644
--- a/advanced/01-pihole.conf
+++ b/advanced/01-pihole.conf
@@ -39,6 +39,4 @@ cache-size=@CACHE_SIZE@
log-queries
log-facility=/var/log/pihole.log
-local-ttl=2
-
log-async
diff --git a/advanced/06-rfc6761.conf b/advanced/06-rfc6761.conf
new file mode 100644
index 00000000..fcdd0010
--- /dev/null
+++ b/advanced/06-rfc6761.conf
@@ -0,0 +1,42 @@
+# Pi-hole: A black hole for Internet advertisements
+# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
+# Network-wide ad blocking via your own hardware.
+#
+# RFC 6761 config file for Pi-hole
+#
+# This file is copyright under the latest version of the EUPL.
+# Please see LICENSE file for your rights under this license.
+
+###############################################################################
+# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
+# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
+# #
+# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
+# WITHIN /etc/dnsmasq.d/yourname.conf #
+###############################################################################
+
+# RFC 6761: Caching DNS servers SHOULD recognize
+# test, localhost, invalid
+# names as special and SHOULD NOT attempt to look up NS records for them, or
+# otherwise query authoritative DNS servers in an attempt to resolve these
+# names.
+server=/test/
+server=/localhost/
+server=/invalid/
+
+# The same RFC requests something similar for
+# 10.in-addr.arpa. 21.172.in-addr.arpa. 27.172.in-addr.arpa.
+# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 28.172.in-addr.arpa.
+# 17.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
+# 18.172.in-addr.arpa. 24.172.in-addr.arpa. 30.172.in-addr.arpa.
+# 19.172.in-addr.arpa. 25.172.in-addr.arpa. 31.172.in-addr.arpa.
+# 20.172.in-addr.arpa. 26.172.in-addr.arpa. 168.192.in-addr.arpa.
+# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
+# 01-pihole.conf) because this also covers IPv6.
+
+# OpenWRT furthermore blocks bind, local, onion domains
+# see https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob_plain;f=package/network/services/dnsmasq/files/rfc6761.conf;hb=HEAD
+# and https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
+# We do not include the ".local" rule ourselves, see https://github.com/pi-hole/pi-hole/pull/4282#discussion_r689112972
+server=/bind/
+server=/onion/
diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh
index 3f85bdfc..312c484f 100755
--- a/advanced/Scripts/chronometer.sh
+++ b/advanced/Scripts/chronometer.sh
@@ -329,8 +329,8 @@ get_sys_stats() {
*) cpu_col="$COL_URG_RED";;
esac
- # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
- cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
+ # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
+ cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
elif [[ "$temp_unit" == "F" ]]; then
cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
@@ -445,7 +445,7 @@ get_strings() {
lan_info="Gateway: $net_gateway"
dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
- ads_info="$total_str$ads_blocked_today of $dns_queries_today"
+ ads_info="$total_str$ads_blocked_today of $dns_queries_today"
dns_info="$dns_count DNS servers"
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
@@ -488,7 +488,7 @@ chronoFunc() {
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
else
- echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str\\n[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str\\n[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
+ echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str\\n[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str\\n[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
fi
printFunc " Hostname: " "$sys_name" "$host_info"
diff --git a/advanced/Scripts/database_migration/gravity-db.sh b/advanced/Scripts/database_migration/gravity-db.sh
old mode 100644
new mode 100755
index 22f241dd..09dc1727
--- a/advanced/Scripts/database_migration/gravity-db.sh
+++ b/advanced/Scripts/database_migration/gravity-db.sh
@@ -122,4 +122,10 @@ upgrade_gravityDB(){
sqlite3 "${database}" < "${scriptPath}/13_to_14.sql"
version=14
fi
+ if [[ "$version" == "14" ]]; then
+ # Changes the vw_adlist created in 5_to_6
+ echo -e " ${INFO} Upgrading gravity database from version 14 to 15"
+ sqlite3 "${database}" < "${scriptPath}/14_to_15.sql"
+ version=15
+ fi
}
diff --git a/advanced/Scripts/database_migration/gravity/13_to_14.sql b/advanced/Scripts/database_migration/gravity/13_to_14.sql
index fa230865..0a465d1d 100644
--- a/advanced/Scripts/database_migration/gravity/13_to_14.sql
+++ b/advanced/Scripts/database_migration/gravity/13_to_14.sql
@@ -10,4 +10,4 @@ ALTER TABLE adlist ADD COLUMN status INTEGER NOT NULL DEFAULT 0;
UPDATE info SET value = 14 WHERE property = 'version';
-COMMIT;
\ No newline at end of file
+COMMIT;
diff --git a/advanced/Scripts/database_migration/gravity/14_to_15.sql b/advanced/Scripts/database_migration/gravity/14_to_15.sql
new file mode 100644
index 00000000..41cb7517
--- /dev/null
+++ b/advanced/Scripts/database_migration/gravity/14_to_15.sql
@@ -0,0 +1,15 @@
+.timeout 30000
+
+PRAGMA FOREIGN_KEYS=OFF;
+
+BEGIN TRANSACTION;
+DROP VIEW vw_adlist;
+
+CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
+ FROM adlist
+ WHERE enabled = 1
+ ORDER BY id;
+
+UPDATE info SET value = 15 WHERE property = 'version';
+
+COMMIT;
diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh
index e213b014..bc254515 100755
--- a/advanced/Scripts/list.sh
+++ b/advanced/Scripts/list.sh
@@ -16,14 +16,14 @@ GRAVITYDB="${piholeDir}/gravity.db"
# Source pihole-FTL from install script
pihole_FTL="${piholeDir}/pihole-FTL.conf"
if [[ -f "${pihole_FTL}" ]]; then
- source "${pihole_FTL}"
+ source "${pihole_FTL}"
fi
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
# have changed
gravityDBfile="${GRAVITYDB}"
-reload=false
+noReloadRequested=false
addmode=true
verbose=true
wildcard=false
@@ -35,6 +35,7 @@ typeId=""
comment=""
declare -i domaincount
domaincount=0
+reload=false
colfile="/opt/pihole/COL_TABLE"
source ${colfile}
@@ -132,7 +133,7 @@ ProcessDomainList() {
else
RemoveDomain "${dom}"
fi
- done
+ done
}
AddDomain() {
@@ -144,19 +145,19 @@ AddDomain() {
requestedListname="$(GetListnameFromTypeId "${typeId}")"
if [[ "${num}" -ne 0 ]]; then
- existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
- if [[ "${existingTypeId}" == "${typeId}" ]]; then
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
+ existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
+ if [[ "${existingTypeId}" == "${typeId}" ]]; then
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
+ fi
+ else
+ existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
+ sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
+ fi
fi
- else
- existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
- sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
- fi
- fi
- return
+ return
fi
# Domain not found in the table, add it!
@@ -184,10 +185,10 @@ RemoveDomain() {
requestedListname="$(GetListnameFromTypeId "${typeId}")"
if [[ "${num}" -eq 0 ]]; then
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
- fi
- return
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
+ fi
+ return
fi
# Domain found in the table, remove it!
@@ -242,21 +243,21 @@ Displaylist() {
NukeList() {
count=$(sqlite3 "${gravityDBfile}" "SELECT COUNT(1) FROM domainlist WHERE type = ${typeId};")
- listname="$(GetListnameFromTypeId "${typeId}")"
+ listname="$(GetListnameFromTypeId "${typeId}")"
if [ "$count" -gt 0 ];then
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};"
echo " ${TICK} Removed ${count} domain(s) from the ${listname}"
else
echo " ${INFO} ${listname} already empty. Nothing to do!"
- fi
+ fi
exit 0;
}
GetComment() {
comment="$1"
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
- echo " ${CROSS} Found invalid characters in domain comment!"
- exit
+ echo " ${CROSS} Found invalid characters in domain comment!"
+ exit
fi
}
@@ -268,7 +269,7 @@ while (( "$#" )); do
"--white-wild" | "white-wild" ) typeId=2; wildcard=true;;
"--wild" | "wildcard" ) typeId=3; wildcard=true;;
"--regex" | "regex" ) typeId=3;;
- "-nr"| "--noreload" ) reload=false;;
+ "-nr"| "--noreload" ) noReloadRequested=true;;
"-d" | "--delmode" ) addmode=false;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
@@ -291,9 +292,9 @@ ProcessDomainList
# Used on web interface
if $web; then
-echo "DONE"
+ echo "DONE"
fi
-if [[ "${reload}" != false ]]; then
+if [[ ${reload} == true && ${noReloadRequested} == false ]]; then
pihole restartdns reload-lists
fi
diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh
old mode 100644
new mode 100755
diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh
index 26ef61fa..ad58d6c7 100755
--- a/advanced/Scripts/piholeDebug.sh
+++ b/advanced/Scripts/piholeDebug.sh
@@ -27,7 +27,7 @@ PIHOLE_COLTABLE_FILE="${PIHOLE_SCRIPTS_DIRECTORY}/COL_TABLE"
# These provide the colors we need for making the log more readable
if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then
- source ${PIHOLE_COLTABLE_FILE}
+ source ${PIHOLE_COLTABLE_FILE}
else
COL_NC='\e[0m' # No Color
COL_RED='\e[1;91m'
@@ -73,15 +73,12 @@ HTML_DIRECTORY="/var/www/html"
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
#BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
SHM_DIRECTORY="/dev/shm"
+ETC="/etc"
# Files required by Pi-hole
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
PIHOLE_CRON_FILE="${CRON_D_DIRECTORY}/pihole"
-PIHOLE_DNS_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/01-pihole.conf"
-PIHOLE_DHCP_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/02-pihole-dhcp.conf"
-PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf"
-
WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
@@ -136,6 +133,9 @@ PIHOLE_FTL_LOG="$(get_ftl_conf_value "LOGFILE" "${LOG_DIRECTORY}/pihole-FTL.log"
PIHOLE_WEB_SERVER_ACCESS_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/access.log"
PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log"
+RESOLVCONF="${ETC}/resolv.conf"
+DNSMASQ_CONF="${ETC}/dnsmasq.conf"
+
# An array of operating system "pretty names" that we officially support
# We can loop through the array at any time to see if it matches a value
#SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
@@ -160,9 +160,6 @@ PIHOLE_PROCESSES=( "lighttpd" "pihole-FTL" )
# Store the required directories in an array so it can be parsed through
REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
-"${PIHOLE_DNS_CONFIG_FILE}"
-"${PIHOLE_DHCP_CONFIG_FILE}"
-"${PIHOLE_WILDCARD_CONFIG_FILE}"
"${WEB_SERVER_CONFIG_FILE}"
"${WEB_SERVER_CUSTOM_CONFIG_FILE}"
"${PIHOLE_INSTALL_LOG_FILE}"
@@ -180,7 +177,9 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
"${PIHOLE_DEBUG_LOG}"
"${PIHOLE_FTL_LOG}"
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
-"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}")
+"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
+"${RESOLVCONF}"
+"${DNSMASQ_CONF}")
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
@@ -586,6 +585,27 @@ processor_check() {
fi
}
+disk_usage() {
+ local file_system
+ local hide
+
+ echo_current_diagnostic "Disk usage"
+ mapfile -t file_system < <(df -h)
+
+ # Some lines of df might contain sensitive information like usernames and passwords.
+ # E.g. curlftpfs filesystems (https://www.looklinux.com/mount-ftp-share-on-linux-using-curlftps/)
+ # We are not interested in those lines so we collect keyword, to remove them from the output
+ # Additinal keywords can be added, separated by "|"
+ hide="curlftpfs"
+
+ # only show those lines not containg a sensitive phrase
+ for line in "${file_system[@]}"; do
+ if [[ ! $line =~ $hide ]]; then
+ log_write " ${line}"
+ fi
+ done
+}
+
parse_setup_vars() {
echo_current_diagnostic "Setup variables"
# If the file exists,
@@ -1074,12 +1094,16 @@ list_files_in_dir() {
elif [[ "${dir_to_parse}" == "${SHM_DIRECTORY}" ]]; then
# SHM file - we do not want to see the content, but we want to see the files and their sizes
log_write "$(ls -lhd "${dir_to_parse}"/"${each_file}")"
+ elif [[ "${dir_to_parse}" == "${DNSMASQ_D_DIRECTORY}" ]]; then
+ # in case of the dnsmasq directory inlcuede all files in the debug output
+ log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
+ make_array_from_file "${dir_to_parse}/${each_file}"
else
# Then, parse the file's content into an array so each line can be analyzed if need be
for i in "${!REQUIRED_FILES[@]}"; do
if [[ "${dir_to_parse}/${each_file}" == "${REQUIRED_FILES[$i]}" ]]; then
# display the filename
- log_write "\\n${COL_GREEN}$(ls -ld "${dir_to_parse}"/"${each_file}")${COL_NC}"
+ log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
# Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing)
case "${dir_to_parse}/${each_file}" in
# If it's Web server error log, give the first and last 25 lines
@@ -1118,6 +1142,7 @@ show_content_of_pihole_files() {
show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}"
show_content_of_files_in_dir "${LOG_DIRECTORY}"
show_content_of_files_in_dir "${SHM_DIRECTORY}"
+ show_content_of_files_in_dir "${ETC}"
}
head_tail_log() {
@@ -1234,10 +1259,10 @@ show_messages() {
}
analyze_gravity_list() {
- echo_current_diagnostic "Gravity List and Database"
+ echo_current_diagnostic "Gravity Database"
local gravity_permissions
- gravity_permissions=$(ls -ld "${PIHOLE_GRAVITY_DB_FILE}")
+ gravity_permissions=$(ls -lhd "${PIHOLE_GRAVITY_DB_FILE}")
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
show_db_entries "Info table" "SELECT property,value FROM info" "20 40"
@@ -1316,7 +1341,7 @@ analyze_pihole_log() {
OLD_IFS="$IFS"
# Get the lines that are in the file(s) and store them in an array for parsing later
IFS=$'\r\n'
- pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
+ pihole_log_permissions=$(ls -lhd "${PIHOLE_LOG}")
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
@@ -1333,11 +1358,15 @@ analyze_pihole_log() {
curl_to_tricorder() {
# Users can submit their debug logs using curl (encrypted)
log_write " * Using ${COL_GREEN}curl${COL_NC} for transmission."
- # transmit he log via TLS and store the token returned in a variable
- tricorder_token=$(curl --silent --upload-file ${PIHOLE_DEBUG_LOG} https://tricorder.pi-hole.net)
- if [ -z "${tricorder_token}" ]; then
- # curl failed, fallback to nc
+ # transmit the log via TLS and store the token returned in a variable
+ tricorder_token=$(curl --silent --fail --show-error --upload-file ${PIHOLE_DEBUG_LOG} https://tricorder.pi-hole.net 2>&1)
+ if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
log_write " * ${COL_GREEN}curl${COL_NC} failed, contact Pi-hole support for assistance."
+ # Log curl error (if available)
+ if [ -n "${tricorder_token}" ]; then
+ log_write " * Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
+ tricorder_token=""
+ fi
fi
}
@@ -1382,15 +1411,14 @@ upload_to_tricorder() {
# Again, try to make this visually striking so the user realizes they need to do something with this information
# Namely, provide the Pi-hole devs with the token
log_write ""
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
+ log_write "${COL_PURPLE}*****************************************************************${COL_NC}\\n"
log_write "${TICK} Your debug token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
- log_write "${INFO}${COL_RED} Logs are deleted 48 hours after upload.${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write "${INFO}${COL_RED} Logs are deleted 48 hours after upload.${COL_NC}\\n"
+ log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
+ log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
log_write ""
- log_write " * Provide the token above to the Pi-hole team for assistance at"
- log_write " * ${FORUMS_URL}"
+ log_write " * Provide the token above to the Pi-hole team for assistance at ${FORUMS_URL}"
# If no token was generated
else
@@ -1414,6 +1442,7 @@ diagnose_operating_system
check_selinux
check_firewalld
processor_check
+disk_usage
check_networking
check_name_resolution
check_dhcp_servers
diff --git a/advanced/Scripts/query.sh b/advanced/Scripts/query.sh
index 26b4508e..0fd9871a 100755
--- a/advanced/Scripts/query.sh
+++ b/advanced/Scripts/query.sh
@@ -21,7 +21,7 @@ matchType="match"
# Source pihole-FTL from install script
pihole_FTL="${piholeDir}/pihole-FTL.conf"
if [[ -f "${pihole_FTL}" ]]; then
- source "${pihole_FTL}"
+ source "${pihole_FTL}"
fi
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
@@ -48,7 +48,7 @@ scanList(){
# Iterate through each regexp and check whether it matches the domainQuery
# If it does, print the matching regexp and continue looping
# Input 1 - regexps | Input 2 - domainQuery
- "regex" )
+ "regex" )
for list in ${lists}; do
if [[ "${domain}" =~ ${list} ]]; then
printf "%b\n" "${list}";
@@ -109,15 +109,15 @@ scanDatabaseTable() {
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
if [[ "${table}" == "gravity" ]]; then
- case "${exact}" in
- "exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
- * ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
- esac
+ case "${exact}" in
+ "exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
+ * ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
+ esac
else
- case "${exact}" in
- "exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
- * ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
- esac
+ case "${exact}" in
+ "exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
+ * ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
+ esac
fi
# Send prepared query to gravity database
@@ -128,8 +128,8 @@ scanDatabaseTable() {
fi
if [[ "${table}" == "gravity" ]]; then
- echo "${result}"
- return
+ echo "${result}"
+ return
fi
# Mark domain as having been white-/blacklist matched (global variable)
@@ -233,9 +233,9 @@ for result in "${results[@]}"; do
adlistAddress="${extra/|*/}"
extra="${extra#*|}"
if [[ "${extra}" == "0" ]]; then
- extra="(disabled)"
+ extra="(disabled)"
else
- extra=""
+ extra=""
fi
if [[ -n "${blockpage}" ]]; then
diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh
index f833fc2f..3fab9a95 100755
--- a/advanced/Scripts/update.sh
+++ b/advanced/Scripts/update.sh
@@ -95,6 +95,10 @@ main() {
# shellcheck disable=1090,2154
source "${setupVars}"
+ # Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
+ package_manager_detect
+ install_dependent_packages "${INSTALLER_DEPS[@]}"
+
# This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
@@ -196,7 +200,7 @@ main() {
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
- echo -e "${basicError}" && exit 1
+ echo -e "${basicError}" && exit 1
fi
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then
diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh
index 1ff20adb..421c9961 100755
--- a/advanced/Scripts/version.sh
+++ b/advanced/Scripts/version.sh
@@ -118,7 +118,7 @@ getLocalBranch(){
local directory="${1}"
local branch
- # Local FTL btranch is stored in /etc/pihole/ftlbranch
+ # Local FTL btranch is stored in /etc/pihole/ftlbranch
if [[ "$1" == "FTL" ]]; then
branch="$(pihole-FTL branch)"
else
diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh
index 744416e7..ec9b2cac 100755
--- a/advanced/Scripts/webpage.sh
+++ b/advanced/Scripts/webpage.sh
@@ -54,7 +54,7 @@ add_setting() {
}
delete_setting() {
- sed -i "/${1}/d" "${setupVars}"
+ sed -i "/^${1}/d" "${setupVars}"
}
change_setting() {
@@ -67,7 +67,7 @@ addFTLsetting() {
}
deleteFTLsetting() {
- sed -i "/${1}/d" "${FTLconf}"
+ sed -i "/^${1}/d" "${FTLconf}"
}
changeFTLsetting() {
@@ -84,7 +84,7 @@ add_dnsmasq_setting() {
}
delete_dnsmasq_setting() {
- sed -i "/${1}/d" "${dnsmasqconfig}"
+ sed -i "/^${1}/d" "${dnsmasqconfig}"
}
SetTemperatureUnit() {
@@ -122,14 +122,14 @@ SetWebPassword() {
read -s -r -p "Enter New Password (Blank for no password): " PASSWORD
echo ""
- if [ "${PASSWORD}" == "" ]; then
- change_setting "WEBPASSWORD" ""
- echo -e " ${TICK} Password Removed"
- exit 0
- fi
+ if [ "${PASSWORD}" == "" ]; then
+ change_setting "WEBPASSWORD" ""
+ echo -e " ${TICK} Password Removed"
+ exit 0
+ fi
- read -s -r -p "Confirm Password: " CONFIRM
- echo ""
+ read -s -r -p "Confirm Password: " CONFIRM
+ echo ""
fi
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
@@ -247,8 +247,8 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
3 ) REV_SERVER_CIDR="${arrRev[0]}.0.0.0/8";;
esac
else
- # Set REV_SERVER_CIDR to whatever value it was set to
- REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}"
+ # Set REV_SERVER_CIDR to whatever value it was set to
+ REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}"
fi
# If REV_SERVER_CIDR is not converted by the above, then use the REV_SERVER_TARGET variable to derive it
@@ -267,11 +267,21 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
delete_setting "CONDITIONAL_FORWARDING_IP"
fi
+ delete_dnsmasq_setting "rev-server"
+
if [[ "${REV_SERVER}" == true ]]; then
add_dnsmasq_setting "rev-server=${REV_SERVER_CIDR},${REV_SERVER_TARGET}"
if [ -n "${REV_SERVER_DOMAIN}" ]; then
+ # Forward local domain names to the CF target, too
add_dnsmasq_setting "server=/${REV_SERVER_DOMAIN}/${REV_SERVER_TARGET}"
fi
+
+ if [[ "${DNS_FQDN_REQUIRED}" != true ]]; then
+ # Forward unqualified names to the CF target only when the "never
+ # forward non-FQDN" option is unticked
+ add_dnsmasq_setting "server=//${REV_SERVER_TARGET}"
+ fi
+
fi
# We need to process DHCP settings here as well to account for possible
@@ -361,34 +371,34 @@ ProcessDHCPSettings() {
source "${setupVars}"
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
- interface="${PIHOLE_INTERFACE}"
+ interface="${PIHOLE_INTERFACE}"
- # Use eth0 as fallback interface
- if [ -z ${interface} ]; then
- interface="eth0"
- fi
+ # Use eth0 as fallback interface
+ if [ -z ${interface} ]; then
+ interface="eth0"
+ fi
- if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
- PIHOLE_DOMAIN="lan"
- change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
- fi
+ if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
+ PIHOLE_DOMAIN="lan"
+ change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
+ fi
- if [[ "${DHCP_LEASETIME}" == "0" ]]; then
- leasetime="infinite"
- elif [[ "${DHCP_LEASETIME}" == "" ]]; then
- leasetime="24"
- change_setting "DHCP_LEASETIME" "${leasetime}"
- elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
- #Installation is affected by known bug, introduced in a previous version.
- #This will automatically clean up setupVars.conf and remove the unnecessary "h"
- leasetime="24"
- change_setting "DHCP_LEASETIME" "${leasetime}"
- else
- leasetime="${DHCP_LEASETIME}h"
- fi
+ if [[ "${DHCP_LEASETIME}" == "0" ]]; then
+ leasetime="infinite"
+ elif [[ "${DHCP_LEASETIME}" == "" ]]; then
+ leasetime="24"
+ change_setting "DHCP_LEASETIME" "${leasetime}"
+ elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
+ #Installation is affected by known bug, introduced in a previous version.
+ #This will automatically clean up setupVars.conf and remove the unnecessary "h"
+ leasetime="24"
+ change_setting "DHCP_LEASETIME" "${leasetime}"
+ else
+ leasetime="${DHCP_LEASETIME}h"
+ fi
- # Write settings to file
- echo "###############################################################################
+ # Write settings to file
+ echo "###############################################################################
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
###############################################################################
@@ -398,34 +408,34 @@ dhcp-option=option:router,${DHCP_ROUTER}
dhcp-leasefile=/etc/pihole/dhcp.leases
#quiet-dhcp
" > "${dhcpconfig}"
- chmod 644 "${dhcpconfig}"
+ chmod 644 "${dhcpconfig}"
- if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
- echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
+ if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
+ echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
- # When there is a Pi-hole domain set and "Never forward non-FQDNs" is
- # ticked, we add `local=/domain/` to tell FTL that this domain is purely
- # local and FTL may answer queries from /etc/hosts or DHCP but should
- # never forward queries on that domain to any upstream servers
- if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
- echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}"
+ # When there is a Pi-hole domain set and "Never forward non-FQDNs" is
+ # ticked, we add `local=/domain/` to tell FTL that this domain is purely
+ # local and FTL may answer queries from /etc/hosts or DHCP but should
+ # never forward queries on that domain to any upstream servers
+ if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
+ echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}"
+ fi
fi
- fi
- # Sourced from setupVars
- # shellcheck disable=SC2154
- if [[ "${DHCP_rapid_commit}" == "true" ]]; then
- echo "dhcp-rapid-commit" >> "${dhcpconfig}"
- fi
+ # Sourced from setupVars
+ # shellcheck disable=SC2154
+ if [[ "${DHCP_rapid_commit}" == "true" ]]; then
+ echo "dhcp-rapid-commit" >> "${dhcpconfig}"
+ fi
- if [[ "${DHCP_IPv6}" == "true" ]]; then
- echo "#quiet-dhcp6
+ if [[ "${DHCP_IPv6}" == "true" ]]; then
+ echo "#quiet-dhcp6
#enable-ra
dhcp-option=option6:dns-server,[::]
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,64,3600
ra-param=*,0,0
" >> "${dhcpconfig}"
- fi
+ fi
else
if [[ -f "${dhcpconfig}" ]]; then
@@ -522,25 +532,6 @@ CustomizeAdLists() {
fi
}
-SetPrivacyMode() {
- if [[ "${args[2]}" == "true" ]]; then
- change_setting "API_PRIVACY_MODE" "true"
- else
- change_setting "API_PRIVACY_MODE" "false"
- fi
-}
-
-ResolutionSettings() {
- typ="${args[2]}"
- state="${args[3]}"
-
- if [[ "${typ}" == "forward" ]]; then
- change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
- elif [[ "${typ}" == "clients" ]]; then
- change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
- fi
-}
-
AddDHCPStaticAddress() {
mac="${args[2]}"
ip="${args[3]}"
@@ -614,7 +605,7 @@ Interfaces:
single Listen only on ${PIHOLE_INTERFACE} interface
all Listen on all interfaces, permit all origins"
exit 0
- fi
+ fi
if [[ "${args[2]}" == "all" ]]; then
echo -e " ${INFO} Listening on all interfaces, permitting all origins. Please use a firewall!"
@@ -663,18 +654,18 @@ addAudit()
domains=""
for domain in "$@"
do
- # Check domain to be added. Only continue if it is valid
- validDomain="$(checkDomain "${domain}")"
- if [[ -n "${validDomain}" ]]; then
- # Put comma in between domains when there is
- # more than one domains to be added
- # SQL INSERT allows adding multiple rows at once using the format
- ## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
- if [[ -n "${domains}" ]]; then
- domains="${domains},"
+ # Check domain to be added. Only continue if it is valid
+ validDomain="$(checkDomain "${domain}")"
+ if [[ -n "${validDomain}" ]]; then
+ # Put comma in between domains when there is
+ # more than one domains to be added
+ # SQL INSERT allows adding multiple rows at once using the format
+ ## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
+ if [[ -n "${domains}" ]]; then
+ domains="${domains},"
+ fi
+ domains="${domains}('${domain}')"
fi
- domains="${domains}('${domain}')"
- fi
done
# Insert only the domain here. The date_added field will be
# filled with its default value (date_added = current timestamp)
@@ -699,10 +690,25 @@ AddCustomDNSAddress() {
ip="${args[2]}"
host="${args[3]}"
- echo "${ip} ${host}" >> "${dnscustomfile}"
+ reload="${args[4]}"
- # Restart dnsmasq to load new custom DNS entries
- RestartDNS
+ validHost="$(checkDomain "${host}")"
+ if [[ -n "${validHost}" ]]; then
+ if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
+ echo "${ip} ${validHost}" >> "${dnscustomfile}"
+ else
+ echo -e " ${CROSS} Invalid IP has been passed"
+ exit 1
+ fi
+ else
+ echo " ${CROSS} Invalid Domain passed!"
+ exit 1
+ fi
+
+ # Restart dnsmasq to load new custom DNS entries only if $reload not false
+ if [[ ! $reload == "false" ]]; then
+ RestartDNS
+ fi
}
RemoveCustomDNSAddress() {
@@ -710,16 +716,25 @@ RemoveCustomDNSAddress() {
ip="${args[2]}"
host="${args[3]}"
+ reload="${args[4]}"
- if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
- sed -i "/^${ip} ${host}$/d" "${dnscustomfile}"
+ validHost="$(checkDomain "${host}")"
+ if [[ -n "${validHost}" ]]; then
+ if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
+ sed -i "/^${ip} ${validHost}$/d" "${dnscustomfile}"
+ else
+ echo -e " ${CROSS} Invalid IP has been passed"
+ exit 1
+ fi
else
- echo -e " ${CROSS} Invalid IP has been passed"
+ echo " ${CROSS} Invalid Domain passed!"
exit 1
fi
- # Restart dnsmasq to update removed custom DNS entries
- RestartDNS
+ # Restart dnsmasq to load new custom DNS entries only if reload is not false
+ if [[ ! $reload == "false" ]]; then
+ RestartDNS
+ fi
}
AddCustomCNAMERecord() {
@@ -727,11 +742,25 @@ AddCustomCNAMERecord() {
domain="${args[2]}"
target="${args[3]}"
+ reload="${args[4]}"
- echo "cname=${domain},${target}" >> "${dnscustomcnamefile}"
-
- # Restart dnsmasq to load new custom CNAME records
- RestartDNS
+ validDomain="$(checkDomain "${domain}")"
+ if [[ -n "${validDomain}" ]]; then
+ validTarget="$(checkDomain "${target}")"
+ if [[ -n "${validTarget}" ]]; then
+ echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
+ else
+ echo " ${CROSS} Invalid Target Passed!"
+ exit 1
+ fi
+ else
+ echo " ${CROSS} Invalid Domain passed!"
+ exit 1
+ fi
+ # Restart dnsmasq to load new custom CNAME records only if reload is not false
+ if [[ ! $reload == "false" ]]; then
+ RestartDNS
+ fi
}
RemoveCustomCNAMERecord() {
@@ -739,11 +768,12 @@ RemoveCustomCNAMERecord() {
domain="${args[2]}"
target="${args[3]}"
+ reload="${args[4]}"
validDomain="$(checkDomain "${domain}")"
if [[ -n "${validDomain}" ]]; then
validTarget="$(checkDomain "${target}")"
- if [[ -n "${validDomain}" ]]; then
+ if [[ -n "${validTarget}" ]]; then
sed -i "/cname=${validDomain},${validTarget}$/d" "${dnscustomcnamefile}"
else
echo " ${CROSS} Invalid Target Passed!"
@@ -754,8 +784,10 @@ RemoveCustomCNAMERecord() {
exit 1
fi
- # Restart dnsmasq to update removed custom CNAME records
- RestartDNS
+ # Restart dnsmasq to update removed custom CNAME records only if $reload not false
+ if [[ ! $reload == "false" ]]; then
+ RestartDNS
+ fi
}
main() {
@@ -778,8 +810,6 @@ main() {
"layout" ) SetWebUILayout;;
"theme" ) SetWebUITheme;;
"-h" | "--help" ) helpFunc;;
- "privacymode" ) SetPrivacyMode;;
- "resolve" ) ResolutionSettings;;
"addstaticdhcp" ) AddDHCPStaticAddress;;
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
"-e" | "email" ) SetAdminEmail "$3";;
diff --git a/advanced/Scripts/wildcard_regex_converter.sh b/advanced/Scripts/wildcard_regex_converter.sh
deleted file mode 100644
index b4b6b4a1..00000000
--- a/advanced/Scripts/wildcard_regex_converter.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-#
-# Provides an automated migration subroutine to convert Pi-hole v3.x wildcard domains to Pi-hole v4.x regex filters
-#
-# This file is copyright under the latest version of the EUPL.
-# Please see LICENSE file for your rights under this license.
-
-# regexFile set in gravity.sh
-
-wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
-
-convert_wildcard_to_regex() {
- if [ ! -f "${wildcardFile}" ]; then
- return
- fi
- local addrlines domains uniquedomains
- # Obtain wildcard domains from old file
- addrlines="$(grep -oE "/.*/" ${wildcardFile})"
- # Strip "/" from domain names and convert "." to regex-compatible "\."
- domains="$(sed 's/\///g;s/\./\\./g' <<< "${addrlines}")"
- # Remove repeated domains (may have been inserted two times due to A and AAAA blocking)
- uniquedomains="$(uniq <<< "${domains}")"
- # Automatically generate regex filters and remove old wildcards file
- awk '{print "(^|\\.)"$0"$"}' <<< "${uniquedomains}" >> "${regexFile:?}" && rm "${wildcardFile}"
-}
diff --git a/advanced/Templates/gravity.db.sql b/advanced/Templates/gravity.db.sql
index 5d7bafa9..3f696d6d 100644
--- a/advanced/Templates/gravity.db.sql
+++ b/advanced/Templates/gravity.db.sql
@@ -57,7 +57,7 @@ CREATE TABLE info
value TEXT NOT NULL
);
-INSERT INTO "info" VALUES('version','14');
+INSERT INTO "info" VALUES('version','15');
CREATE TABLE domain_audit
(
@@ -143,12 +143,10 @@ CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1);
-CREATE VIEW vw_adlist AS SELECT DISTINCT address, adlist.id AS id
+CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
FROM adlist
- LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id
- LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
- WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1)
- ORDER BY adlist.id;
+ WHERE enabled = 1
+ ORDER BY id;
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
BEGIN
diff --git a/advanced/Templates/pihole-FTL.service b/advanced/Templates/pihole-FTL.service
index 7b5d215c..865e2cd9 100644
--- a/advanced/Templates/pihole-FTL.service
+++ b/advanced/Templates/pihole-FTL.service
@@ -24,10 +24,14 @@ start() {
touch /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases /run/pihole /etc/pihole
- chmod 0644 /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases /etc/pihole/macvendor.db
+ chmod 0644 /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
+ # Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist
+ chmod -f 0644 /etc/pihole/macvendor.db
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist
chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
- if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE+eip "/usr/bin/pihole-FTL"; then
+ # Chown database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist
+ chmod -f 0664 /etc/pihole/pihole-FTL.db
+ if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
else
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
diff --git a/advanced/lighttpd.conf.debian b/advanced/lighttpd.conf.debian
index 9c892fc0..a58b5a88 100644
--- a/advanced/lighttpd.conf.debian
+++ b/advanced/lighttpd.conf.debian
@@ -78,11 +78,6 @@ $HTTP["url"] =~ "^/admin/" {
"X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY"
)
-
- $HTTP["url"] =~ "\.(eot|otf|tt[cf]|woff2?)$" {
- # Allow Block Page access to local fonts
- setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
- }
}
# Block . files from being served, such as .git, .github, .gitignore
@@ -90,5 +85,12 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("")
}
+# allow teleporter iframe on settings page
+$HTTP["url"] =~ "/teleporter\.php$" {
+ $HTTP["referer"] =~ "/admin/settings\.php" {
+ setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
+ }
+}
+
# Default expire header
expire.url = ( "" => "access plus 0 seconds" )
diff --git a/advanced/lighttpd.conf.fedora b/advanced/lighttpd.conf.fedora
index aae4a6a4..ad336a93 100644
--- a/advanced/lighttpd.conf.fedora
+++ b/advanced/lighttpd.conf.fedora
@@ -86,11 +86,6 @@ $HTTP["url"] =~ "^/admin/" {
"X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY"
)
-
- $HTTP["url"] =~ "\.(eot|otf|tt[cf]|woff2?)$" {
- # Allow Block Page access to local fonts
- setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
- }
}
# Block . files from being served, such as .git, .github, .gitignore
@@ -98,5 +93,12 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("")
}
+# allow teleporter iframe on settings page
+$HTTP["url"] =~ "/teleporter\.php$" {
+ $HTTP["referer"] =~ "/admin/settings\.php" {
+ setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
+ }
+}
+
# Default expire header
expire.url = ( "" => "access plus 0 seconds" )
diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh
index 5eda20ea..cbb8ebae 100755
--- a/automated install/basic-install.sh
+++ b/automated install/basic-install.sh
@@ -34,27 +34,26 @@ export PATH+=':/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
# List of supported DNS servers
DNS_SERVERS=$(cat << EOM
-Google (ECS);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844
+Google (ECS, DNSSEC);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844
OpenDNS (ECS, DNSSEC);208.67.222.222;208.67.220.220;2620:119:35::35;2620:119:53::53
Level3;4.2.2.1;4.2.2.2;;
Comodo;8.26.56.26;8.20.247.20;;
-DNS.WATCH;84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b
+DNS.WATCH (DNSSEC);84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b
Quad9 (filtered, DNSSEC);9.9.9.9;149.112.112.112;2620:fe::fe;2620:fe::9
Quad9 (unfiltered, no DNSSEC);9.9.9.10;149.112.112.10;2620:fe::10;2620:fe::fe:10
-Quad9 (filtered + ECS);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11
-Cloudflare;1.1.1.1;1.0.0.1;2606:4700:4700::1111;2606:4700:4700::1001
+Quad9 (filtered, ECS, DNSSEC);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11
+Cloudflare (DNSSEC);1.1.1.1;1.0.0.1;2606:4700:4700::1111;2606:4700:4700::1001
EOM
)
# Location for final installation log storage
-installLogLoc=/etc/pihole/install.log
+installLogLoc="/etc/pihole/install.log"
# This is an important file as it contains information specific to the machine it's being installed on
-setupVars=/etc/pihole/setupVars.conf
+setupVars="/etc/pihole/setupVars.conf"
# Pi-hole uses lighttpd as a Web server, and this is the config file for it
-# shellcheck disable=SC2034
-lighttpdConfig=/etc/lighttpd/lighttpd.conf
+lighttpdConfig="/etc/lighttpd/lighttpd.conf"
# This is a file used for the colorized output
-coltable=/opt/pihole/COL_TABLE
+coltable="/opt/pihole/COL_TABLE"
# Root of the web server
webroot="/var/www/html"
@@ -77,7 +76,7 @@ PI_HOLE_CONFIG_DIR="/etc/pihole"
PI_HOLE_BIN_DIR="/usr/local/bin"
PI_HOLE_BLOCKPAGE_DIR="${webroot}/pihole"
if [ -z "$useUpdateVars" ]; then
- useUpdateVars=false
+ useUpdateVars=false
fi
adlistFile="/etc/pihole/adlists.list"
@@ -91,27 +90,12 @@ PRIVACY_LEVEL=0
CACHE_SIZE=10000
if [ -z "${USER}" ]; then
- USER="$(id -un)"
+ USER="$(id -un)"
fi
-
-# Check if we are running on a real terminal and find the rows and columns
-# If there is no real terminal, we will default to 80x24
-if [ -t 0 ] ; then
- screen_size=$(stty size)
-else
- screen_size="24 80"
-fi
-# Determine terminal rows and columns by parsing screen_size
-printf -v rows '%d' "${screen_size%% *}"
-printf -v columns '%d' "${screen_size##* }"
-
-# Divide by two so the dialogs take up half of the screen, which looks nice.
-r=$(( rows / 2 ))
-c=$(( columns / 2 ))
-# Unless the screen is tiny
-r=$(( r < 20 ? 20 : r ))
-c=$(( c < 70 ? 70 : c ))
+# whiptail dialog dimensions: 20 rows and 70 chars width assures to fit on small screens and is known to hold all content.
+r=20
+c=70
######## Undocumented Flags. Shhh ########
# These are undocumented flags; some of which we can use when repairing an installation
@@ -149,7 +133,7 @@ fi
# A simple function that just echoes out our logo in ASCII format
# This lets users know that it is a Pi-hole, LLC product
show_ascii_berry() {
- echo -e "
+ echo -e "
${COL_LIGHT_GREEN}.;;,.
.ccccc:,.
:cccclll:. ..,,
@@ -277,123 +261,93 @@ os_check() {
# Compatibility
package_manager_detect() {
-# If apt-get is installed, then we know it's part of the Debian family
-if is_command apt-get ; then
- # Set some global variables here
- # We don't set them earlier since the family might be Red Hat, so these values would be different
- PKG_MANAGER="apt-get"
- # A variable to store the command used to update the package cache
- UPDATE_PKG_CACHE="${PKG_MANAGER} update"
- # The command we will use to actually install packages
- PKG_INSTALL=("${PKG_MANAGER}" -qq --no-install-recommends install)
- # grep -c will return 1 if there are no matches. This is an acceptable condition, so we OR TRUE to prevent set -e exiting the script.
- PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
- # Update package cache. This is required already here to assure apt-cache calls have package lists available.
- update_package_cache || exit 1
- # Debian 7 doesn't have iproute2 so check if it's available first
- if apt-cache show iproute2 > /dev/null 2>&1; then
- iproute_pkg="iproute2"
- # Otherwise, check if iproute is available
- elif apt-cache show iproute > /dev/null 2>&1; then
- iproute_pkg="iproute"
- # Else print error and exit
- else
- printf " %b Aborting installation: iproute2 and iproute packages were not found in APT repository.\\n" "${CROSS}"
- exit 1
- fi
- # Check for and determine version number (major and minor) of current php install
- if is_command php ; then
- printf " %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "$(php <<< "")"
- printf -v phpInsMajor "%d" "$(php <<< "")"
- printf -v phpInsMinor "%d" "$(php <<< "")"
- # Is installed php version 7.0 or greater
- if [ "${phpInsMajor}" -ge 7 ]; then
- phpInsNewer=true
+ # First check to see if apt-get is installed.
+ if is_command apt-get ; then
+ # Set some global variables here
+ # We don't set them earlier since the installed package manager might be rpm, so these values would be different
+ PKG_MANAGER="apt-get"
+ # A variable to store the command used to update the package cache
+ UPDATE_PKG_CACHE="${PKG_MANAGER} update"
+ # The command we will use to actually install packages
+ PKG_INSTALL=("${PKG_MANAGER}" -qq --no-install-recommends install)
+ # grep -c will return 1 if there are no matches. This is an acceptable condition, so we OR TRUE to prevent set -e exiting the script.
+ PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
+ # Update package cache
+ update_package_cache || exit 1
+ # Check for and determine version number (major and minor) of current php install
+ local phpVer="php"
+ if is_command php ; then
+ printf " %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "$(php <<< "")"
+ printf -v phpInsMajor "%d" "$(php <<< "")"
+ printf -v phpInsMinor "%d" "$(php <<< "")"
+ phpVer="php$phpInsMajor.$phpInsMinor"
fi
- fi
- # Several other packages depend on the version of PHP. If PHP is not installed, or an insufficient version,
- # those packages should fall back to the default (latest?)
- if [[ "$phpInsNewer" != true ]]; then
- # Prefer the php metapackage if it's there
- if apt-cache show php > /dev/null 2>&1; then
- phpVer="php"
- # Else fall back on the php5 package if it's there
- elif apt-cache show php5 > /dev/null 2>&1; then
- phpVer="php5"
- # Else print error and exit
+ # Packages required to perfom the os_check (stored as an array)
+ OS_CHECK_DEPS=(grep dnsutils)
+ # Packages required to run this install script (stored as an array)
+ INSTALLER_DEPS=(git iproute2 whiptail ca-certificates)
+ # Packages required to run Pi-hole (stored as an array)
+ PIHOLE_DEPS=(cron curl iputils-ping lsof psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2)
+ # Packages required for the Web admin interface (stored as an array)
+ # It's useful to separate this from Pi-hole, since the two repos are also setup separately
+ PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-sqlite3" "${phpVer}-xml" "${phpVer}-intl")
+ # Prior to PHP8.0, JSON functionality is provided as dedicated module, required by Pi-hole AdminLTE: https://www.php.net/manual/json.installation.php
+ if [[ -z "${phpInsMajor}" || "${phpInsMajor}" -lt 8 ]]; then
+ PIHOLE_WEB_DEPS+=("${phpVer}-json")
+ fi
+ # The Web server user,
+ LIGHTTPD_USER="www-data"
+ # group,
+ LIGHTTPD_GROUP="www-data"
+ # and config file
+ LIGHTTPD_CFG="lighttpd.conf.debian"
+
+ # This function waits for dpkg to unlock, which signals that the previous apt-get command has finished.
+ test_dpkg_lock() {
+ i=0
+ # fuser is a program to show which processes use the named files, sockets, or filesystems
+ # So while the lock is held,
+ while fuser /var/lib/dpkg/lock >/dev/null 2>&1
+ do
+ # we wait half a second,
+ sleep 0.5
+ # increase the iterator,
+ ((i=i+1))
+ done
+ # and then report success once dpkg is unlocked.
+ return 0
+ }
+
+ # If apt-get is not found, check for rpm.
+ elif is_command rpm ; then
+ # Then check if dnf or yum is the package manager
+ if is_command dnf ; then
+ PKG_MANAGER="dnf"
else
- printf " %b Aborting installation: No PHP packages were found in APT repository.\\n" "${CROSS}"
- exit 1
+ PKG_MANAGER="yum"
fi
- else
- # Else, PHP is already installed at a version beyond v7.0, so the additional packages
- # should match version with the current PHP version.
- phpVer="php$phpInsMajor.$phpInsMinor"
- fi
- # We also need the correct version for `php-sqlite` (which differs across distros)
- if apt-cache show "${phpVer}-sqlite3" > /dev/null 2>&1; then
- phpSqlite="sqlite3"
- elif apt-cache show "${phpVer}-sqlite" > /dev/null 2>&1; then
- phpSqlite="sqlite"
- else
- printf " %b Aborting installation: No SQLite PHP module was found in APT repository.\\n" "${CROSS}"
- exit 1
- fi
- # Packages required to perfom the os_check (stored as an array)
- OS_CHECK_DEPS=(grep dnsutils)
- # Packages required to run this install script (stored as an array)
- INSTALLER_DEPS=(git "${iproute_pkg}" whiptail)
- # Packages required to run Pi-hole (stored as an array)
- PIHOLE_DEPS=(cron curl iputils-ping lsof netcat psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2)
- # Packages required for the Web admin interface (stored as an array)
- # It's useful to separate this from Pi-hole, since the two repos are also setup separately
- PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-${phpSqlite}" "${phpVer}-xml" "${phpVer}-intl")
- # Prior to PHP8.0, JSON functionality is provided as dedicated module, required by Pi-hole AdminLTE: https://www.php.net/manual/json.installation.php
- if [[ "${phpInsNewer}" != true || "${phpInsMajor}" -lt 8 ]]; then
- PIHOLE_WEB_DEPS+=("${phpVer}-json")
- fi
- # The Web server user,
- LIGHTTPD_USER="www-data"
- # group,
- LIGHTTPD_GROUP="www-data"
- # and config file
- LIGHTTPD_CFG="lighttpd.conf.debian"
- # This function waits for dpkg to unlock, which signals that the previous apt-get command has finished.
- test_dpkg_lock() {
- i=0
- # fuser is a program to show which processes use the named files, sockets, or filesystems
- # So while the lock is held,
- while fuser /var/lib/dpkg/lock >/dev/null 2>&1
- do
- # we wait half a second,
- sleep 0.5
- # increase the iterator,
- ((i=i+1))
- done
- # and then report success once dpkg is unlocked.
- return 0
- }
+ # These variable names match the ones for apt-get. See above for an explanation of what they are for.
+ PKG_INSTALL=("${PKG_MANAGER}" install -y)
+ PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
+ OS_CHECK_DEPS=(grep bind-utils)
+ INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig ca-certificates)
+ PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc sqlite libcap lsof)
+ PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl)
+ LIGHTTPD_USER="lighttpd"
+ LIGHTTPD_GROUP="lighttpd"
+ LIGHTTPD_CFG="lighttpd.conf.fedora"
-# If apt-get is not found, check for rpm to see if it's a Red Hat family OS
-elif is_command rpm ; then
- # Then check if dnf or yum is the package manager
- if is_command dnf ; then
- PKG_MANAGER="dnf"
+ # If neither apt-get or yum/dnf package managers were found
else
- PKG_MANAGER="yum"
+ # we cannot install required packages
+ printf " %b No supported package manager found\\n" "${CROSS}"
+ # so exit the installer
+ exit
fi
+}
- # These variable names match the ones in the Debian family. See above for an explanation of what they are for.
- PKG_INSTALL=("${PKG_MANAGER}" install -y)
- PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
- OS_CHECK_DEPS=(grep bind-utils)
- INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig)
- PIHOLE_DEPS=(cronie curl findutils nmap-ncat sudo unzip libidn2 psmisc sqlite libcap lsof)
- PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl)
- LIGHTTPD_USER="lighttpd"
- LIGHTTPD_GROUP="lighttpd"
- LIGHTTPD_CFG="lighttpd.conf.fedora"
+select_rpm_php(){
# If the host OS is Fedora,
if grep -qiE 'fedora|fedberry' /etc/redhat-release; then
# all required packages should be available by default with the latest fedora release
@@ -445,46 +399,36 @@ elif is_command rpm ; then
REMI_PKG="remi-release"
REMI_REPO="remi-php72"
rpm -q ${REMI_PKG} &> /dev/null || rc=$?
- if [[ $rc -ne 0 ]]; then
- # The PHP version available via default repositories is older than version 7
- if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information" "${r}" "${c}"; then
- # User decided to NOT update PHP from REMI, attempt to install the default available PHP version
- printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
- : # continue with unsupported php version
- else
- printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
- "${PKG_INSTALL[@]}" "https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm" &> /dev/null
- # enable the PHP 7 repository via yum-config-manager (provided by yum-utils)
- "${PKG_INSTALL[@]}" "yum-utils" &> /dev/null
- yum-config-manager --enable ${REMI_REPO} &> /dev/null
- printf " %b Remi's RPM repository has been enabled for PHP7\\n" "${TICK}"
- # trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
- if "${PKG_INSTALL[@]}" "php-cli" &> /dev/null; then
- printf " %b PHP7 installed/updated via Remi's RPM repository\\n" "${TICK}"
+ if [[ $rc -ne 0 ]]; then
+ # The PHP version available via default repositories is older than version 7
+ if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information" "${r}" "${c}"; then
+ # User decided to NOT update PHP from REMI, attempt to install the default available PHP version
+ printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
+ : # continue with unsupported php version
else
- printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
- exit 1
+ printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
+ "${PKG_INSTALL[@]}" "https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm" &> /dev/null
+ # enable the PHP 7 repository via yum-config-manager (provided by yum-utils)
+ "${PKG_INSTALL[@]}" "yum-utils" &> /dev/null
+ yum-config-manager --enable ${REMI_REPO} &> /dev/null
+ printf " %b Remi's RPM repository has been enabled for PHP7\\n" "${TICK}"
+ # trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
+ if "${PKG_INSTALL[@]}" "php-cli" &> /dev/null; then
+ printf " %b PHP7 installed/updated via Remi's RPM repository\\n" "${TICK}"
+ else
+ printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
+ exit 1
+ fi
fi
+ fi # Warn user of unsupported version of Fedora or CentOS
+ if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" "${r}" "${c}"; then
+ printf " %b Aborting installation due to unsupported RPM based distribution\\n" "${CROSS}"
+ exit
+ else
+ printf " %b Continuing installation with unsupported RPM based distribution\\n" "${INFO}"
fi
fi
fi
- else
- # Warn user of unsupported version of Fedora or CentOS
- if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" "${r}" "${c}"; then
- printf " %b Aborting installation due to unsupported RPM based distribution\\n" "${CROSS}"
- exit
- else
- printf " %b Continuing installation with unsupported RPM based distribution\\n" "${INFO}"
- fi
- fi
-
-# If neither apt-get or yum/dnf package managers were found
-else
- # it's not an OS we can support,
- printf " %b OS distribution not supported\\n" "${CROSS}"
- # so exit the installer
- exit
-fi
}
# A function for checking if a directory is a git repository
@@ -570,12 +514,12 @@ update_repo() {
git stash --all --quiet &> /dev/null || true # Okay for stash failure
git clean --quiet --force -d || true # Okay for already clean directory
# Pull the latest commits
- git pull --quiet &> /dev/null || return $?
+ git pull --no-rebase --quiet &> /dev/null || return $?
# Check current branch. If it is master, then reset to the latest available tag.
# In case extra commits have been added after tagging/release (i.e in case of metadata updates/README.MD tweaks)
curBranch=$(git rev-parse --abbrev-ref HEAD)
if [[ "${curBranch}" == "master" ]]; then
- git reset --hard "$(git describe --abbrev=0 --tags)" || return $?
+ git reset --hard "$(git describe --abbrev=0 --tags)" || return $?
fi
# Show a completion message
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
@@ -685,12 +629,12 @@ welcomeDialogs() {
IMPORTANT: If you have not already done so, you must ensure that this device has a static IP. Either through DHCP reservation, or by manually assigning one. Depending on your operating system, there are many ways to achieve this.
Choose yes to indicate that you have understood this message, and wish to continue" "${r}" "${c}"; then
-#Nothing to do, continue
- echo
-else
- printf " %b Installer exited at static IP message.\\n" "${INFO}"
- exit 1
-fi
+ #Nothing to do, continue
+ echo
+ else
+ printf " %b Installer exited at static IP message.\\n" "${INFO}"
+ exit 1
+ fi
}
# A function that lets the user pick an interface to use with Pi-hole
@@ -730,7 +674,7 @@ chooseInterface() {
# Feed the available interfaces into this while loop
done <<< "${availableInterfaces}"
# The whiptail command that will be run, stored in a variable
- chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" "${interfaceCount}")
+ chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" 6)
# Now run the command using the interfaces saved into the array
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
# If the user chooses Cancel, exit
@@ -772,9 +716,8 @@ testIPv6() {
fi
}
-# A dialog for showing the user about IPv6 blocking
-useIPv6dialog() {
- # Determine the IPv6 address used for blocking
+find_IPv6_information() {
+ # Detects IPv6 address used for communication to WAN addresses.
IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}'))
# For each address in the array above, determine the type of IPv6 address it is
@@ -794,122 +737,91 @@ useIPv6dialog() {
# set the IPv6 address to the ULA address
IPV6_ADDRESS="${ULA_ADDRESS}"
# Show this info to the user
- printf " %b Found IPv6 ULA address, using it for blocking IPv6 ads\\n" "${INFO}"
+ printf " %b Found IPv6 ULA address\\n" "${INFO}"
# Otherwise, if the GUA_ADDRESS has a value,
elif [[ ! -z "${GUA_ADDRESS}" ]]; then
# Let the user know
- printf " %b Found IPv6 GUA address, using it for blocking IPv6 ads\\n" "${INFO}"
+ printf " %b Found IPv6 GUA address\\n" "${INFO}"
# And assign it to the global variable
IPV6_ADDRESS="${GUA_ADDRESS}"
# If none of those work,
else
- # explain that IPv6 blocking will not be used
- printf " %b Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled\\n" "${INFO}"
+ printf " %b Unable to find IPv6 ULA/GUA address\\n" "${INFO}"
# So set the variable to be empty
IPV6_ADDRESS=""
fi
-
- # If the IPV6_ADDRESS contains a value
- if [[ ! -z "${IPV6_ADDRESS}" ]]; then
- # Display that IPv6 is supported and will be used
- whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." "${r}" "${c}"
- fi
}
-# A function to check if we should use IPv4 and/or IPv6 for blocking ads
-use4andor6() {
- # Named local variables
- local useIPv4
- local useIPv6
- # Let user choose IPv4 and/or IPv6 via a checklist
- cmd=(whiptail --separate-output --checklist "Select Protocols (press space to toggle selection)" "${r}" "${c}" 2)
- # In an array, show the options available:
- # IPv4 (on by default)
- options=(IPv4 "Block ads over IPv4" on
- # or IPv6 (on by default if available)
- IPv6 "Block ads over IPv6" on)
- # In a variable, show the choices available; exit if Cancel is selected
- choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
- # For each choice available,
- for choice in ${choices}
- do
- # Set the values to true
- case ${choice} in
- IPv4 ) useIPv4=true;;
- IPv6 ) useIPv6=true;;
- esac
- done
- # If IPv4 is to be used,
- if [[ "${useIPv4}" ]]; then
- # Run our function to get the information we need
- find_IPv4_information
- if [[ -f "/etc/dhcpcd.conf" ]]; then
- # configure networking via dhcpcd
- getStaticIPv4Settings
- setDHCPCD
- fi
- fi
- # If IPv6 is to be used,
- if [[ "${useIPv6}" ]]; then
- # Run our function to get this information
- useIPv6dialog
- fi
+# A function to collect IPv4 and IPv6 information of the device
+collect_v4andv6_information() {
+ find_IPv4_information
# Echo the information to the user
printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
- printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
- # If neither protocol is selected,
- if [[ ! "${useIPv4}" ]] && [[ ! "${useIPv6}" ]]; then
- # Show an error in red
- printf " %bError: Neither IPv4 or IPv6 selected%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
- # and exit with an error
- exit 1
+ # if `dhcpcd` is used offer to set this as static IP for the device
+ if [[ -f "/etc/dhcpcd.conf" ]]; then
+ # configure networking via dhcpcd
+ getStaticIPv4Settings
fi
+ find_IPv6_information
+ printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
}
getStaticIPv4Settings() {
# Local, named variables
local ipSettingsCorrect
+ local DHCPChoice
# Ask if the user wants to use DHCP settings as their static IP
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
- 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}
- Gateway: ${IPv4gw}" "${r}" "${c}"; then
+ DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n
+ IP address: ${IPV4_ADDRESS} \\n
+ Gateway: ${IPv4gw} \\n" "${r}" "${c}" 3\
+ "Yes" "Set static IP using current values" \
+ "No" "Set static IP using custom values" \
+ "Skip" "I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3) || \
+ { printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
+
+ case ${DHCPChoice} in
+ "Yes")
# 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.
-If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
-It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
- # Nothing else to do since the variables are already set above
- else
- # Otherwise, we need to ask the user to input their desired settings.
- # 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
- until [[ "${ipSettingsCorrect}" = True ]]; do
+ If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
+ It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
+ # Nothing else to do since the variables are already set above
+ setDHCPCD
+ ;;
- # 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) || \
- # Canceling IPv4 settings window
- { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
- printf " %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
+ "No")
+ # Otherwise, we need to ask the user to input their desired settings.
+ # 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
+ until [[ "${ipSettingsCorrect}" = True ]]; do
- # 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) || \
- # Canceling gateway settings window
- { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
- printf " %b Your static IPv4 gateway: %s\\n" "${INFO}" "${IPv4gw}"
+ # 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) || \
+ # Canceling IPv4 settings window
+ { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+ printf " %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
- # 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
- # End the if statement for DHCP vs. static
- 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) || \
+ # Canceling gateway settings window
+ { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+ printf " %b Your static IPv4 gateway: %s\\n" "${INFO}" "${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
+ setDHCPCD
+ ;;
+ esac
}
# Configure networking via dhcpcd
@@ -1001,8 +913,8 @@ setDNS() {
IFS=${OIFS}
# In a whiptail dialog, show the options
DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." "${r}" "${c}" 7 \
- "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
- # Exit if the user selects "Cancel"
+ "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
+ # Exit if the user selects "Cancel"
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
# Depending on the user's choice, set the GLOBAL variables to the IP of the respective provider
@@ -1247,8 +1159,10 @@ version_check_dnsmasq() {
local dnsmasq_pihole_id_string="addn-hosts=/etc/pihole/gravity.list"
local dnsmasq_pihole_id_string2="# Dnsmasq config for Pi-hole's FTLDNS"
local dnsmasq_original_config="${PI_HOLE_LOCAL_REPO}/advanced/dnsmasq.conf.original"
- local dnsmasq_pihole_01_snippet="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf"
- local dnsmasq_pihole_01_location="/etc/dnsmasq.d/01-pihole.conf"
+ local dnsmasq_pihole_01_source="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf"
+ local dnsmasq_pihole_01_target="/etc/dnsmasq.d/01-pihole.conf"
+ local dnsmasq_rfc6761_06_source="${PI_HOLE_LOCAL_REPO}/advanced/06-rfc6761.conf"
+ local dnsmasq_rfc6761_06_target="/etc/dnsmasq.d/06-rfc6761.conf"
# If the dnsmasq config file exists
if [[ -f "${dnsmasq_conf}" ]]; then
@@ -1266,8 +1180,8 @@ version_check_dnsmasq() {
install -D -m 644 -T "${dnsmasq_original_config}" "${dnsmasq_conf}"
printf "%b %b Restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}"
else
- # Otherwise, don't to anything
- printf " it is not a Pi-hole file, leaving alone!\\n"
+ # Otherwise, don't to anything
+ printf " it is not a Pi-hole file, leaving alone!\\n"
fi
else
# If a file cannot be found,
@@ -1277,44 +1191,48 @@ version_check_dnsmasq() {
printf "%b %b No dnsmasq.conf found... restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}"
fi
- printf " %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..." "${INFO}"
+ printf " %b Installing %s..." "${INFO}" "${dnsmasq_pihole_01_target}"
# Check to see if dnsmasq directory exists (it may not due to being a fresh install and dnsmasq no longer being a dependency)
if [[ ! -d "/etc/dnsmasq.d" ]];then
install -d -m 755 "/etc/dnsmasq.d"
fi
# Copy the new Pi-hole DNS config file into the dnsmasq.d directory
- install -D -m 644 -T "${dnsmasq_pihole_01_snippet}" "${dnsmasq_pihole_01_location}"
- printf "%b %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf\\n" "${OVER}" "${TICK}"
+ install -D -m 644 -T "${dnsmasq_pihole_01_source}" "${dnsmasq_pihole_01_target}"
+ printf "%b %b Installed %s\n" "${OVER}" "${TICK}" "${dnsmasq_pihole_01_target}"
# Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
# First, swap in the interface to listen on,
- sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_location}"
+ sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_target}"
if [[ "${PIHOLE_DNS_1}" != "" ]]; then
# then swap in the primary DNS server.
- sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_location}"
+ sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_target}"
else
# Otherwise, remove the line which sets DNS1.
- sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_location}"
+ sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_target}"
fi
# Ditto if DNS2 is not empty
if [[ "${PIHOLE_DNS_2}" != "" ]]; then
- sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_location}"
+ sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_target}"
else
- sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_location}"
+ sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_target}"
fi
- # Set the cache size
- sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" ${dnsmasq_pihole_01_location}
+ # Set the cache size
+ sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" "${dnsmasq_pihole_01_target}"
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' "${dnsmasq_conf}"
# If the user does not want to enable logging,
if [[ "${QUERY_LOGGING}" == false ]] ; then
# disable it by commenting out the directive in the DNS config file
- sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_location}"
+ sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_target}"
else
# Otherwise, enable it by uncommenting the directive in the DNS config file
- sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_location}"
+ sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_target}"
fi
+
+ printf " %b Installing %s..." "${INFO}" "${dnsmasq_rfc6761_06_source}"
+ install -D -m 644 -T "${dnsmasq_rfc6761_06_source}" "${dnsmasq_rfc6761_06_target}"
+ printf "%b %b Installed %s\n" "${OVER}" "${TICK}" "${dnsmasq_rfc6761_06_target}"
}
# Clean an existing installation to prepare for upgrade/reinstall
@@ -1405,18 +1323,18 @@ installConfigs() {
# make it and set the owners
install -d -m 755 -o "${USER}" -g root /etc/lighttpd
# Otherwise, if the config file already exists
- elif [[ -f "/etc/lighttpd/lighttpd.conf" ]]; then
+ elif [[ -f "${lighttpdConfig}" ]]; then
# back up the original
- mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
+ mv "${lighttpdConfig}"{,.orig}
fi
# and copy in the config file Pi-hole needs
- install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf
+ install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}"
# Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it
touch /etc/lighttpd/external.conf
chmod 644 /etc/lighttpd/external.conf
# If there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config
if [[ -f "${PI_HOLE_BLOCKPAGE_DIR}/custom.php" ]]; then
- sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' /etc/lighttpd/lighttpd.conf
+ sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' "${lighttpdConfig}"
fi
# Make the directories if they do not exist and set the owners
mkdir -p /run/lighttpd
@@ -1563,9 +1481,6 @@ disable_resolved_stublistener() {
}
update_package_cache() {
- # Running apt-get update/upgrade with minimal output can cause some issues with
- # requiring user input (e.g password for phpmyadmin see #218)
-
# Update package cache on apt based OSes. Do this every time since
# it's quick and packages can be updated at any time.
@@ -1577,8 +1492,14 @@ update_package_cache() {
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else
# Otherwise, show an error and exit
+
+ # In case we used apt-get and apt is also available, we use this as recommendation as we have seen it
+ # gives more user-friendly (interactive) advice
+ if [[ ${PKG_MANAGER} == "apt-get" ]] && is_command apt ; then
+ UPDATE_PKG_CACHE="apt update"
+ fi
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
- printf " %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "${UPDATE_PKG_CACHE}" "${COL_NC}"
+ printf " %bError: Unable to update package cache. Please try \"%s\"%b\\n" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
return 1
fi
}
@@ -1630,6 +1551,8 @@ install_dependent_packages() {
# If there's anything to install, install everything in the list.
if [[ "${#installArray[@]}" -gt 0 ]]; then
test_dpkg_lock
+ # Running apt-get install with minimal output can cause some issues with
+ # requiring user input (e.g password for phpmyadmin see #218)
printf " %b Processing %s install(s) for: %s, please wait...\\n" "${INFO}" "${PKG_MANAGER}" "${installArray[*]}"
printf '%*s\n' "$columns" '' | tr " " -;
"${PKG_INSTALL[@]}" "${installArray[@]}"
@@ -1642,7 +1565,7 @@ install_dependent_packages() {
# Install Fedora/CentOS packages
for i in "$@"; do
- # For each package, check if it's already installed (and if so, don't add it to the installArray)
+ # For each package, check if it's already installed (and if so, don't add it to the installArray)
printf " %b Checking for %s..." "${INFO}" "${i}"
if "${PKG_MANAGER}" -q list installed "${i}" &> /dev/null; then
printf "%b %b Checking for %s\\n" "${OVER}" "${TICK}" "${i}"
@@ -1808,20 +1731,22 @@ finalExports() {
# If the setup variable file exists,
if [[ -e "${setupVars}" ]]; then
# update the variables in the file
- sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;' "${setupVars}"
+ sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/d;' "${setupVars}"
fi
# echo the information to the user
{
- echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
- echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
- echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
- echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
- echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
- echo "QUERY_LOGGING=${QUERY_LOGGING}"
- echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}"
- echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}"
- echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}"
- echo "CACHE_SIZE=${CACHE_SIZE}"
+ echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
+ echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
+ echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
+ echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
+ echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
+ echo "QUERY_LOGGING=${QUERY_LOGGING}"
+ echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}"
+ echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}"
+ echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}"
+ echo "CACHE_SIZE=${CACHE_SIZE}"
+ echo "DNS_FQDN_REQUIRED=${DNS_FQDN_REQUIRED:-true}"
+ echo "DNS_BOGUS_PRIV=${DNS_BOGUS_PRIV:-true}"
}>> "${setupVars}"
chmod 644 "${setupVars}"
@@ -1869,27 +1794,6 @@ installLogrotate() {
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
}
-# At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
-# Refactoring of install script has changed the name of a couple of variables. Sort them out here.
-accountForRefactor() {
- sed -i 's/piholeInterface/PIHOLE_INTERFACE/g' "${setupVars}"
- sed -i 's/IPv4_address/IPV4_ADDRESS/g' "${setupVars}"
- sed -i 's/IPv4addr/IPV4_ADDRESS/g' "${setupVars}"
- sed -i 's/IPv6_address/IPV6_ADDRESS/g' "${setupVars}"
- sed -i 's/piholeIPv6/IPV6_ADDRESS/g' "${setupVars}"
- sed -i 's/piholeDNS1/PIHOLE_DNS_1/g' "${setupVars}"
- sed -i 's/piholeDNS2/PIHOLE_DNS_2/g' "${setupVars}"
- sed -i 's/^INSTALL_WEB=/INSTALL_WEB_INTERFACE=/' "${setupVars}"
- # Add 'INSTALL_WEB_SERVER', if its not been applied already: https://github.com/pi-hole/pi-hole/pull/2115
- if ! grep -q '^INSTALL_WEB_SERVER=' ${setupVars}; then
- local webserver_installed=false
- if grep -q '^INSTALL_WEB_INTERFACE=true' ${setupVars}; then
- webserver_installed=true
- fi
- echo -e "INSTALL_WEB_SERVER=$webserver_installed" >> "${setupVars}"
- fi
-}
-
# Install base files and web interface
installPihole() {
# If the user wants to install the Web interface,
@@ -1920,10 +1824,6 @@ installPihole() {
fi
fi
fi
- # For updates and unattended install.
- if [[ "${useUpdateVars}" == true ]]; then
- accountForRefactor
- fi
# Install base files and web interface
if ! installScripts; then
printf " %b Failure in dependent script copy function.\\n" "${CROSS}"
@@ -2008,7 +1908,7 @@ displayFinalMessage() {
if [[ "${#1}" -gt 0 ]] ; then
# set the password to the first argument.
pwstring="$1"
- elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then
+ elif [[ $(grep 'WEBPASSWORD' -c "${setupVars}") -gt 0 ]]; then
# Else if the password exists from previous setup, we'll load it later
pwstring="unchanged"
else
@@ -2021,7 +1921,7 @@ displayFinalMessage() {
additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin
Your Admin Webpage login password is ${pwstring}"
- fi
+ fi
# Final completion message to user
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using:
@@ -2031,8 +1931,6 @@ IPv6: ${IPV6_ADDRESS:-"Not Configured"}
If you have not done so already, the above IP should be set to static.
-The install log is in /etc/pihole.
-
${additional}" "${r}" "${c}"
}
@@ -2050,7 +1948,7 @@ update_dialogs() {
strAdd="You will be updated to the latest version."
fi
opt2a="Reconfigure"
- opt2b="This will reset your Pi-hole and allow you to enter new settings."
+ opt2b="Resets Pi-hole and allows re-selecting settings."
# Display the information to the user
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 \
@@ -2145,7 +2043,7 @@ checkout_pull_branch() {
# Data in the repositories is public anyway so we can make it readable by everyone (+r to keep executable permission if already set by git)
chmod -R a+rX "${directory}"
- git_pull=$(git pull || return 1)
+ git_pull=$(git pull --no-rebase || return 1)
if [[ "$git_pull" == *"up-to-date"* ]]; then
printf " %b %s\\n" "${INFO}" "${git_pull}"
@@ -2556,6 +2454,11 @@ main() {
printf " %b Checking for / installing Required dependencies for this install script...\\n" "${INFO}"
install_dependent_packages "${INSTALLER_DEPS[@]}"
+ #In case of RPM based distro, select the proper PHP version
+ if [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]] ; then
+ select_rpm_php
+ fi
+
# Check if SELinux is Enforcing
checkSelinux
@@ -2583,12 +2486,12 @@ main() {
get_available_interfaces
# Find interfaces and let the user choose one
chooseInterface
+ # find IPv4 and IPv6 information of the device
+ collect_v4andv6_information
# Decide what upstream DNS Servers to use
setDNS
# Give the user a choice of blocklists to include in their install. Or not.
chooseBlocklists
- # Let the user decide if they want to block ads over IPv4 and/or IPv6
- use4andor6
# Let the user decide if they want the web interface to be installed automatically
setAdminFlag
# Let the user decide if they want query logging enabled...
@@ -2661,7 +2564,7 @@ main() {
# Add password to web UI if there is none
pw=""
# If no password is set,
- if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then
+ if [[ $(grep 'WEBPASSWORD' -c "${setupVars}") == 0 ]] ; then
# generate a random password
pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
# shellcheck disable=SC1091
diff --git a/automated install/uninstall.sh b/automated install/uninstall.sh
index 0f4c4ca6..5e27514f 100755
--- a/automated install/uninstall.sh
+++ b/automated install/uninstall.sh
@@ -145,6 +145,7 @@ removeNoPurge() {
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.conf &> /dev/null
+ ${SUDO} rm -f /etc/dnsmasq.d/06-rfc6761.conf &> /dev/null
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
${SUDO} rm -rf /etc/pihole/ &> /dev/null
${SUDO} rm -rf /etc/.pihole/ &> /dev/null
diff --git a/gravity.sh b/gravity.sh
index ff02e9f3..bb4f4e4b 100755
--- a/gravity.sh
+++ b/gravity.sh
@@ -15,8 +15,6 @@ export LC_ALL=C
coltable="/opt/pihole/COL_TABLE"
source "${coltable}"
-regexconverter="/opt/pihole/wildcard_regex_converter.sh"
-source "${regexconverter}"
# shellcheck disable=SC1091
source "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh"
@@ -122,7 +120,7 @@ gravity_swap_databases() {
gravityBlocks=$(stat --format "%b" ${gravityDBfile})
# Only keep the old database if available disk space is at least twice the size of the existing gravity.db.
# Better be safe than sorry...
- if [ "${availableBlocks}" -gt "$(("${gravityBlocks}" * 2))" ] && [ -f "${gravityDBfile}" ]; then
+ if [ "${availableBlocks}" -gt "$((gravityBlocks * 2))" ] && [ -f "${gravityDBfile}" ]; then
echo -e " ${TICK} The old database remains available."
mv "${gravityDBfile}" "${gravityOLDfile}"
else
@@ -215,7 +213,7 @@ database_table_from_file() {
# Move source file to backup directory, create directory if not existing
mkdir -p "${backup_path}"
mv "${source}" "${backup_file}" 2> /dev/null || \
- echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
+ echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
# Delete tmpFile
rm "${tmpFile}" > /dev/null 2>&1 || \
@@ -432,9 +430,9 @@ gravity_DownloadBlocklists() {
compression="--compressed"
echo -e " ${INFO} Using libz compression\n"
else
- compression=""
- echo -e " ${INFO} Libz compression not available\n"
- fi
+ compression=""
+ echo -e " ${INFO} Libz compression not available\n"
+ fi
# Loop through $sources and download each one
for ((i = 0; i < "${#sources[@]}"; i++)); do
url="${sources[$i]}"
@@ -464,9 +462,9 @@ gravity_DownloadBlocklists() {
check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$url" )"
if [[ "${check_url}" =~ ${regex} ]]; then
- echo -e " ${CROSS} Invalid Target"
+ echo -e " ${CROSS} Invalid Target"
else
- gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}"
+ gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}"
fi
echo ""
done
@@ -585,28 +583,28 @@ gravity_DownloadBlocklistFromUrl() {
blocked=false
case $BLOCKINGMODE in
"IP-NODATA-AAAA"|"IP")
- # Get IP address of this domain
- ip="$(dig "${domain}" +short)"
- # Check if this IP matches any IP of the system
- if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<< "$(ip a)") -gt 0 ]]; then
- blocked=true
- fi;;
+ # Get IP address of this domain
+ ip="$(dig "${domain}" +short)"
+ # Check if this IP matches any IP of the system
+ if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<< "$(ip a)") -gt 0 ]]; then
+ blocked=true
+ fi;;
"NXDOMAIN")
- if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
- blocked=true
- fi;;
+ if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
+ blocked=true
+ fi;;
"NULL"|*)
- if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
- blocked=true
- fi;;
- esac
+ if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
+ blocked=true
+ fi;;
+ esac
if [[ "${blocked}" == true ]]; then
printf -v ip_addr "%s" "${PIHOLE_DNS_1%#*}"
if [[ ${PIHOLE_DNS_1} != *"#"* ]]; then
- port=53
+ port=53
else
- printf -v port "%s" "${PIHOLE_DNS_1#*#}"
+ printf -v port "%s" "${PIHOLE_DNS_1#*#}"
fi
ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}" | tail -1)
if [[ $(echo "${url}" | awk -F '://' '{print $1}') = "https" ]]; then
@@ -625,11 +623,11 @@ gravity_DownloadBlocklistFromUrl() {
case $url in
# Did we "download" a local file?
"file"*)
- if [[ -s "${patternBuffer}" ]]; then
- echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
- else
- echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
- fi;;
+ if [[ -s "${patternBuffer}" ]]; then
+ echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
+ else
+ echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
+ fi;;
# Did we "download" a remote file?
*)
# Determine "Status:" output based on HTTP response
diff --git a/pihole b/pihole
index 96a4a9f6..4f1b95eb 100755
--- a/pihole
+++ b/pihole
@@ -398,34 +398,24 @@ Branches:
}
tricorderFunc() {
+ local tricorder_token
if [[ ! -p "/dev/stdin" ]]; then
echo -e " ${INFO} Please do not call Tricorder directly"
exit 1
fi
- if ! (echo > /dev/tcp/tricorder.pi-hole.net/9998) >/dev/null 2>&1; then
- echo -e " ${CROSS} Unable to connect to Pi-hole's Tricorder server"
- exit 1
- fi
-
- if command -v openssl &> /dev/null; then
- openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin
- exit "$?"
- else
- echo -e " ${INFO} ${COL_YELLOW}Security Notice${COL_NC}: ${COL_WHITE}openssl${COL_NC} is not installed
- Your debug log will be transmitted unencrypted via plain-text
- There is a possibility that this could be intercepted by a third party
- If you wish to cancel, press Ctrl-C to exit within 10 seconds"
- secs="10"
- while [[ "$secs" -gt "0" ]]; do
- echo -ne "."
- sleep 1
- : $((secs--))
- done
- echo " "
- nc tricorder.pi-hole.net 9999 < /dev/stdin
- exit "$?"
+ tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
+ if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
+ echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
+ # Log curl error (if available)
+ if [ -n "${tricorder_token}" ]; then
+ echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
+ tricorder_token=""
+ fi
+ exit 1
fi
+ echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
+ exit 0
}
updateCheckFunc() {
diff --git a/test/README.md b/test/README.md
index b4dd1122..692155b7 100644
--- a/test/README.md
+++ b/test/README.md
@@ -18,8 +18,8 @@ py.test -vv -n auto -m "build_stage"
py.test -vv -n auto -m "not build_stage"
```
-The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
+The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
# How do I debug python?
-Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
+Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
diff --git a/test/_centos_7.Dockerfile b/test/_centos_7.Dockerfile
index 434242bf..355f4fdb 100644
--- a/test/_centos_7.Dockerfile
+++ b/test/_centos_7.Dockerfile
@@ -1,4 +1,5 @@
FROM centos:7
+RUN yum install -y git
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
diff --git a/test/_centos_8.Dockerfile b/test/_centos_8.Dockerfile
index afd2dc8a..fddb3ed1 100644
--- a/test/_centos_8.Dockerfile
+++ b/test/_centos_8.Dockerfile
@@ -1,4 +1,5 @@
FROM centos:8
+RUN yum install -y git
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
diff --git a/test/_fedora_33.Dockerfile b/test/_fedora_33.Dockerfile
index 9ae94c70..5cdd66ee 100644
--- a/test/_fedora_33.Dockerfile
+++ b/test/_fedora_33.Dockerfile
@@ -1,4 +1,5 @@
FROM fedora:33
+RUN dnf install -y git
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
diff --git a/test/_fedora_32.Dockerfile b/test/_fedora_34.Dockerfile
similarity index 93%
rename from test/_fedora_32.Dockerfile
rename to test/_fedora_34.Dockerfile
index e9c2ff2a..fbbaacd6 100644
--- a/test/_fedora_32.Dockerfile
+++ b/test/_fedora_34.Dockerfile
@@ -1,4 +1,5 @@
-FROM fedora:32
+FROM fedora:34
+RUN dnf install -y git
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
diff --git a/test/conftest.py b/test/conftest.py
index 13731eb8..fb7e1eea 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -1,10 +1,9 @@
import pytest
import testinfra
+import testinfra.backend.docker
+import subprocess
from textwrap import dedent
-check_output = testinfra.get_backend(
- "local://"
-).get_module("Command").check_output
SETUPVARS = {
'PIHOLE_INTERFACE': 'eth99',
@@ -12,85 +11,42 @@ SETUPVARS = {
'PIHOLE_DNS_2': '4.2.2.2'
}
+IMAGE = 'pytest_pihole:test_container'
+
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
info_box = "[i]"
-@pytest.fixture
-def Pihole(Docker):
- '''
- used to contain some script stubbing, now pretty much an alias.
- Also provides bash as the default run function shell
- '''
- def run_bash(self, command, *args, **kwargs):
- cmd = self.get_command(command, *args)
- if self.user is not None:
- out = self.run_local(
- "docker exec -u %s %s /bin/bash -c %s",
- self.user, self.name, cmd)
- else:
- out = self.run_local(
- "docker exec %s /bin/bash -c %s", self.name, cmd)
- out.command = self.encode(cmd)
- return out
+# Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
+# https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
+def run_bash(self, command, *args, **kwargs):
+ cmd = self.get_command(command, *args)
+ if self.user is not None:
+ out = self.run_local(
+ "docker exec -u %s %s /bin/bash -c %s", self.user, self.name, cmd
+ )
+ else:
+ out = self.run_local("docker exec %s /bin/bash -c %s", self.name, cmd)
+ out.command = self.encode(cmd)
+ return out
- funcType = type(Docker.run)
- Docker.run = funcType(run_bash, Docker)
- return Docker
+
+testinfra.backend.docker.DockerBackend.run = run_bash
@pytest.fixture
-def Docker(request, args, image, cmd):
- '''
- combine our fixtures into a docker run command and setup finalizer to
- cleanup
- '''
- assert 'docker' in check_output('id'), "Are you in the docker group?"
- docker_run = "docker run {} {} {}".format(args, image, cmd)
- docker_id = check_output(docker_run)
+def host():
+ # run a container
+ docker_id = subprocess.check_output(
+ ['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
- def teardown():
- check_output("docker rm -f %s", docker_id)
- request.addfinalizer(teardown)
+ # return a testinfra connection to the container
+ docker_host = testinfra.get_host("docker://" + docker_id)
- docker_container = testinfra.get_backend("docker://" + docker_id)
- docker_container.id = docker_id
- return docker_container
-
-
-@pytest.fixture
-def args(request):
- '''
- -t became required when tput began being used
- '''
- return '-t -d'
-
-
-@pytest.fixture(params=[
- 'test_container'
-])
-def tag(request):
- '''
- consumed by image to make the test matrix
- '''
- return request.param
-
-
-@pytest.fixture()
-def image(request, tag):
- '''
- built by test_000_build_containers.py
- '''
- return 'pytest_pihole:{}'.format(tag)
-
-
-@pytest.fixture()
-def cmd(request):
- '''
- default to doing nothing by tailing null, but don't exit
- '''
- return 'tail -f /dev/null'
+ yield docker_host
+ # at the end of the test suite, destroy the container
+ subprocess.check_call(['docker', 'rm', '-f', docker_id])
# Helper functions
@@ -100,7 +56,7 @@ def mock_command(script, args, container):
in unit tests
'''
full_script_path = '/usr/local/bin/{}'.format(script)
- mock_script = dedent('''\
+ mock_script = dedent(r'''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1" in'''.format(script=script))
@@ -121,13 +77,75 @@ def mock_command(script, args, container):
scriptlog=script))
+def mock_command_passthrough(script, args, container):
+ '''
+ Per other mock_command* functions, allows intercepting of commands we don't want to run for real
+ in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
+ be passed through to the actual command.
+
+ Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
+ '''
+ orig_script_path = container.check_output('command -v {}'.format(script))
+ full_script_path = '/usr/local/bin/{}'.format(script)
+ mock_script = dedent(r'''\
+ #!/bin/bash -e
+ echo "\$0 \$@" >> /var/log/{script}
+ case "\$1" in'''.format(script=script))
+ for k, v in args.items():
+ case = dedent('''
+ {arg})
+ echo {res}
+ exit {retcode}
+ ;;'''.format(arg=k, res=v[0], retcode=v[1]))
+ mock_script += case
+ mock_script += dedent(r'''
+ *)
+ {orig_script_path} "\$@"
+ ;;'''.format(orig_script_path=orig_script_path))
+ mock_script += dedent('''
+ esac''')
+ container.run('''
+ cat < {script}\n{content}\nEOF
+ chmod +x {script}
+ rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
+ content=mock_script,
+ scriptlog=script))
+
+
+def mock_command_run(script, args, container):
+ '''
+ Allows for setup of commands we don't really want to have to run for real
+ in unit tests
+ '''
+ full_script_path = '/usr/local/bin/{}'.format(script)
+ mock_script = dedent(r'''\
+ #!/bin/bash -e
+ echo "\$0 \$@" >> /var/log/{script}
+ case "\$1 \$2" in'''.format(script=script))
+ for k, v in args.items():
+ 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('''
+ cat < {script}\n{content}\nEOF
+ chmod +x {script}
+ rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
+ content=mock_script,
+ scriptlog=script))
+
+
def mock_command_2(script, args, container):
'''
Allows for setup of commands we don't really want to have to run for real
in unit tests
'''
full_script_path = '/usr/local/bin/{}'.format(script)
- mock_script = dedent('''\
+ mock_script = dedent(r'''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in'''.format(script=script))
diff --git a/test/requirements.txt b/test/requirements.txt
index 17d62ad9..d65ee6a5 100644
--- a/test/requirements.txt
+++ b/test/requirements.txt
@@ -1,6 +1,6 @@
-docker-compose==1.23.2
-pytest==4.3.0
-pytest-xdist==1.26.1
-pytest-cov==2.6.1
-testinfra==1.19.0
-tox==3.7.0
+docker-compose
+pytest
+pytest-xdist
+pytest-cov
+pytest-testinfra
+tox
diff --git a/test/test_automated_install.py b/test/test_automated_install.py
index 593c19d2..911407fc 100644
--- a/test/test_automated_install.py
+++ b/test/test_automated_install.py
@@ -1,3 +1,4 @@
+import pytest
from textwrap import dedent
import re
from .conftest import (
@@ -6,28 +7,30 @@ from .conftest import (
info_box,
cross_box,
mock_command,
+ mock_command_run,
mock_command_2,
+ mock_command_passthrough,
run_script
)
-def test_supported_operating_system(Pihole):
+def test_supported_package_manager(host):
'''
- confirm installer exists on unsupported distribution
+ confirm installer exits when no supported package manager found
'''
- # break supported package managers to emulate an unsupported distribution
- Pihole.run('rm -rf /usr/bin/apt-get')
- Pihole.run('rm -rf /usr/bin/rpm')
- package_manager_detect = Pihole.run('''
+ # break supported package managers
+ host.run('rm -rf /usr/bin/apt-get')
+ host.run('rm -rf /usr/bin/rpm')
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
''')
- expected_stdout = cross_box + ' OS distribution not supported'
+ expected_stdout = cross_box + ' No supported package manager found'
assert expected_stdout in package_manager_detect.stdout
# assert package_manager_detect.rc == 1
-def test_setupVars_are_sourced_to_global_scope(Pihole):
+def test_setupVars_are_sourced_to_global_scope(host):
'''
currently update_dialogs sources setupVars with a dot,
then various other functions use the variables.
@@ -37,7 +40,7 @@ def test_setupVars_are_sourced_to_global_scope(Pihole):
for k, v in SETUPVARS.items():
setup_var_file += "{}={}\n".format(k, v)
setup_var_file += "EOF\n"
- Pihole.run(setup_var_file)
+ host.run(setup_var_file)
script = dedent('''\
set -e
@@ -55,13 +58,13 @@ def test_setupVars_are_sourced_to_global_scope(Pihole):
printSetupVars
''')
- output = run_script(Pihole, script).stdout
+ output = run_script(host, script).stdout
for k, v in SETUPVARS.items():
assert "{}={}".format(k, v) in output
-def test_setupVars_saved_to_file(Pihole):
+def test_setupVars_saved_to_file(host):
'''
confirm saved settings are written to a file for future updates to re-use
'''
@@ -69,7 +72,7 @@ def test_setupVars_saved_to_file(Pihole):
set_setup_vars = '\n'
for k, v in SETUPVARS.items():
set_setup_vars += " {}={}\n".format(k, v)
- Pihole.run(set_setup_vars).stdout
+ host.run(set_setup_vars)
script = dedent('''\
set -e
@@ -84,17 +87,17 @@ def test_setupVars_saved_to_file(Pihole):
cat /etc/pihole/setupVars.conf
'''.format(set_setup_vars))
- output = run_script(Pihole, script).stdout
+ output = run_script(host, script).stdout
for k, v in SETUPVARS.items():
assert "{}={}".format(k, v) in output
-def test_selinux_not_detected(Pihole):
+def test_selinux_not_detected(host):
'''
confirms installer continues when SELinux configuration file does not exist
'''
- check_selinux = Pihole.run('''
+ check_selinux = host.run('''
rm -f /etc/selinux/config
source /opt/pihole/basic-install.sh
checkSelinux
@@ -104,11 +107,12 @@ def test_selinux_not_detected(Pihole):
assert check_selinux.rc == 0
-def test_installPiholeWeb_fresh_install_no_errors(Pihole):
+def test_installPiholeWeb_fresh_install_no_errors(host):
'''
confirms all web page assets from Core repo are installed on a fresh build
'''
- installWeb = Pihole.run('''
+ installWeb = host.run('''
+ umask 0027
source /opt/pihole/basic-install.sh
installPiholeWeb
''')
@@ -124,16 +128,527 @@ def test_installPiholeWeb_fresh_install_no_errors(Pihole):
assert expected_stdout in installWeb.stdout
expected_stdout = tick_box + ' Installing sudoer file'
assert expected_stdout in installWeb.stdout
- web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
+ web_directory = host.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'blockingpage.css' in web_directory
-def test_update_package_cache_success_no_errors(Pihole):
+def get_directories_recursive(host, directory):
+ if directory is None:
+ return directory
+ ls = host.run('ls -d {}'.format(directory + '/*/'))
+ directories = list(filter(bool, ls.stdout.splitlines()))
+ dirs = directories
+ for dirval in directories:
+ dir_rec = get_directories_recursive(host, dirval)
+ if isinstance(dir_rec, str):
+ dirs.extend([dir_rec])
+ else:
+ dirs.extend(dir_rec)
+ return dirs
+
+
+def test_installPihole_fresh_install_readableFiles(host):
+ '''
+ confirms all neccessary files are readable by pihole user
+ '''
+ # Whiptail dialog returns Cancel for user prompt
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ # mock git pull
+ mock_command_passthrough('git', {'pull': ('', '0')}, host)
+ # mock systemctl to not start lighttpd and FTL
+ mock_command_2(
+ 'systemctl',
+ {
+ 'enable lighttpd': (
+ '',
+ '0'
+ ),
+ 'restart lighttpd': (
+ '',
+ '0'
+ ),
+ 'start lighttpd': (
+ '',
+ '0'
+ ),
+ 'enable pihole-FTL': (
+ '',
+ '0'
+ ),
+ 'restart pihole-FTL': (
+ '',
+ '0'
+ ),
+ 'start pihole-FTL': (
+ '',
+ '0'
+ ),
+ '*': (
+ 'echo "systemctl call with $@"',
+ '0'
+ ),
+ },
+ host
+ )
+ # try to install man
+ host.run('command -v apt-get > /dev/null && apt-get install -qq man')
+ host.run('command -v dnf > /dev/null && dnf install -y man')
+ host.run('command -v yum > /dev/null && yum install -y man')
+ # create configuration file
+ setup_var_file = 'cat < /etc/pihole/setupVars.conf\n'
+ for k, v in SETUPVARS.items():
+ setup_var_file += "{}={}\n".format(k, v)
+ setup_var_file += "INSTALL_WEB_SERVER=true\n"
+ setup_var_file += "INSTALL_WEB_INTERFACE=true\n"
+ setup_var_file += "EOF\n"
+ host.run(setup_var_file)
+ install = host.run('''
+ export TERM=xterm
+ export DEBIAN_FRONTEND=noninteractive
+ umask 0027
+ runUnattended=true
+ useUpdateVars=true
+ source /opt/pihole/basic-install.sh > /dev/null
+ runUnattended=true
+ useUpdateVars=true
+ main
+ ''')
+ assert 0 == install.rc
+ maninstalled = True
+ if (info_box + ' man not installed') in install.stdout:
+ maninstalled = False
+ piholeuser = 'pihole'
+ exit_status_success = 0
+ test_cmd = 'su --shell /bin/bash --command "test -{0} {1}" -p {2}'
+ # check files in /etc/pihole for read, write and execute permission
+ check_etc = test_cmd.format('r', '/etc/pihole', piholeuser)
+ actual_rc = host.run(check_etc).rc
+ assert exit_status_success == actual_rc
+ check_etc = test_cmd.format('x', '/etc/pihole', piholeuser)
+ actual_rc = host.run(check_etc).rc
+ assert exit_status_success == actual_rc
+ # readable and writable dhcp.leases
+ check_leases = test_cmd.format('r', '/etc/pihole/dhcp.leases', piholeuser)
+ actual_rc = host.run(check_leases).rc
+ assert exit_status_success == actual_rc
+ check_leases = test_cmd.format('w', '/etc/pihole/dhcp.leases', piholeuser)
+ actual_rc = host.run(check_leases).rc
+ # readable dns-servers.conf
+ assert exit_status_success == actual_rc
+ check_servers = test_cmd.format(
+ 'r', '/etc/pihole/dns-servers.conf', piholeuser)
+ actual_rc = host.run(check_servers).rc
+ assert exit_status_success == actual_rc
+ # readable GitHubVersions
+ check_version = test_cmd.format(
+ 'r', '/etc/pihole/GitHubVersions', piholeuser)
+ actual_rc = host.run(check_version).rc
+ assert exit_status_success == actual_rc
+ # readable install.log
+ check_install = test_cmd.format(
+ 'r', '/etc/pihole/install.log', piholeuser)
+ actual_rc = host.run(check_install).rc
+ assert exit_status_success == actual_rc
+ # readable localbranches
+ check_localbranch = test_cmd.format(
+ 'r', '/etc/pihole/localbranches', piholeuser)
+ actual_rc = host.run(check_localbranch).rc
+ assert exit_status_success == actual_rc
+ # readable localversions
+ check_localversion = test_cmd.format(
+ 'r', '/etc/pihole/localversions', piholeuser)
+ actual_rc = host.run(check_localversion).rc
+ assert exit_status_success == actual_rc
+ # readable logrotate
+ check_logrotate = test_cmd.format(
+ 'r', '/etc/pihole/logrotate', piholeuser)
+ actual_rc = host.run(check_logrotate).rc
+ assert exit_status_success == actual_rc
+ # readable macvendor.db
+ check_macvendor = test_cmd.format(
+ 'r', '/etc/pihole/macvendor.db', piholeuser)
+ actual_rc = host.run(check_macvendor).rc
+ assert exit_status_success == actual_rc
+ # readable and writeable pihole-FTL.conf
+ check_FTLconf = test_cmd.format(
+ 'r', '/etc/pihole/pihole-FTL.conf', piholeuser)
+ actual_rc = host.run(check_FTLconf).rc
+ assert exit_status_success == actual_rc
+ check_FTLconf = test_cmd.format(
+ 'w', '/etc/pihole/pihole-FTL.conf', piholeuser)
+ actual_rc = host.run(check_FTLconf).rc
+ assert exit_status_success == actual_rc
+ # readable setupVars.conf
+ check_setup = test_cmd.format(
+ 'r', '/etc/pihole/setupVars.conf', piholeuser)
+ actual_rc = host.run(check_setup).rc
+ assert exit_status_success == actual_rc
+ # check dnsmasq files
+ # readable /etc/dnsmasq.conf
+ check_dnsmasqconf = test_cmd.format(
+ 'r', '/etc/dnsmasq.conf', piholeuser)
+ actual_rc = host.run(check_dnsmasqconf).rc
+ assert exit_status_success == actual_rc
+ # readable /etc/dnsmasq.d/01-pihole.conf
+ check_dnsmasqconf = test_cmd.format(
+ 'r', '/etc/dnsmasq.d', piholeuser)
+ actual_rc = host.run(check_dnsmasqconf).rc
+ assert exit_status_success == actual_rc
+ check_dnsmasqconf = test_cmd.format(
+ 'x', '/etc/dnsmasq.d', piholeuser)
+ actual_rc = host.run(check_dnsmasqconf).rc
+ assert exit_status_success == actual_rc
+ check_dnsmasqconf = test_cmd.format(
+ 'r', '/etc/dnsmasq.d/01-pihole.conf', piholeuser)
+ actual_rc = host.run(check_dnsmasqconf).rc
+ assert exit_status_success == actual_rc
+ # check readable and executable /etc/init.d/pihole-FTL
+ check_init = test_cmd.format(
+ 'x', '/etc/init.d/pihole-FTL', piholeuser)
+ actual_rc = host.run(check_init).rc
+ assert exit_status_success == actual_rc
+ check_init = test_cmd.format(
+ 'r', '/etc/init.d/pihole-FTL', piholeuser)
+ actual_rc = host.run(check_init).rc
+ assert exit_status_success == actual_rc
+ # check readable /etc/lighttpd/lighttpd.conf
+ check_lighttpd = test_cmd.format(
+ 'r', '/etc/lighttpd/lighttpd.conf', piholeuser)
+ actual_rc = host.run(check_lighttpd).rc
+ assert exit_status_success == actual_rc
+ # check readable and executable manpages
+ if maninstalled is True:
+ check_man = test_cmd.format(
+ 'x', '/usr/local/share/man', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'x', '/usr/local/share/man/man8', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man/man8', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'x', '/usr/local/share/man/man5', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man/man5', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man/man8/pihole.8', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man/man8/pihole-FTL.8', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ check_man = test_cmd.format(
+ 'r', '/usr/local/share/man/man5/pihole-FTL.conf.5', piholeuser)
+ actual_rc = host.run(check_man).rc
+ assert exit_status_success == actual_rc
+ # check not readable sudoers file
+ check_sudo = test_cmd.format(
+ 'r', '/etc/sudoers.d/pihole', piholeuser)
+ actual_rc = host.run(check_sudo).rc
+ assert exit_status_success != actual_rc
+ # check not readable cron file
+ check_sudo = test_cmd.format(
+ 'x', '/etc/cron.d/', piholeuser)
+ actual_rc = host.run(check_sudo).rc
+ assert exit_status_success == actual_rc
+ check_sudo = test_cmd.format(
+ 'r', '/etc/cron.d/', piholeuser)
+ actual_rc = host.run(check_sudo).rc
+ assert exit_status_success == actual_rc
+ check_sudo = test_cmd.format(
+ 'r', '/etc/cron.d/pihole', piholeuser)
+ actual_rc = host.run(check_sudo).rc
+ assert exit_status_success == actual_rc
+ directories = get_directories_recursive(host, '/etc/.pihole/')
+ for directory in directories:
+ check_pihole = test_cmd.format('r', directory, piholeuser)
+ actual_rc = host.run(check_pihole).rc
+ check_pihole = test_cmd.format('x', directory, piholeuser)
+ actual_rc = host.run(check_pihole).rc
+ findfiles = 'find "{}" -maxdepth 1 -type f -exec echo {{}} \\;;'
+ filelist = host.run(findfiles.format(directory))
+ files = list(filter(bool, filelist.stdout.splitlines()))
+ for file in files:
+ check_pihole = test_cmd.format('r', file, piholeuser)
+ actual_rc = host.run(check_pihole).rc
+
+
+@pytest.mark.parametrize("test_webpage", [True])
+def test_installPihole_fresh_install_readableBlockpage(host, test_webpage):
+ '''
+ confirms all web page assets from Core repo are readable
+ by $LIGHTTPD_USER on a fresh build
+ '''
+ piholeWebpage = [
+ "127.0.0.1",
+ # "pi.hole"
+ ]
+ # Whiptail dialog returns Cancel for user prompt
+ mock_command('whiptail', {'*': ('', '0')}, host)
+
+ # mock git pull
+ mock_command_passthrough('git', {'pull': ('', '0')}, host)
+ # mock systemctl to start lighttpd and FTL
+ ligthttpdcommand = dedent(r'''\"\"
+ echo 'starting lighttpd with {}'
+ if [ command -v "apt-get" >/dev/null 2>&1 ]; then
+ LIGHTTPD_USER="www-data"
+ LIGHTTPD_GROUP="www-data"
+ else
+ LIGHTTPD_USER="lighttpd"
+ LIGHTTPD_GROUP="lighttpd"
+ fi
+ mkdir -p "{run}"
+ chown {usergroup} "{run}"
+ mkdir -p "{cache}"
+ chown {usergroup} "/var/cache"
+ chown {usergroup} "{cache}"
+ mkdir -p "{compress}"
+ chown {usergroup} "{compress}"
+ mkdir -p "{uploads}"
+ chown {usergroup} "{uploads}"
+ chmod 0777 /var
+ chmod 0777 /var/cache
+ chmod 0777 "{cache}"
+ find "{run}" -type d -exec chmod 0777 {chmodarg} \;;
+ find "{run}" -type f -exec chmod 0666 {chmodarg} \;;
+ find "{compress}" -type d -exec chmod 0777 {chmodarg} \;;
+ find "{compress}" -type f -exec chmod 0666 {chmodarg} \;;
+ find "{uploads}" -type d -exec chmod 0777 {chmodarg} \;;
+ find "{uploads}" -type f -exec chmod 0666 {chmodarg} \;;
+ /usr/sbin/lighttpd -tt -f '{config}'
+ /usr/sbin/lighttpd -f '{config}'
+ echo \"\"'''.format(
+ '{}',
+ usergroup='${{LIGHTTPD_USER}}:${{LIGHTTPD_GROUP}}',
+ chmodarg='{{}}',
+ config='/etc/lighttpd/lighttpd.conf',
+ run='/var/run/lighttpd',
+ cache='/var/cache/lighttpd',
+ uploads='/var/cache/lighttpd/uploads',
+ compress='/var/cache/lighttpd/compress'
+ )
+ )
+ FTLcommand = dedent('''\"\"
+ set -x
+ /etc/init.d/pihole-FTL restart
+ echo \"\"''')
+ mock_command_run(
+ 'systemctl',
+ {
+ 'enable lighttpd': (
+ '',
+ '0'
+ ),
+ 'restart lighttpd': (
+ ligthttpdcommand.format('restart'),
+ '0'
+ ),
+ 'start lighttpd': (
+ ligthttpdcommand.format('start'),
+ '0'
+ ),
+ 'enable pihole-FTL': (
+ '',
+ '0'
+ ),
+ 'restart pihole-FTL': (
+ FTLcommand,
+ '0'
+ ),
+ 'start pihole-FTL': (
+ FTLcommand,
+ '0'
+ ),
+ '*': (
+ 'echo "systemctl call with $@"',
+ '0'
+ ),
+ },
+ host
+ )
+ # create configuration file
+ setup_var_file = 'cat < /etc/pihole/setupVars.conf\n'
+ for k, v in SETUPVARS.items():
+ setup_var_file += "{}={}\n".format(k, v)
+ setup_var_file += "INSTALL_WEB_SERVER=true\n"
+ setup_var_file += "INSTALL_WEB_INTERFACE=true\n"
+ setup_var_file += "IPV4_ADDRESS=127.0.0.1\n"
+ setup_var_file += "EOF\n"
+ host.run(setup_var_file)
+ installWeb = host.run('''
+ export TERM=xterm
+ export DEBIAN_FRONTEND=noninteractive
+ umask 0027
+ runUnattended=true
+ useUpdateVars=true
+ source /opt/pihole/basic-install.sh > /dev/null
+ runUnattended=true
+ useUpdateVars=true
+ main
+ echo "LIGHTTPD_USER=${LIGHTTPD_USER}"
+ echo "webroot=${webroot}"
+ echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}"
+ echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}"
+ ''')
+ assert 0 == installWeb.rc
+ piholeuser = 'pihole'
+ webuser = ''
+ user = re.findall(
+ r"^\s*LIGHTTPD_USER=.*$", installWeb.stdout, re.MULTILINE)
+ for match in user:
+ webuser = match.replace('LIGHTTPD_USER=', '').strip()
+ webroot = ''
+ user = re.findall(
+ r"^\s*webroot=.*$", installWeb.stdout, re.MULTILINE)
+ for match in user:
+ webroot = match.replace('webroot=', '').strip()
+ if not webroot.strip():
+ webroot = '/var/www/html'
+ installWebInterface = True
+ interface = re.findall(
+ r"^\s*INSTALL_WEB_INTERFACE=.*$", installWeb.stdout, re.MULTILINE)
+ for match in interface:
+ testvalue = match.replace('INSTALL_WEB_INTERFACE=', '').strip().lower()
+ if not testvalue.strip():
+ installWebInterface = testvalue == "true"
+ installWebServer = True
+ server = re.findall(
+ r"^\s*INSTALL_WEB_SERVER=.*$", installWeb.stdout, re.MULTILINE)
+ for match in server:
+ testvalue = match.replace('INSTALL_WEB_SERVER=', '').strip().lower()
+ if not testvalue.strip():
+ installWebServer = testvalue == "true"
+ # if webserver install was not requested
+ # at least pihole must be able to read files
+ if installWebServer is False:
+ webuser = piholeuser
+ exit_status_success = 0
+ test_cmd = 'su --shell /bin/bash --command "test -{0} {1}" -p {2}'
+ # check files that need a running FTL to be created
+ # readable and writeable pihole-FTL.db
+ check_FTLconf = test_cmd.format(
+ 'r', '/etc/pihole/pihole-FTL.db', piholeuser)
+ actual_rc = host.run(check_FTLconf).rc
+ assert exit_status_success == actual_rc
+ check_FTLconf = test_cmd.format(
+ 'w', '/etc/pihole/pihole-FTL.db', piholeuser)
+ actual_rc = host.run(check_FTLconf).rc
+ assert exit_status_success == actual_rc
+ # check directories above $webroot for read and execute permission
+ check_var = test_cmd.format('r', '/var', webuser)
+ actual_rc = host.run(check_var).rc
+ assert exit_status_success == actual_rc
+ check_var = test_cmd.format('x', '/var', webuser)
+ actual_rc = host.run(check_var).rc
+ assert exit_status_success == actual_rc
+ check_www = test_cmd.format('r', '/var/www', webuser)
+ actual_rc = host.run(check_www).rc
+ assert exit_status_success == actual_rc
+ check_www = test_cmd.format('x', '/var/www', webuser)
+ actual_rc = host.run(check_www).rc
+ assert exit_status_success == actual_rc
+ check_html = test_cmd.format('r', '/var/www/html', webuser)
+ actual_rc = host.run(check_html).rc
+ assert exit_status_success == actual_rc
+ check_html = test_cmd.format('x', '/var/www/html', webuser)
+ actual_rc = host.run(check_html).rc
+ assert exit_status_success == actual_rc
+ # check directories below $webroot for read and execute permission
+ check_admin = test_cmd.format('r', webroot + '/admin', webuser)
+ actual_rc = host.run(check_admin).rc
+ assert exit_status_success == actual_rc
+ check_admin = test_cmd.format('x', webroot + '/admin', webuser)
+ actual_rc = host.run(check_admin).rc
+ assert exit_status_success == actual_rc
+ directories = get_directories_recursive(host, webroot + '/admin/*/')
+ for directory in directories:
+ check_pihole = test_cmd.format('r', directory, webuser)
+ actual_rc = host.run(check_pihole).rc
+ check_pihole = test_cmd.format('x', directory, webuser)
+ actual_rc = host.run(check_pihole).rc
+ findfiles = 'find "{}" -maxdepth 1 -type f -exec echo {{}} \\;;'
+ filelist = host.run(findfiles.format(directory))
+ files = list(filter(bool, filelist.stdout.splitlines()))
+ for file in files:
+ check_pihole = test_cmd.format('r', file, webuser)
+ actual_rc = host.run(check_pihole).rc
+ # check web interface files
+ # change nameserver to pi-hole
+ # setting nameserver in /etc/resolv.conf to pi-hole does
+ # not work here because of the way docker uses this file
+ ns = host.run(
+ r"sed -i 's/nameserver.*/nameserver 127.0.0.1/' /etc/resolv.conf")
+ pihole_is_ns = ns.rc == 0
+
+ def is_ip(address):
+ m = re.match(r"(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})", address)
+ return bool(m)
+ if installWebInterface is True:
+ check_pihole = test_cmd.format('r', webroot + '/pihole', webuser)
+ actual_rc = host.run(check_pihole).rc
+ assert exit_status_success == actual_rc
+ check_pihole = test_cmd.format('x', webroot + '/pihole', webuser)
+ actual_rc = host.run(check_pihole).rc
+ assert exit_status_success == actual_rc
+ # check most important files in $webroot for read permission
+ check_index = test_cmd.format(
+ 'r', webroot + '/pihole/index.php', webuser)
+ actual_rc = host.run(check_index).rc
+ assert exit_status_success == actual_rc
+ check_blockpage = test_cmd.format(
+ 'r', webroot + '/pihole/blockingpage.css', webuser)
+ actual_rc = host.run(check_blockpage).rc
+ assert exit_status_success == actual_rc
+ if test_webpage is True:
+ # check webpage for unreadable files
+ noPHPfopen = re.compile(
+ (r"PHP Error(%d+):\s+fopen([^)]+):\s+" +
+ r"failed to open stream: " +
+ r"Permission denied in"),
+ re.I)
+ # using cURL option --dns-servers is not possible
+ status = (
+ 'curl -s --head "{}" | ' +
+ 'head -n 1 | ' +
+ 'grep "HTTP/1.[01] [23].." > /dev/null')
+ digcommand = r"dig A +short {} @127.0.0.1 | head -n 1"
+ pagecontent = 'curl --verbose -L "{}"'
+ for page in piholeWebpage:
+ testpage = "http://" + page + "/admin/"
+ resolvesuccess = True
+ if is_ip(page) is False:
+ dig = host.run(digcommand.format(page))
+ testpage = "http://" + dig.stdout.strip() + "/admin/"
+ resolvesuccess = dig.rc == 0
+ if resolvesuccess or pihole_is_ns:
+ # check HTTP status of blockpage
+ actual_rc = host.run(status.format(testpage))
+ assert exit_status_success == actual_rc.rc
+ # check for PHP error
+ actual_output = host.run(pagecontent.format(testpage))
+ assert noPHPfopen.match(actual_output.stdout) is None
+
+
+def test_update_package_cache_success_no_errors(host):
'''
confirms package cache was updated without any errors
'''
- updateCache = Pihole.run('''
+ updateCache = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
@@ -143,12 +658,12 @@ def test_update_package_cache_success_no_errors(Pihole):
assert 'error' not in updateCache.stdout.lower()
-def test_update_package_cache_failure_no_errors(Pihole):
+def test_update_package_cache_failure_no_errors(host):
'''
confirms package cache was not updated
'''
- mock_command('apt-get', {'update': ('', '1')}, Pihole)
- updateCache = Pihole.run('''
+ mock_command('apt-get', {'update': ('', '1')}, host)
+ updateCache = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
update_package_cache
@@ -158,12 +673,12 @@ def test_update_package_cache_failure_no_errors(Pihole):
assert 'Error: Unable to update package cache.' in updateCache.stdout
-def test_FTL_detect_aarch64_no_errors(Pihole):
+def test_FTL_detect_aarch64_no_errors(host):
'''
confirms only aarch64 package is downloaded for FTL engine
'''
# mock uname to return aarch64 platform
- mock_command('uname', {'-m': ('aarch64', '0')}, Pihole)
+ mock_command('uname', {'-m': ('aarch64', '0')}, host)
# mock ldd to respond with aarch64 shared library
mock_command(
'ldd',
@@ -173,9 +688,9 @@ def test_FTL_detect_aarch64_no_errors(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -191,15 +706,15 @@ def test_FTL_detect_aarch64_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_armv4t_no_errors(Pihole):
+def test_FTL_detect_armv4t_no_errors(host):
'''
confirms only armv4t package is downloaded for FTL engine
'''
# mock uname to return armv4t platform
- mock_command('uname', {'-m': ('armv4t', '0')}, Pihole)
+ mock_command('uname', {'-m': ('armv4t', '0')}, host)
# mock ldd to respond with ld-linux shared library
- mock_command('ldd', {'/bin/ls': ('/lib/ld-linux.so.3', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('ldd', {'/bin/ls': ('/lib/ld-linux.so.3', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -215,15 +730,15 @@ def test_FTL_detect_armv4t_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_armv5te_no_errors(Pihole):
+def test_FTL_detect_armv5te_no_errors(host):
'''
confirms only armv5te package is downloaded for FTL engine
'''
# mock uname to return armv5te platform
- mock_command('uname', {'-m': ('armv5te', '0')}, Pihole)
+ mock_command('uname', {'-m': ('armv5te', '0')}, host)
# mock ldd to respond with ld-linux shared library
- mock_command('ldd', {'/bin/ls': ('/lib/ld-linux.so.3', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('ldd', {'/bin/ls': ('/lib/ld-linux.so.3', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -239,15 +754,15 @@ def test_FTL_detect_armv5te_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_armv6l_no_errors(Pihole):
+def test_FTL_detect_armv6l_no_errors(host):
'''
confirms only armv6l package is downloaded for FTL engine
'''
# mock uname to return armv6l platform
- mock_command('uname', {'-m': ('armv6l', '0')}, Pihole)
+ mock_command('uname', {'-m': ('armv6l', '0')}, host)
# mock ldd to respond with ld-linux-armhf shared library
- mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -264,15 +779,15 @@ def test_FTL_detect_armv6l_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_armv7l_no_errors(Pihole):
+def test_FTL_detect_armv7l_no_errors(host):
'''
confirms only armv7l package is downloaded for FTL engine
'''
# mock uname to return armv7l platform
- mock_command('uname', {'-m': ('armv7l', '0')}, Pihole)
+ mock_command('uname', {'-m': ('armv7l', '0')}, host)
# mock ldd to respond with ld-linux-armhf shared library
- mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -289,15 +804,15 @@ def test_FTL_detect_armv7l_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_armv8a_no_errors(Pihole):
+def test_FTL_detect_armv8a_no_errors(host):
'''
confirms only armv8a package is downloaded for FTL engine
'''
# mock uname to return armv8a platform
- mock_command('uname', {'-m': ('armv8a', '0')}, Pihole)
+ mock_command('uname', {'-m': ('armv8a', '0')}, host)
# mock ldd to respond with ld-linux-armhf shared library
- mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -313,11 +828,11 @@ def test_FTL_detect_armv8a_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_x86_64_no_errors(Pihole):
+def test_FTL_detect_x86_64_no_errors(host):
'''
confirms only x86_64 package is downloaded for FTL engine
'''
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -333,11 +848,11 @@ def test_FTL_detect_x86_64_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_detect_unknown_no_errors(Pihole):
+def test_FTL_detect_unknown_no_errors(host):
''' confirms only generic package is downloaded for FTL engine '''
# mock uname to return generic platform
- mock_command('uname', {'-m': ('mips', '0')}, Pihole)
- detectPlatform = Pihole.run('''
+ mock_command('uname', {'-m': ('mips', '0')}, host)
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -349,18 +864,18 @@ def test_FTL_detect_unknown_no_errors(Pihole):
assert expected_stdout in detectPlatform.stdout
-def test_FTL_download_aarch64_no_errors(Pihole):
+def test_FTL_download_aarch64_no_errors(host):
'''
confirms only aarch64 package is downloaded for FTL engine
'''
# mock whiptail answers and ensure installer dependencies
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${INSTALLER_DEPS[@]}
''')
- download_binary = Pihole.run('''
+ download_binary = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
FTLinstall "pihole-FTL-aarch64-linux-gnu"
@@ -370,11 +885,11 @@ def test_FTL_download_aarch64_no_errors(Pihole):
assert 'error' not in download_binary.stdout.lower()
-def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
+def test_FTL_binary_installed_and_responsive_no_errors(host):
'''
confirms FTL binary is copied and functional in installed location
'''
- installed_binary = Pihole.run('''
+ installed_binary = host.run('''
source /opt/pihole/basic-install.sh
create_pihole_user
funcOutput=$(get_binary_name)
@@ -387,11 +902,11 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
assert expected_stdout in installed_binary.stdout
-# def test_FTL_support_files_installed(Pihole):
+# def test_FTL_support_files_installed(host):
# '''
# confirms FTL support files are installed
# '''
-# support_files = Pihole.run('''
+# support_files = host.run('''
# source /opt/pihole/basic-install.sh
# FTLdetect
# stat -c '%a %n' /var/log/pihole-FTL.log
@@ -404,7 +919,7 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
# assert '644 /var/log/pihole-FTL.log' in support_files.stdout
-def test_IPv6_only_link_local(Pihole):
+def test_IPv6_only_link_local(host):
'''
confirms IPv6 blocking is disabled for Link-local address
'''
@@ -417,18 +932,17 @@ def test_IPv6_only_link_local(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
- useIPv6dialog
+ find_IPv6_information
''')
- expected_stdout = ('Unable to find IPv6 ULA/GUA address, '
- 'IPv6 adblocking will not be enabled')
+ expected_stdout = ('Unable to find IPv6 ULA/GUA address')
assert expected_stdout in detectPlatform.stdout
-def test_IPv6_only_ULA(Pihole):
+def test_IPv6_only_ULA(host):
'''
confirms IPv6 blocking is enabled for ULA addresses
'''
@@ -441,17 +955,17 @@ def test_IPv6_only_ULA(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
- useIPv6dialog
+ find_IPv6_information
''')
- expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
+ expected_stdout = 'Found IPv6 ULA address'
assert expected_stdout in detectPlatform.stdout
-def test_IPv6_only_GUA(Pihole):
+def test_IPv6_only_GUA(host):
'''
confirms IPv6 blocking is enabled for GUA addresses
'''
@@ -464,17 +978,17 @@ def test_IPv6_only_GUA(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
- useIPv6dialog
+ find_IPv6_information
''')
- expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
+ expected_stdout = 'Found IPv6 GUA address'
assert expected_stdout in detectPlatform.stdout
-def test_IPv6_GUA_ULA_test(Pihole):
+def test_IPv6_GUA_ULA_test(host):
'''
confirms IPv6 blocking is enabled for GUA and ULA addresses
'''
@@ -488,17 +1002,17 @@ def test_IPv6_GUA_ULA_test(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
- useIPv6dialog
+ find_IPv6_information
''')
- expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
+ expected_stdout = 'Found IPv6 ULA address'
assert expected_stdout in detectPlatform.stdout
-def test_IPv6_ULA_GUA_test(Pihole):
+def test_IPv6_ULA_GUA_test(host):
'''
confirms IPv6 blocking is enabled for GUA and ULA addresses
'''
@@ -512,23 +1026,23 @@ def test_IPv6_ULA_GUA_test(Pihole):
'0'
)
},
- Pihole
+ host
)
- detectPlatform = Pihole.run('''
+ detectPlatform = host.run('''
source /opt/pihole/basic-install.sh
- useIPv6dialog
+ find_IPv6_information
''')
- expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
+ expected_stdout = 'Found IPv6 ULA address'
assert expected_stdout in detectPlatform.stdout
-def test_validate_ip(Pihole):
+def test_validate_ip(host):
'''
Tests valid_ip for various IP addresses
'''
def test_address(addr, success=True):
- output = Pihole.run('''
+ output = host.run('''
source /opt/pihole/basic-install.sh
valid_ip "{addr}"
'''.format(addr=addr))
@@ -563,9 +1077,9 @@ def test_validate_ip(Pihole):
test_address('0.0.0.0#00001', False)
-def test_os_check_fails(Pihole):
+def test_os_check_fails(host):
''' Confirms install fails on unsupported OS '''
- Pihole.run('''
+ host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${OS_CHECK_DEPS[@]}
@@ -575,7 +1089,7 @@ def test_os_check_fails(Pihole):
VERSION_ID="2"
EOT
''')
- detectOS = Pihole.run('''t
+ detectOS = host.run('''t
source /opt/pihole/basic-install.sh
os_check
''')
@@ -583,15 +1097,15 @@ def test_os_check_fails(Pihole):
assert expected_stdout in detectOS.stdout
-def test_os_check_passes(Pihole):
+def test_os_check_passes(host):
''' Confirms OS meets the requirements '''
- Pihole.run('''
+ host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${OS_CHECK_DEPS[@]}
install_dependent_packages ${INSTALLER_DEPS[@]}
''')
- detectOS = Pihole.run('''
+ detectOS = host.run('''
source /opt/pihole/basic-install.sh
os_check
''')
@@ -599,10 +1113,10 @@ def test_os_check_passes(Pihole):
assert expected_stdout in detectOS.stdout
-def test_package_manager_has_installer_deps(Pihole):
+def test_package_manager_has_installer_deps(host):
''' Confirms OS is able to install the required packages for the installer'''
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- output = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ output = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${INSTALLER_DEPS[@]}
@@ -612,12 +1126,13 @@ def test_package_manager_has_installer_deps(Pihole):
assert output.rc == 0
-def test_package_manager_has_pihole_deps(Pihole):
+def test_package_manager_has_pihole_deps(host):
''' Confirms OS is able to install the required packages for Pi-hole '''
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- output = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ output = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
install_dependent_packages ${PIHOLE_DEPS[@]}
''')
@@ -625,12 +1140,13 @@ def test_package_manager_has_pihole_deps(Pihole):
assert output.rc == 0
-def test_package_manager_has_web_deps(Pihole):
+def test_package_manager_has_web_deps(host):
''' Confirms OS is able to install the required packages for web '''
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- output = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ output = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
install_dependent_packages ${PIHOLE_WEB_DEPS[@]}
''')
diff --git a/test/test_centos_7_support.py b/test/test_centos_7_support.py
index ed99231a..f72740a6 100644
--- a/test/test_centos_7_support.py
+++ b/test/test_centos_7_support.py
@@ -5,49 +5,52 @@ from .conftest import (
)
-def test_php_upgrade_default_optout_centos_eq_7(Pihole):
+def test_php_upgrade_default_optout_centos_eq_7(host):
'''
confirms the default behavior to opt-out of installing PHP7 from REMI
'''
- package_manager_detect = Pihole.run('''
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_upgrade_user_optout_centos_eq_7(Pihole):
+def test_php_upgrade_user_optout_centos_eq_7(host):
'''
confirms installer behavior when user opt-out of installing PHP7 from REMI
(php not currently installed)
'''
# Whiptail dialog returns Cancel for user prompt
- mock_command('whiptail', {'*': ('', '1')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '1')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_upgrade_user_optin_centos_eq_7(Pihole):
+def test_php_upgrade_user_optin_centos_eq_7(host):
'''
confirms installer behavior when user opt-in to installing PHP7 from REMI
(php not currently installed)
'''
# Whiptail dialog returns Continue for user prompt
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
assert 'opt-out' not in package_manager_detect.stdout
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
@@ -56,5 +59,5 @@ def test_php_upgrade_user_optin_centos_eq_7(Pihole):
expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert remi_package.is_installed
diff --git a/test/test_centos_8_support.py b/test/test_centos_8_support.py
index b8ad9607..464055b4 100644
--- a/test/test_centos_8_support.py
+++ b/test/test_centos_8_support.py
@@ -5,54 +5,57 @@ from .conftest import (
)
-def test_php_upgrade_default_continue_centos_gte_8(Pihole):
+def test_php_upgrade_default_continue_centos_gte_8(host):
'''
confirms the latest version of CentOS continues / does not optout
(should trigger on CentOS7 only)
'''
- package_manager_detect = Pihole.run('''
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
' Deprecated PHP may be in use.')
assert unexpected_stdout not in package_manager_detect.stdout
# ensure remi was not installed on latest CentOS
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_upgrade_user_optout_skipped_centos_gte_8(Pihole):
+def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
'''
confirms installer skips user opt-out of installing PHP7 from REMI on
latest CentOS (should trigger on CentOS7 only)
(php not currently installed)
'''
# Whiptail dialog returns Cancel for user prompt
- mock_command('whiptail', {'*': ('', '1')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '1')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
' Deprecated PHP may be in use.')
assert unexpected_stdout not in package_manager_detect.stdout
# ensure remi was not installed on latest CentOS
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
+def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
'''
confirms installer skips user opt-in to installing PHP7 from REMI on
latest CentOS (should trigger on CentOS7 only)
(php not currently installed)
'''
# Whiptail dialog returns Continue for user prompt
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
assert 'opt-out' not in package_manager_detect.stdout
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
@@ -61,5 +64,5 @@ def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert unexpected_stdout not in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
diff --git a/test/test_centos_common_support.py b/test/test_centos_common_support.py
index 8412173d..8903a7a0 100644
--- a/test/test_centos_common_support.py
+++ b/test/test_centos_common_support.py
@@ -7,15 +7,16 @@ from .conftest import (
)
-def test_release_supported_version_check_centos(Pihole):
+def test_release_supported_version_check_centos(host):
'''
confirms installer exits on unsupported releases of CentOS
'''
# modify /etc/redhat-release to mock an unsupported CentOS release
- Pihole.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
- package_manager_detect = Pihole.run('''
+ host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = cross_box + (' CentOS 6 is not supported.')
assert expected_stdout in package_manager_detect.stdout
@@ -23,85 +24,89 @@ def test_release_supported_version_check_centos(Pihole):
assert expected_stdout in package_manager_detect.stdout
-def test_enable_epel_repository_centos(Pihole):
+def test_enable_epel_repository_centos(host):
'''
confirms the EPEL package repository is enabled when installed on CentOS
'''
- package_manager_detect = Pihole.run('''
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = info_box + (' Enabling EPEL package repository '
'(https://fedoraproject.org/wiki/EPEL)')
assert expected_stdout in package_manager_detect.stdout
expected_stdout = tick_box + ' Installed epel-release'
assert expected_stdout in package_manager_detect.stdout
- epel_package = Pihole.package('epel-release')
+ epel_package = host.package('epel-release')
assert epel_package.is_installed
-def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
+def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
'''
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
'''
# first we will install the default php version to test installer behavior
- php_install = Pihole.run('yum install -y php')
+ php_install = host.run('yum install -y php')
assert php_install.rc == 0
- php_package = Pihole.package('php')
+ php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7")
- package_manager_detect = Pihole.run('''
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
+def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
'''
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
'''
# first we will install the default php version to test installer behavior
- php_install = Pihole.run('yum install -y php')
+ php_install = host.run('yum install -y php')
assert php_install.rc == 0
- php_package = Pihole.package('php')
+ php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7")
# Whiptail dialog returns Cancel for user prompt
- mock_command('whiptail', {'*': ('', '1')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '1')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
-def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
+def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
'''
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
'''
# first we will install the default php version to test installer behavior
- php_install = Pihole.run('yum install -y php')
+ php_install = host.run('yum install -y php')
assert php_install.rc == 0
- php_package = Pihole.package('php')
+ php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7")
# Whiptail dialog returns Continue for user prompt
- mock_command('whiptail', {'*': ('', '0')}, Pihole)
- package_manager_detect = Pihole.run('''
+ mock_command('whiptail', {'*': ('', '0')}, host)
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
install_dependent_packages PIHOLE_WEB_DEPS[@]
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
@@ -113,8 +118,8 @@ def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert remi_package.is_installed
- updated_php_package = Pihole.package('php')
+ updated_php_package = host.package('php')
updated_php_version = updated_php_package.version.split('.')[0]
assert int(updated_php_version) == 7
diff --git a/test/test_centos_fedora_common_support.py b/test/test_centos_fedora_common_support.py
index 21ae6d1d..a2a13048 100644
--- a/test/test_centos_fedora_common_support.py
+++ b/test/test_centos_fedora_common_support.py
@@ -5,7 +5,7 @@ from .conftest import (
)
-def mock_selinux_config(state, Pihole):
+def mock_selinux_config(state, host):
'''
Creates a mock SELinux config file with expected content
'''
@@ -13,20 +13,20 @@ def mock_selinux_config(state, Pihole):
valid_states = ['enforcing', 'permissive', 'disabled']
assert state in valid_states
# getenforce returns the running state of SELinux
- mock_command('getenforce', {'*': (state.capitalize(), '0')}, Pihole)
+ mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
# create mock configuration with desired content
- Pihole.run('''
+ host.run('''
mkdir /etc/selinux
echo "SELINUX={state}" > /etc/selinux/config
'''.format(state=state.lower()))
-def test_selinux_enforcing_exit(Pihole):
+def test_selinux_enforcing_exit(host):
'''
confirms installer prompts to exit when SELinux is Enforcing by default
'''
- mock_selinux_config("enforcing", Pihole)
- check_selinux = Pihole.run('''
+ mock_selinux_config("enforcing", host)
+ check_selinux = host.run('''
source /opt/pihole/basic-install.sh
checkSelinux
''')
@@ -37,12 +37,12 @@ def test_selinux_enforcing_exit(Pihole):
assert check_selinux.rc == 1
-def test_selinux_permissive(Pihole):
+def test_selinux_permissive(host):
'''
confirms installer continues when SELinux is Permissive
'''
- mock_selinux_config("permissive", Pihole)
- check_selinux = Pihole.run('''
+ mock_selinux_config("permissive", host)
+ check_selinux = host.run('''
source /opt/pihole/basic-install.sh
checkSelinux
''')
@@ -51,12 +51,12 @@ def test_selinux_permissive(Pihole):
assert check_selinux.rc == 0
-def test_selinux_disabled(Pihole):
+def test_selinux_disabled(host):
'''
confirms installer continues when SELinux is Disabled
'''
- mock_selinux_config("disabled", Pihole)
- check_selinux = Pihole.run('''
+ mock_selinux_config("disabled", host)
+ check_selinux = host.run('''
source /opt/pihole/basic-install.sh
checkSelinux
''')
diff --git a/test/test_fedora_support.py b/test/test_fedora_support.py
index a2ac4c71..63fde90e 100644
--- a/test/test_fedora_support.py
+++ b/test/test_fedora_support.py
@@ -1,15 +1,16 @@
-def test_epel_and_remi_not_installed_fedora(Pihole):
+def test_epel_and_remi_not_installed_fedora(host):
'''
confirms installer does not attempt to install EPEL/REMI repositories
on Fedora
'''
- package_manager_detect = Pihole.run('''
+ package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
+ select_rpm_php
''')
assert package_manager_detect.stdout == ''
- epel_package = Pihole.package('epel-release')
+ epel_package = host.package('epel-release')
assert not epel_package.is_installed
- remi_package = Pihole.package('remi-release')
+ remi_package = host.package('remi-release')
assert not remi_package.is_installed
diff --git a/test/tox.centos_7.ini b/test/tox.centos_7.ini
index c2752698..88940fdd 100644
--- a/test/tox.centos_7.ini
+++ b/test/tox.centos_7.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.centos_8.ini b/test/tox.centos_8.ini
index c8852bae..5088da16 100644
--- a/test/tox.centos_8.ini
+++ b/test/tox.centos_8.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.debian_10.ini b/test/tox.debian_10.ini
index e8c5d746..9c2a05d1 100644
--- a/test/tox.debian_10.ini
+++ b/test/tox.debian_10.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.debian_11.ini b/test/tox.debian_11.ini
index af3c6e36..f3cdbe84 100644
--- a/test/tox.debian_11.ini
+++ b/test/tox.debian_11.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.debian_9.ini b/test/tox.debian_9.ini
index b33e9927..b46e0a49 100644
--- a/test/tox.debian_9.ini
+++ b/test/tox.debian_9.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.fedora_33.ini b/test/tox.fedora_33.ini
index 00ea732a..d33fbf53 100644
--- a/test/tox.fedora_33.ini
+++ b/test/tox.fedora_33.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.fedora_32.ini b/test/tox.fedora_34.ini
similarity index 74%
rename from test/tox.fedora_32.ini
rename to test/tox.fedora_34.ini
index c68e0757..819291fa 100644
--- a/test/tox.fedora_32.ini
+++ b/test/tox.fedora_34.ini
@@ -1,8 +1,8 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
deps = -rrequirements.txt
-commands = docker build -f _fedora_32.Dockerfile -t pytest_pihole:test_container ../
+commands = docker build -f _fedora_34.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_automated_install.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
diff --git a/test/tox.ubuntu_16.ini b/test/tox.ubuntu_16.ini
index 6f484b6b..bce948a2 100644
--- a/test/tox.ubuntu_16.ini
+++ b/test/tox.ubuntu_16.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.ubuntu_18.ini b/test/tox.ubuntu_18.ini
index 10d4ac09..cf7a3642 100644
--- a/test/tox.ubuntu_18.ini
+++ b/test/tox.ubuntu_18.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.ubuntu_20.ini b/test/tox.ubuntu_20.ini
index 8b405b28..03b605ce 100644
--- a/test/tox.ubuntu_20.ini
+++ b/test/tox.ubuntu_20.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker
diff --git a/test/tox.ubuntu_21.ini b/test/tox.ubuntu_21.ini
index 651f933b..12b1ac0b 100644
--- a/test/tox.ubuntu_21.ini
+++ b/test/tox.ubuntu_21.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py37
+envlist = py38
[testenv]
whitelist_externals = docker