Compare commits

..

1 Commits

Author SHA1 Message Date
Dan Schaper
6ce527010b Initial work on stubbing for lua.
Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
2021-06-21 10:49:46 -07:00
49 changed files with 1436 additions and 856 deletions

View File

@@ -1,10 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: saturday
time: "10:00"
open-pull-requests-limit: 10
target-branch: developement

View File

@@ -1,40 +0,0 @@
name: "CodeQL"
on:
push:
branches:
- master
- development
pull_request:
branches:
- master
- development
schedule:
- cron: '32 11 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
-
name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
-
name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: 'python'
-
name: Autobuild
uses: github/codeql-action/autobuild@v1
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -5,44 +5,21 @@ on:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
smoke-test:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
-
name: Checkout repository
uses: actions/checkout@v2
-
name: Run Smoke Tests
run: |
# Ensure scripts in repository are executable
IFS=$'\n';
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
unset IFS;
# If FAIL is 1 then we fail.
[[ $FAIL == 1 ]] && exit 1 || echo "Smoke Tests Passed"
distro-test:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
needs: smoke-test
strategy:
matrix:
distro: [debian_9, debian_10, debian_11, ubuntu_16, ubuntu_18, ubuntu_20, ubuntu_21, centos_7, centos_8, fedora_32, fedora_33]
distro: [debian_9, debian_10, ubuntu_16, ubuntu_18, ubuntu_20, centos_7, centos_8, fedora_32, fedora_33]
env:
DISTRO: ${{matrix.distro}}
steps:
-
name: Checkout repository
uses: actions/checkout@v2
-
name: Set up Python 3.7
- uses: actions/checkout@v1
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: 3.7
-
name: Install dependencies
- name: Install dependencies
run: pip install -r test/requirements.txt
-
name: Test with tox
- name: Test with tox
run: tox -c test/tox.${DISTRO}.ini

67
.gitignore vendored
View File

@@ -7,5 +7,70 @@ __pycache__
.tox
.eggs
*.egg-info
.idea/
# Created by https://www.gitignore.io/api/jetbrains+iml
### JetBrains+iml ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# All idea files, with exceptions
.idea
!.idea/codeStyles/*
!.idea/codeStyleSettings.xml
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Ruby plugin and RubyMine
/.rakeTasks
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### JetBrains+iml Patch ###
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
.idea/misc.xml
*.ipr
# End of https://www.gitignore.io/api/jetbrains+iml

25
.idea/codeStyleSettings.xml generated Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</value>
</option>
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
</project>

7
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -11,9 +11,9 @@
</p>
<!-- markdownlint-enable MD033 -->
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 that helps ensure _you_ are the sole person in control of your privacy
- **Free**: open source software which 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); 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); just be sure to disable DHCP on your router first (if it has that feature available).
As a last resort, you can manually set each device to use Pi-hole as their DNS server.
As a last resort, you can always 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 and 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, as well as 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)
Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
Sending a donation using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses and rewarding our dedicated development team:
### 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 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 that 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 various social media outlets.
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.
**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.
**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.
- [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
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 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).
### The Command Line Interface
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`.
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`.
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

View File

@@ -39,4 +39,6 @@ cache-size=@CACHE_SIZE@
log-queries
log-facility=/var/log/pihole.log
local-ttl=2
log-async

View File

@@ -1,41 +0,0 @@
# 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
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 27.172.in-addr.arpa.
# 17.172.in-addr.arpa. 30.172.in-addr.arpa. 28.172.in-addr.arpa.
# 18.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
# 19.172.in-addr.arpa. 24.172.in-addr.arpa. 31.172.in-addr.arpa.
# 20.172.in-addr.arpa. 25.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/

View File

@@ -498,6 +498,10 @@ chronoFunc() {
printFunc " RAM usage: " "$ram_perc%" "$ram_info"
printFunc " HDD usage: " "$disk_perc" "$disk_info"
if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then
printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info"
fi
if [[ "$DHCP_ACTIVE" == "true" ]]; then
printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
fi

0
advanced/Scripts/database_migration/gravity-db.sh Executable file → Normal file
View File

View File

@@ -23,7 +23,7 @@ fi
# have changed
gravityDBfile="${GRAVITYDB}"
noReloadRequested=false
reload=false
addmode=true
verbose=true
wildcard=false
@@ -35,7 +35,6 @@ typeId=""
comment=""
declare -i domaincount
domaincount=0
reload=false
colfile="/opt/pihole/COL_TABLE"
source ${colfile}
@@ -243,13 +242,13 @@ 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;
}
@@ -269,7 +268,7 @@ while (( "$#" )); do
"--white-wild" | "white-wild" ) typeId=2; wildcard=true;;
"--wild" | "wildcard" ) typeId=3; wildcard=true;;
"--regex" | "regex" ) typeId=3;;
"-nr"| "--noreload" ) noReloadRequested=true;;
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
@@ -295,6 +294,6 @@ if $web; then
echo "DONE"
fi
if [[ ${reload} == true && ${noReloadRequested} == false ]]; then
if [[ "${reload}" != false ]]; then
pihole restartdns reload-lists
fi

3
advanced/Scripts/piholeCheckout.sh Executable file → Normal file
View File

@@ -166,15 +166,12 @@ checkout() {
checkout_pull_branch "${webInterfaceDir}" "${2}"
elif [[ "${1}" == "ftl" ]] ; then
local path
local oldbranch
path="${2}/${binary}"
oldbranch="$(pihole-FTL -b)"
if check_download_exists "$path"; then
echo " ${TICK} Branch ${2} exists"
echo "${2}" > /etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch
echo -e " ${INFO} Switching to branch: \"${2}\" from \"${oldbranch}\""
FTLinstall "${binary}"
restart_service pihole-FTL
enable_service pihole-FTL

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# (c) 2021 Pi-hole (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Generates pihole_debug.log to be used for troubleshooting.
@@ -56,6 +56,11 @@ FAQ_BAD_ADDRESS="${COL_CYAN}https://discourse.pi-hole.net/t/why-do-i-see-bad-add
# Other URLs we may use
FORUMS_URL="${COL_CYAN}https://discourse.pi-hole.net${COL_NC}"
TRICORDER_CONTEST="${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}"
# Port numbers used for uploading the debug log
TRICORDER_NC_PORT_NUMBER=9999
TRICORDER_SSL_PORT_NUMBER=9998
# Directories required by Pi-hole
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
@@ -73,12 +78,15 @@ 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"
@@ -133,9 +141,6 @@ 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,6 +165,9 @@ 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}"
@@ -177,9 +185,7 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
"${PIHOLE_DEBUG_LOG}"
"${PIHOLE_FTL_LOG}"
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
"${RESOLVCONF}"
"${DNSMASQ_CONF}")
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}")
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
@@ -192,6 +198,33 @@ show_disclaimer(){
log_write "${DISCLAIMER}"
}
check_for_ftl(){
echo_current_diagnostic "Checking for pihole-FTL binary"
declare -g FTL_PATH
read -r FTL_PATH < <(which pihole-FTL)
if [ -z "${FTL_PATH}" ]; then
log_write "${CROSS} ${COL_RED} Unable to find pihole-FTL binary.${COL_NC}"
# Non-zero return value
return 2
else
log_write "${TICK} pihole-FTL: ${COL_GREEN}${FTL_PATH}${COL_NC}"
fi
}
check_for_lua(){
echo_current_diagnostic "Checking for lua capabilities"
if ! (${FTL_PATH} lua -v &>/dev/null); then
log_write "${CROSS} ${COL_RED} pihole-FTL binary does not have lua capabilites.${COL_NC}"
# Non-zero return value
return
else
log_write "${TICK} pihole-FTL: ${COL_GREEN}lua found!${COL_NC}"
fi
}
source_setup_variables() {
# Display the current test that is running
log_write "\\n${COL_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables"
@@ -229,7 +262,6 @@ copy_to_debug_log() {
}
initialize_debug() {
local system_uptime
# Clear the screen so the debug log is readable
clear
show_disclaimer
@@ -237,10 +269,6 @@ initialize_debug() {
log_write "${COL_PURPLE}*** [ INITIALIZING ]${COL_NC}"
# Timestamp the start of the log
log_write "${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initialized."
# Uptime of the system
# credits to https://stackoverflow.com/questions/28353409/bash-format-uptime-to-show-days-hours-minutes
system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}')
log_write "${INFO} System has been running for ${system_uptime}"
}
# This is a function for visually displaying the current test that is being run.
@@ -409,12 +437,12 @@ os_check() {
# This function gets a list of supported OS versions from a TXT record at versions.pi-hole.net
# and determines whether or not the script is running on one of those systems
local remote_os_domain valid_os valid_version detected_os detected_version cmdResult digReturnCode response
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
remote_os_domain="versions.pi-hole.net"
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
cmdResult="$(dig +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
cmdResult="$(dig +short -t txt ${remote_os_domain} @ns1.pi-hole.net 2>&1; echo $?)"
#Get the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
@@ -604,6 +632,38 @@ parse_locale() {
parse_file "${pihole_locale}"
}
does_ip_match_setup_vars() {
# Check for IPv4 or 6
local protocol="${1}"
# IP address to check for
local ip_address="${2}"
# See what IP is in the setupVars.conf file
local setup_vars_ip
setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} grep IPV"${protocol}"_ADDRESS | cut -d '=' -f2)
# If it's an IPv6 address
if [[ "${protocol}" == "6" ]]; then
# Strip off the / (CIDR notation)
if [[ "${ip_address%/*}" == "${setup_vars_ip%/*}" ]]; then
# if it matches, show it in green
log_write " ${COL_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
else
# otherwise show it in red with an FAQ URL
log_write " ${COL_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
fi
else
# if the protocol isn't 6, it's 4 so no need to strip the CIDR notation
# since it exists in the setupVars.conf that way
if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then
# show in green if it matches
log_write " ${COL_GREEN}${ip_address}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
else
# otherwise show it in red
log_write " ${COL_RED}${ip_address}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
fi
fi
}
detect_ip_addresses() {
# First argument should be a 4 or a 6
local protocol=${1}
@@ -620,7 +680,8 @@ detect_ip_addresses() {
log_write "${TICK} IPv${protocol} address(es) bound to the ${PIHOLE_INTERFACE} interface:"
# Since there may be more than one IP address, store them in an array
for i in "${!ip_addr_list[@]}"; do
log_write " ${ip_addr_list[$i]}"
# For each one in the list, print it out
does_ip_match_setup_vars "${protocol}" "${ip_addr_list[$i]}"
done
# Print a blank line just for formatting
log_write ""
@@ -629,6 +690,13 @@ detect_ip_addresses() {
log_write "${CROSS} ${COL_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interface.\\n"
return 1
fi
# If the protocol is v6
if [[ "${protocol}" == "6" ]]; then
# let the user know that as long as there is one green address, things should be ok
log_write " ^ Please note that you may have more than one IP address listed."
log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\\n"
log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\\n"
fi
}
ping_ipv4_or_ipv6() {
@@ -777,14 +845,30 @@ check_x_headers() {
# server is operating correctly
echo_current_diagnostic "Dashboard and block page"
# Use curl -I to get the header and parse out just the X-Pi-hole one
local block_page
block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r')
# Do it for the dashboard as well, as the header is different than above
local dashboard
dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r')
# Store what the X-Header should be in variables for comparison later
local block_page_working
block_page_working="X-Pi-hole: A black hole for Internet advertisements."
local dashboard_working
dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!"
local full_curl_output_block_page
full_curl_output_block_page="$(curl -Is localhost)"
local full_curl_output_dashboard
full_curl_output_dashboard="$(curl -Is localhost/admin/)"
# If the X-header found by curl matches what is should be,
if [[ $block_page == "$block_page_working" ]]; then
# display a success message
log_write "$TICK Block page X-Header: ${COL_GREEN}${block_page}${COL_NC}"
else
# Otherwise, show an error
log_write "$CROSS Block page X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
fi
# Same logic applies to the dashboard as above, if the X-Header matches what a working system should have,
if [[ $dashboard == "$dashboard_working" ]]; then
# then we can show a success
@@ -802,13 +886,13 @@ dig_at() {
# Store the arguments as variables with names
local protocol="${1}"
local IP="${2}"
echo_current_diagnostic "Name resolution (IPv${protocol}) using a random blocked domain and a known ad-serving domain"
# Set more local variables
# We need to test name resolution locally, via Pi-hole, and via a public resolver
local local_dig
local pihole_dig
local remote_dig
local interfaces
local addresses
# Use a static domain that we know has IPv4 and IPv6 to avoid false positives
# Sometimes the randomly chosen domains don't use IPv6, or something else is wrong with them
local remote_url="doubleclick.com"
@@ -817,15 +901,15 @@ dig_at() {
if [[ ${protocol} == "6" ]]; then
# Set the IPv6 variables and record type
local local_address="::1"
local pihole_address="${IP}"
local remote_address="2001:4860:4860::8888"
local sed_selector="inet6"
local record_type="AAAA"
# Otherwise, it should be 4
else
# so use the IPv4 values
local local_address="127.0.0.1"
local pihole_address="${IP}"
local remote_address="8.8.8.8"
local sed_selector="inet"
local record_type="A"
fi
@@ -835,55 +919,32 @@ dig_at() {
local random_url
random_url=$(sqlite3 "${PIHOLE_GRAVITY_DB_FILE}" "SELECT domain FROM vw_gravity ORDER BY RANDOM() LIMIT 1")
# First, do a dig on localhost to see if Pi-hole can use itself to block a domain
if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then
# If it can, show success
log_write "${TICK} ${random_url} ${COL_GREEN}is ${local_dig}${COL_NC} via ${COL_CYAN}localhost$COL_NC (${local_address})"
else
# Otherwise, show a failure
log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}localhost${COL_NC} (${local_address})"
fi
# Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address
# This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is
# just asing itself locally
# The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't
# waiting for too long
#
# Turn off history expansion such that the "!" in the sed command cannot do silly things
set +H
# Get interfaces
# sed logic breakdown:
# / master /d;
# Removes all interfaces that are slaves of others (e.g. virtual docker interfaces)
# /UP/!d;
# Removes all interfaces which are not UP
# s/^[0-9]*: //g;
# Removes interface index
# s/: <.*//g;
# Removes everything after the interface name
interfaces="$(ip link show | sed "/ master /d;/UP/!d;s/^[0-9]*: //g;s/: <.*//g;")"
# The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long
while IFS= read -r iface ; do
# Get addresses of current interface
# sed logic breakdown:
# /inet(|6) /!d;
# Removes all lines from ip a that do not contain either "inet " or "inet6 "
# s/^.*inet(|6) //g;
# Removes all leading whitespace as well as the "inet " or "inet6 " string
# s/\/.*$//g;
# Removes CIDR and everything thereafter (e.g., scope properties)
addresses="$(ip address show dev "${iface}" | sed "/${sed_selector} /!d;s/^.*${sed_selector} //g;s/\/.*$//g;")"
if [ -n "${addresses}" ]; then
while IFS= read -r local_address ; do
# Check if Pi-hole can use itself to block a domain
if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${local_address}" +short "${record_type}"); then
# If it can, show success
log_write "${TICK} ${random_url} ${COL_GREEN}is ${local_dig}${COL_NC} on ${COL_CYAN}${iface}${COL_NC} (${COL_CYAN}${local_address}${COL_NC})"
else
# Otherwise, show a failure
log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} on ${COL_RED}${iface}${COL_NC} (${COL_RED}${local_address}${COL_NC})"
fi
done <<< "${addresses}"
else
log_write "${TICK} No IPv${protocol} address available on ${COL_CYAN}${iface}${COL_NC}"
fi
done <<< "${interfaces}"
# If Pi-hole can dig itself from it's IP (not the loopback address)
if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${pihole_address}" +short "${record_type}"); then
# show a success
log_write "${TICK} ${random_url} ${COL_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})"
else
# Otherwise, show a failure
log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}Pi-hole${COL_NC} (${pihole_address})"
fi
# Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server
# We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6
if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @"${remote_address}" +short "${record_type}" | head -n1); then
if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then
# If successful, the real IP of the domain will be returned instead of Pi-hole's IP
log_write "${TICK} ${remote_url} ${COL_GREEN}is ${remote_dig}${COL_NC} via ${COL_CYAN}a remote, public DNS server${COL_NC} (${remote_address})"
else
@@ -998,7 +1059,7 @@ parse_file() {
local file_lines
# For each line in the file,
for file_lines in "${file_info[@]}"; do
if [[ -n "${file_lines}" ]]; then
if [[ ! -z "${file_lines}" ]]; then
# don't include the Web password hash
[[ "${file_lines}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue
# otherwise, display the lines of the file
@@ -1012,8 +1073,12 @@ parse_file() {
check_name_resolution() {
# Check name resolution from localhost, Pi-hole's IP, and Google's name severs
# using the function we created earlier
dig_at 4
dig_at 6
dig_at 4 "${IPV4_ADDRESS%/*}"
# If IPv6 enabled,
if [[ "${IPV6_ADDRESS}" ]]; then
# check resolution
dig_at 6 "${IPV6_ADDRESS%/*}"
fi
}
# This function can check a directory exists
@@ -1056,17 +1121,13 @@ 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}"
log_write "$(ls -ld "${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 -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
log_write "\\n${COL_GREEN}$(ls -ld "${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
@@ -1105,7 +1166,6 @@ 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() {
@@ -1206,11 +1266,11 @@ show_groups() {
}
show_adlists() {
show_db_entries "Adlists" "SELECT id,CASE enabled WHEN '0' THEN ' 0' WHEN '1' THEN ' 1' ELSE enabled END enabled,GROUP_CONCAT(adlist_by_group.group_id) group_ids,address,datetime(date_added,'unixepoch','localtime') date_added,datetime(date_modified,'unixepoch','localtime') date_modified,comment FROM adlist LEFT JOIN adlist_by_group ON adlist.id = adlist_by_group.adlist_id GROUP BY id;" "5 7 12 100 19 19 50"
show_db_entries "Adlists" "SELECT id,CASE enabled WHEN '0' THEN ' 0' WHEN '1' THEN ' 1' ELSE enabled END enabled,GROUP_CONCAT(adlist_by_group.group_id) group_ids,address,datetime(date_added,'unixepoch','localtime') date_added,datetime(date_modified,'unixepoch','localtime') date_modified,comment FROM adlist LEFT JOIN adlist_by_group ON adlist.id = adlist_by_group.adlist_id GROUP BY id;" "4 7 12 100 19 19 50"
}
show_domainlist() {
show_db_entries "Domainlist (0/1 = exact white-/blacklist, 2/3 = regex white-/blacklist)" "SELECT id,CASE type WHEN '0' THEN '0 ' WHEN '1' THEN ' 1 ' WHEN '2' THEN ' 2 ' WHEN '3' THEN ' 3' ELSE type END type,CASE enabled WHEN '0' THEN ' 0' WHEN '1' THEN ' 1' ELSE enabled END enabled,GROUP_CONCAT(domainlist_by_group.group_id) group_ids,domain,datetime(date_added,'unixepoch','localtime') date_added,datetime(date_modified,'unixepoch','localtime') date_modified,comment FROM domainlist LEFT JOIN domainlist_by_group ON domainlist.id = domainlist_by_group.domainlist_id GROUP BY id;" "5 4 7 12 100 19 19 50"
show_db_entries "Domainlist (0/1 = exact white-/blacklist, 2/3 = regex white-/blacklist)" "SELECT id,CASE type WHEN '0' THEN '0 ' WHEN '1' THEN ' 1 ' WHEN '2' THEN ' 2 ' WHEN '3' THEN ' 3' ELSE type END type,CASE enabled WHEN '0' THEN ' 0' WHEN '1' THEN ' 1' ELSE enabled END enabled,GROUP_CONCAT(domainlist_by_group.group_id) group_ids,domain,datetime(date_added,'unixepoch','localtime') date_added,datetime(date_modified,'unixepoch','localtime') date_modified,comment FROM domainlist LEFT JOIN domainlist_by_group ON domainlist.id = domainlist_by_group.domainlist_id GROUP BY id;" "4 4 7 12 100 19 19 50"
}
show_clients() {
@@ -1222,10 +1282,10 @@ show_messages() {
}
analyze_gravity_list() {
echo_current_diagnostic "Gravity Database"
echo_current_diagnostic "Gravity List and Database"
local gravity_permissions
gravity_permissions=$(ls -lhd "${PIHOLE_GRAVITY_DB_FILE}")
gravity_permissions=$(ls -ld "${PIHOLE_GRAVITY_DB_FILE}")
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
show_db_entries "Info table" "SELECT property,value FROM info" "20 40"
@@ -1248,88 +1308,77 @@ analyze_gravity_list() {
IFS="$OLD_IFS"
}
obfuscated_pihole_log() {
local pihole_log=("$@")
local line
local error_to_check_for
local line_to_obfuscate
local obfuscated_line
for line in "${pihole_log[@]}"; do
# A common error in the pihole.log is when there is a non-hosts formatted file
# that the DNS server is attempting to read. Since it's not formatted
# correctly, there will be an entry for "bad address at line n"
# So we can check for that here and highlight it in red so the user can see it easily
error_to_check_for=$(echo "${line}" | grep 'bad address at')
# Some users may not want to have the domains they visit sent to us
# To that end, we check for lines in the log that would contain a domain name
line_to_obfuscate=$(echo "${line}" | grep ': query\|: forwarded\|: reply')
# If the variable contains a value, it found an error in the log
if [[ -n ${error_to_check_for} ]]; then
# So we can print it in red to make it visible to the user
log_write " ${CROSS} ${COL_RED}${line}${COL_NC} (${FAQ_BAD_ADDRESS})"
else
# If the variable does not a value (the current default behavior), so do not obfuscate anything
if [[ -z ${OBFUSCATE} ]]; then
log_write " ${line}"
# Othwerise, a flag was passed to this command to obfuscate domains in the log
else
# So first check if there are domains in the log that should be obfuscated
if [[ -n ${line_to_obfuscate} ]]; then
# If there are, we need to use awk to replace only the domain name (the 6th field in the log)
# so we substitute the domain for the placeholder value
obfuscated_line=$(echo "${line_to_obfuscate}" | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
log_write " ${obfuscated_line}"
else
log_write " ${line}"
fi
fi
fi
done
}
analyze_pihole_log() {
echo_current_diagnostic "Pi-hole log"
local pihole_log_head=()
local pihole_log_tail=()
local pihole_log_permissions
local logging_enabled
logging_enabled=$(grep -c "^log-queries" /etc/dnsmasq.d/01-pihole.conf)
if [[ "${logging_enabled}" == "0" ]]; then
# Inform user that logging has been disabled and pihole.log does not contain queries
log_write "${INFO} Query logging is disabled"
log_write ""
fi
# Put the current Internal Field Separator into another variable so it can be restored later
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 -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}"
obfuscated_pihole_log "${pihole_log_head[@]}"
log_write ""
mapfile -t pihole_log_tail < <(tail -n 20 ${PIHOLE_LOG})
log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_LOG})------${COL_NC}"
obfuscated_pihole_log "${pihole_log_tail[@]}"
log_write ""
# Set the IFS back to what it was
IFS="$OLD_IFS"
echo_current_diagnostic "Pi-hole log"
local head_line
# Put the current Internal Field Separator into another variable so it can be restored later
OLD_IFS="$IFS"
# Get the lines that are in the file(s) and store them in an array for parsing later
IFS=$'\r\n'
local pihole_log_permissions
pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
local pihole_log_head=()
mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
local error_to_check_for
local line_to_obfuscate
local obfuscated_line
for head_line in "${pihole_log_head[@]}"; do
# A common error in the pihole.log is when there is a non-hosts formatted file
# that the DNS server is attempting to read. Since it's not formatted
# correctly, there will be an entry for "bad address at line n"
# So we can check for that here and highlight it in red so the user can see it easily
error_to_check_for=$(echo "${head_line}" | grep 'bad address at')
# Some users may not want to have the domains they visit sent to us
# To that end, we check for lines in the log that would contain a domain name
line_to_obfuscate=$(echo "${head_line}" | grep ': query\|: forwarded\|: reply')
# If the variable contains a value, it found an error in the log
if [[ -n ${error_to_check_for} ]]; then
# So we can print it in red to make it visible to the user
log_write " ${CROSS} ${COL_RED}${head_line}${COL_NC} (${FAQ_BAD_ADDRESS})"
else
# If the variable does not a value (the current default behavior), so do not obfuscate anything
if [[ -z ${OBFUSCATE} ]]; then
log_write " ${head_line}"
# Othwerise, a flag was passed to this command to obfuscate domains in the log
else
# So first check if there are domains in the log that should be obfuscated
if [[ -n ${line_to_obfuscate} ]]; then
# If there are, we need to use awk to replace only the domain name (the 6th field in the log)
# so we substitute the domain for the placeholder value
obfuscated_line=$(echo "${line_to_obfuscate}" | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
log_write " ${obfuscated_line}"
else
log_write " ${head_line}"
fi
fi
fi
done
log_write ""
# Set the IFS back to what it was
IFS="$OLD_IFS"
}
curl_to_tricorder() {
# Users can submit their debug logs using curl (encrypted)
log_write " * Using ${COL_GREEN}curl${COL_NC} for transmission."
# 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=""
tricorder_use_nc_or_curl() {
# Users can submit their debug logs using nc (unencrypted) or curl (encrypted) if available
# Check for curl first since encryption is a good thing
if command -v curl &> /dev/null; then
# If the command exists,
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:${TRICORDER_SSL_PORT_NUMBER})
if [ -z "${tricorder_token}" ]; then
# curl failed, fallback to nc
log_write " * ${COL_GREEN}curl${COL_NC} failed, falling back to ${COL_YELLOW}netcat${COL_NC} for transmission."
tricorder_token=$(< ${PIHOLE_DEBUG_LOG} nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER})
fi
# Otherwise,
else
# use net cat
log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission."
# Save the token returned by our server in a variable
tricorder_token=$(< ${PIHOLE_DEBUG_LOG} nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER})
fi
}
@@ -1348,13 +1397,14 @@ upload_to_tricorder() {
# Provide information on what they should do with their token
log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
log_write " * For more information, see: ${TRICORDER_CONTEST}"
log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat."
# If pihole -d is running automatically (usually through the dashboard)
if [[ "${AUTOMATED}" ]]; then
# let the user know
log_write "${INFO} Debug script running in automated mode"
# and then decide again which tool to use to submit it
curl_to_tricorder
tricorder_use_nc_or_curl
# If we're not running in automated mode,
else
echo ""
@@ -1363,7 +1413,7 @@ upload_to_tricorder() {
read -r -p "[?] Would you like to upload the log? [y/N] " response
case ${response} in
# If they say yes, run our function for uploading the log
[yY][eE][sS]|[yY]) curl_to_tricorder;;
[yY][eE][sS]|[yY]) tricorder_use_nc_or_curl;;
# If they choose no, just exit out of the script
*) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit;
esac
@@ -1374,15 +1424,15 @@ 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}\\n"
log_write "${COL_PURPLE}***********************************${COL_NC}"
log_write "${COL_PURPLE}***********************************${COL_NC}"
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}\\n"
log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
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 ${FORUMS_URL}"
log_write " * Provide the token above to the Pi-hole team for assistance at"
log_write " * ${FORUMS_URL}"
log_write " * Your log will self-destruct on our server after ${COL_RED}48 hours${COL_NC}."
# If no token was generated
else
# Show an error and some help instructions
@@ -1398,28 +1448,40 @@ make_temporary_log
initialize_debug
# setupVars.conf needs to be sourced before the networking so the values are
# available to the other functions
source_setup_variables
check_component_versions
check_critical_program_versions
diagnose_operating_system
check_selinux
check_firewalld
processor_check
check_networking
check_name_resolution
check_dhcp_servers
process_status
ftl_full_status
parse_setup_vars
check_x_headers
analyze_gravity_list
show_groups
show_domainlist
show_clients
show_adlists
show_content_of_pihole_files
show_messages
parse_locale
analyze_pihole_log
copy_to_debug_log
upload_to_tricorder
if ! check_for_ftl; then
log_write "${COL_RED}Unable to complete debug run. Please contact support for assistance."
log_write "Please note the error that is displayed above.${COL_NC}"
#Non-zero return value
exit 2
fi
if ! check_for_lua; then
log_write "${COL_RED}Unable to complete debug run. Please contact support for assistance."
log_write "Please note the error that is displayed above.${COL_NC}"
#Non-zero return value
exit 2
fi
# source_setup_variables
# check_component_versions
# check_critical_program_versions
# diagnose_operating_system
# check_selinux
# check_firewalld
# processor_check
# check_networking
# check_name_resolution
# check_dhcp_servers
# process_status
# ftl_full_status
# parse_setup_vars
# check_x_headers
# analyze_gravity_list
# show_groups
# show_domainlist
# show_clients
# show_adlists
# show_content_of_pihole_files
# show_messages
# parse_locale
# analyze_pihole_log
# copy_to_debug_log
# upload_to_tricorder

View File

@@ -11,11 +11,6 @@
colfile="/opt/pihole/COL_TABLE"
source ${colfile}
# In case we're running at the same time as a system logrotate, use a
# separate logrotate state file to prevent stepping on each other's
# toes.
STATEFILE="/var/lib/logrotate/pihole"
# Determine database location
# Obtain DBFILE=... setting from pihole-FTL.db
# Constructed to return nothing when
@@ -37,7 +32,7 @@ if [[ "$@" == *"once"* ]]; then
# Nightly logrotation
if command -v /usr/sbin/logrotate >/dev/null; then
# Logrotate once
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
/usr/sbin/logrotate --force /etc/pihole/logrotate
else
# Copy pihole.log over to pihole.log.1
# and empty out pihole.log
@@ -52,8 +47,8 @@ else
# Manual flushing
if command -v /usr/sbin/logrotate >/dev/null; then
# Logrotate twice to move all data out of sight of FTL
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate; sleep 3
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
/usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
/usr/sbin/logrotate --force /etc/pihole/logrotate
else
# Flush both pihole.log and pihole.log.1 (if existing)
echo " " > /var/log/pihole.log

View File

@@ -95,10 +95,6 @@ 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!"

View File

@@ -44,8 +44,7 @@ Options:
-e, email Set an administrative contact address for the Block Page
-h, --help Show this help dialog
-i, interface Specify dnsmasq's interface listening behavior
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)
-t, teleporter Backup configuration as an archive"
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)"
exit 0
}
@@ -54,7 +53,7 @@ add_setting() {
}
delete_setting() {
sed -i "/^${1}/d" "${setupVars}"
sed -i "/${1}/d" "${setupVars}"
}
change_setting() {
@@ -67,7 +66,7 @@ addFTLsetting() {
}
deleteFTLsetting() {
sed -i "/^${1}/d" "${FTLconf}"
sed -i "/${1}/d" "${FTLconf}"
}
changeFTLsetting() {
@@ -84,7 +83,7 @@ add_dnsmasq_setting() {
}
delete_dnsmasq_setting() {
sed -i "/^${1}/d" "${dnsmasqconfig}"
sed -i "/${1}/d" "${dnsmasqconfig}"
}
SetTemperatureUnit() {
@@ -267,23 +266,18 @@ 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
# Prevent Firefox from automatically switching over to DNS-over-HTTPS
# This follows https://support.mozilla.org/en-US/kb/configuring-networks-disable-dns-over-https
# (sourced 7th September 2019)
add_dnsmasq_setting "server=/use-application-dns.net/"
# We need to process DHCP settings here as well to account for possible
# changes in the non-FQDN forwarding. This cannot be done in 01-pihole.conf
# as we don't want to delete all local=/.../ lines so it's much safer to
@@ -432,7 +426,7 @@ dhcp-leasefile=/etc/pihole/dhcp.leases
echo "#quiet-dhcp6
#enable-ra
dhcp-option=option6:dns-server,[::]
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,64,3600
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
ra-param=*,0,0
" >> "${dhcpconfig}"
fi
@@ -722,7 +716,7 @@ RemoveCustomDNSAddress() {
host="${args[3]}"
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
sed -i "/^${ip} ${host}$/d" "${dnscustomfile}"
sed -i "/${ip} ${host}/d" "${dnscustomfile}"
else
echo -e " ${CROSS} Invalid IP has been passed"
exit 1
@@ -754,7 +748,7 @@ RemoveCustomCNAMERecord() {
if [[ -n "${validDomain}" ]]; then
validTarget="$(checkDomain "${target}")"
if [[ -n "${validDomain}" ]]; then
sed -i "/cname=${validDomain},${validTarget}$/d" "${dnscustomcnamefile}"
sed -i "/cname=${validDomain},${validTarget}/d" "${dnscustomcnamefile}"
else
echo " ${CROSS} Invalid Target Passed!"
exit 1

View File

@@ -0,0 +1,28 @@
#!/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}"
}

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
#!/usr/bin/env bash
### BEGIN INIT INFO
# Provides: pihole-FTL
# Required-Start: $remote_fs $syslog $network
@@ -9,8 +9,11 @@
# Description: Enable service provided by pihole-FTL daemon
### END INIT INFO
FTLUSER=pihole
PIDFILE=/run/pihole-FTL.pid
is_running() {
pgrep -xo "pihole-FTL" > /dev/null
pgrep -o "pihole-FTL" > /dev/null 2>&1
}
@@ -20,18 +23,27 @@ start() {
echo "pihole-FTL is already running"
else
# Touch files to ensure they exist (create if non-existing, preserve if existing)
mkdir -pm 0755 /run/pihole
touch /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
touch /var/log/pihole-FTL.log /var/log/pihole.log
touch /run/pihole-FTL.pid /run/pihole-FTL.port
touch /etc/pihole/dhcp.leases
mkdir -p /run/pihole
mkdir -p /var/log/pihole
chown pihole:pihole /run/pihole /var/log/pihole
# Remove possible leftovers from previous pihole-FTL processes
rm -f /dev/shm/FTL-* 2> /dev/null
rm /run/pihole/FTL.sock 2> /dev/null
# 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
chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port
chown pihole:pihole /etc/pihole /etc/pihole/dhcp.leases 2> /dev/null
chown pihole:pihole /var/log/pihole-FTL.log /var/log/pihole.log
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
# 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,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
chown pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db 2> /dev/null
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE+eip "$(which pihole-FTL)"; then
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
else
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
/usr/bin/pihole-FTL
pihole-FTL
fi
echo
fi
@@ -40,20 +52,20 @@ start() {
# Stop the service
stop() {
if is_running; then
pkill -xo "pihole-FTL"
for i in 1 2 3 4 5; do
pkill -o pihole-FTL
for i in {1..5}; do
if ! is_running; then
break
fi
printf "."
echo -n "."
sleep 1
done
echo
if is_running; then
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
pkill -xo -9 "pihole-FTL"
pkill -o -9 pihole-FTL
exit 1
else
echo "Stopped"
@@ -61,8 +73,6 @@ stop() {
else
echo "Not running"
fi
# Cleanup
rm -f /run/pihole/FTL.sock /dev/shm/FTL-*
echo
}
@@ -91,7 +101,7 @@ case "$1" in
start
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status}"
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac

View File

@@ -26,7 +26,7 @@
# parameter "quiet": don't print messages
00 00 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole flush once quiet
@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate
@reboot root /usr/sbin/logrotate /etc/pihole/logrotate
# Pi-hole: Grab local version and branch every 10 minutes
*/10 * * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker local

View File

@@ -11,6 +11,15 @@ $serverName = htmlspecialchars($_SERVER["SERVER_NAME"]);
// Remove external ipv6 brackets if any
$serverName = preg_replace('/^\[(.*)\]$/', '${1}', $serverName);
if (!is_file("/etc/pihole/setupVars.conf"))
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
// Get values from setupVars.conf
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
unset($setupVars);
// Set landing page location, found within /var/www/html/
$landPage = "../landing.php";
@@ -25,6 +34,21 @@ if (!empty($_SERVER["FQDN"])) {
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
}
// Set which extension types render as Block Page (Including "" for index.ext)
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
// Get extension of current URL
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
// Set mobile friendly viewport
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1">';
// Set response header
function setHeader($type = "x") {
header("X-Pi-hole: A black hole for Internet advertisements.");
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
}
// Determine block page type
if ($serverName === "pi.hole"
|| (!empty($_SERVER["VIRTUAL_HOST"]) && $serverName === $_SERVER["VIRTUAL_HOST"])) {
@@ -47,26 +71,325 @@ if ($serverName === "pi.hole"
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
$viewPort
<title>● $serverName</title>
<link rel='stylesheet' href='pihole/blockingpage.css'>
<link rel='shortcut icon' href='admin/img/favicons/favicon.ico' type='image/x-icon'>
<style>
#splashpage { background: #222; color: rgba(255, 255, 255, 0.7); text-align: center; }
#splashpage img { margin: 5px; width: 256px; }
#splashpage b { color: inherit; }
</style>
</head>
<body id='splashpage'>
<img src='admin/img/logo.svg' alt='Pi-hole logo' width='256' height='377'>
<br>
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
<a href='/admin'>Did you mean to go to the admin panel?</a>
<div id="pihole_card">
<img src='admin/img/logo.svg' alt='Pi-hole logo' id="pihole_logo_splash" />
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
<a href='/admin'>Did you mean to go to the admin panel?</a>
</div>
</body>
</html>
EOT;
exit($splashPage);
} elseif ($currentUrlExt === "js") {
// Serve Pi-hole JavaScript for blocked domains requesting JS
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER
// e.g: An iframe of a blocked domain
exit(setHeader().'<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><script>window.close();</script>
</head>
<body>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=">
</body>
</html>');
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
// Serve SVG upon receiving non $validExtTypes URL extension or query string
// e.g: Not an iframe of a blocked domain, such as when browsing to a file/query directly
// QoL addition: Allow the SVG to be clicked on in order to quickly show the full Block Page
$blockImg = '<a href="/">
<svg xmlns="http://www.w3.org/2000/svg" width="110" height="16">
<circle cx="8" cy="8" r="7" fill="none" stroke="rgba(152,2,2,.5)" stroke-width="2"/>
<path fill="rgba(152,2,2,.5)" d="M11.526 3.04l1.414 1.415-8.485 8.485-1.414-1.414z"/>
<text x="19.3" y="12" opacity=".3" style="font:11px Arial">
Blocked by Pi-hole
</text>
</svg>
</a>';
exit(setHeader()."<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
$viewPort
</head>
<body>$blockImg</body>
</html>");
}
exit(header("HTTP/1.1 404 Not Found"));
/* Start processing Block Page from here */
// Define admin email address text based off $svEmail presence
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
// Get possible non-standard location of FTL's database
$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf");
if (isset($FTLsettings["GRAVITYDB"])) {
$gravityDBFile = $FTLsettings["GRAVITYDB"];
} else {
$gravityDBFile = "/etc/pihole/gravity.db";
}
// Connect to gravity.db
try {
$db = new SQLite3($gravityDBFile, SQLITE3_OPEN_READONLY);
} catch (Exception $exception) {
die("[ERROR]: Failed to connect to gravity.db");
}
// Get all adlist addresses
$adlistResults = $db->query("SELECT address FROM vw_adlist");
$adlistsUrls = array();
while ($row = $adlistResults->fetchArray()) {
array_push($adlistsUrls, $row[0]);
}
if (empty($adlistsUrls))
die("[ERROR]: There are no adlists enabled");
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
$adlistsCount = count($adlistsUrls) + 3;
// Set query timeout
ini_set("default_socket_timeout", 3);
// Logic for querying blocklists
function queryAds($serverName) {
// Determine the time it takes while querying adlists
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
$queryAdsURL = sprintf(
"http://127.0.0.1:%s/admin/scripts/pi-hole/php/queryads.php?domain=%s&bp",
$_SERVER["SERVER_PORT"],
$serverName
);
$queryAds = file($queryAdsURL, FILE_IGNORE_NEW_LINES);
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
// Exception Handling
try {
// Define Exceptions
if (strpos($queryAds[0], "No exact results") !== FALSE) {
// Return "none" into $queryAds array
return array("0" => "none");
} else if ($queryTime >= ini_get("default_socket_timeout")) {
// Connection Timeout
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
} elseif (!strpos($queryAds[0], ".") !== false) {
// Unknown $queryAds output
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
}
return $queryAds;
} catch (Exception $e) {
// Return exception as array
return array("0" => "error", "1" => $e->getMessage());
}
}
// Get results of queryads.php exact search
$queryAds = queryAds($serverName);
// Pass error through to Block Page
if ($queryAds[0] === "error")
die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
// Count total number of matching blocklists
$featuredTotal = count($queryAds);
// Place results into key => value array
$queryResults = null;
foreach ($queryAds as $str) {
$value = explode(" ", $str);
@$queryResults[$value[0]] .= "$value[1]";
}
// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
if (strpos($queryAds[0], "blacklist") !== FALSE) {
$notableFlagClass = "blacklist";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
$notableFlagClass = "noblock";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
$wlInfo = "recentwl";
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
$notableFlagClass = "wildcard";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif ($queryAds[0] === "none") {
$featuredTotal = "0";
$notableFlagClass = "noblock";
// QoL addition: Determine appropriate info message if CNAME exists
// Suggests to the user that $serverName has a CNAME (alias) that may be blocked
$dnsRecord = dns_get_record("$serverName")[0];
if (array_key_exists("target", $dnsRecord)) {
$wlInfo = $dnsRecord['target'];
} else {
$wlInfo = "unknown";
}
}
// Set #bpOutput notification
$wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
$wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
// Get Pi-hole Core version
$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
// Print $execTime on development branches
// Testing for - is marginally faster than "git rev-parse --abbrev-ref HEAD"
if (explode("-", $phVersion)[1] != "0")
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
// Please Note: Text is added via CSS to allow an admin to provide a localized
// language without the need to edit this file
setHeader();
?>
<!doctype html>
<!-- Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL. -->
<html>
<head>
<meta charset="utf-8">
<?=$viewPort ?>
<meta name="robots" content="noindex,nofollow">
<meta http-equiv="x-dns-prefetch-control" content="off">
<link rel="stylesheet" href="pihole/blockingpage.css">
<link rel="shortcut icon" href="admin/img/favicons/favicon.ico" type="image/x-icon">
<title>● <?=$serverName ?></title>
<script src="admin/scripts/vendor/jquery.min.js"></script>
<script>
window.onload = function () {
<?php
// Remove href fallback from "Back to safety" button
if ($featuredTotal > 0) {
echo '$("#bpBack").removeAttr("href");';
// Enable whitelisting if JS is available
echo '$("#bpWhitelist").prop("disabled", false);';
// Enable password input if necessary
if (!empty($svPasswd)) {
echo '$("#bpWLPassword").attr("placeholder", "Password");';
echo '$("#bpWLPassword").prop("disabled", false);';
}
// Otherwise hide the input
else {
echo '$("#bpWLPassword").hide();';
}
}
?>
}
</script>
</head>
<body id="blockpage"><div id="bpWrapper">
<header>
<h1 id="bpTitle">
<a class="title" href="/"><?php //Website Blocked ?></a>
</h1>
<div class="spc"></div>
<input id="bpAboutToggle" type="checkbox">
<div id="bpAbout">
<div class="aboutPH">
<div class="aboutImg"></div>
<p>Open Source Ad Blocker
<small>Designed for Raspberry Pi</small>
</p>
</div>
<div class="aboutLink">
<a class="linkPH" href="https://docs.pi-hole.net/"><?php //About PH ?></a>
<?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
</div>
</div>
<div id="bpAlt">
<label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
</div>
</header>
<main>
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
<div id="bpBlock">
<p class="blockMsg"><?=$serverName ?></p>
</div>
<?php if(isset($notableFlagClass)) { ?>
<div id="bpFlag">
<p class="flagMsg <?=$notableFlagClass ?>"></p>
</div>
<?php } ?>
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
<div id="bpButtons" class="buttons">
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
</div>
<input id="bpMoreToggle" type="checkbox">
<div id="bpMoreInfo">
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
<form id="bpWLButtons" class="buttons">
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled>
<input id="bpWLPassword" type="password" placeholder="JavaScript disabled" disabled>
<button id="bpWhitelist" type="button" disabled></button>
</form>
</div>
</main>
<footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
</div>
<script>
function add() {
$("#bpOutput").removeClass("hidden error exception");
$("#bpOutput").addClass("add");
var domain = "<?=$serverName ?>";
var pw = $("#bpWLPassword");
if(domain.length === 0) {
return;
}
$.ajax({
url: "/admin/scripts/pi-hole/php/add.php",
method: "post",
data: {"domain":domain, "list":"white", "pw":pw.val()},
success: function(response) {
if(response.indexOf("Pi-hole blocking") !== -1) {
setTimeout(function(){window.location.reload(1);}, 10000);
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("success");
$("#bpOutput").html("");
} else {
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("error");
$("#bpOutput").html(""+response+"");
}
},
error: function(jqXHR, exception) {
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("exception");
$("#bpOutput").html("");
}
});
}
<?php if ($featuredTotal > 0) { ?>
$(document).keypress(function(e) {
if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
add();
}
});
$("#bpWhitelist").on("click", function() {
add();
});
<?php } ?>
</script>
</body></html>

View File

@@ -20,6 +20,7 @@ server.modules = (
"mod_accesslog",
"mod_auth",
"mod_expire",
"mod_compress",
"mod_redirect",
"mod_setenv",
"mod_rewrite"
@@ -40,6 +41,26 @@ index-file.names = ( "index.php", "index.html", "index.lighttpd.html"
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = (
"application/json",
"application/vnd.ms-fontobject",
"application/xml",
"font/eot",
"font/opentype",
"font/otf",
"font/ttf",
"image/bmp",
"image/svg+xml",
"image/vnd.microsoft.icon",
"image/x-icon",
"text/css",
"text/html",
"text/javascript",
"text/plain",
"text/xml"
)
mimetype.assign = (
".ico" => "image/x-icon",
".jpeg" => "image/jpeg",
@@ -78,6 +99,11 @@ $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

View File

@@ -21,6 +21,7 @@ server.modules = (
"mod_expire",
"mod_fastcgi",
"mod_accesslog",
"mod_compress",
"mod_redirect",
"mod_setenv",
"mod_rewrite"
@@ -41,6 +42,26 @@ index-file.names = ( "index.php", "index.html", "index.lighttpd.html"
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = (
"application/json",
"application/vnd.ms-fontobject",
"application/xml",
"font/eot",
"font/opentype",
"font/otf",
"font/ttf",
"image/bmp",
"image/svg+xml",
"image/vnd.microsoft.icon",
"image/x-icon",
"text/css",
"text/html",
"text/javascript",
"text/plain",
"text/xml"
)
mimetype.assign = (
".ico" => "image/x-icon",
".jpeg" => "image/jpeg",
@@ -86,6 +107,11 @@ $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

View File

@@ -34,26 +34,27 @@ 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, 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
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
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 (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
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
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, 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
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
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
lighttpdConfig="/etc/lighttpd/lighttpd.conf"
# shellcheck disable=SC2034
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"
@@ -74,7 +75,7 @@ PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update versi
PI_HOLE_INSTALL_DIR="/opt/pihole"
PI_HOLE_CONFIG_DIR="/etc/pihole"
PI_HOLE_BIN_DIR="/usr/local/bin"
PI_HOLE_404_DIR="${webroot}/pihole"
PI_HOLE_BLOCKPAGE_DIR="${webroot}/pihole"
if [ -z "$useUpdateVars" ]; then
useUpdateVars=false
fi
@@ -93,9 +94,24 @@ if [ -z "${USER}" ]; then
USER="$(id -un)"
fi
# 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
# 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 ))
######## Undocumented Flags. Shhh ########
# These are undocumented flags; some of which we can use when repairing an installation
@@ -170,12 +186,12 @@ os_check() {
# This function gets a list of supported OS versions from a TXT record at versions.pi-hole.net
# and determines whether or not the script is running on one of those systems
local remote_os_domain valid_os valid_version valid_response detected_os detected_version display_warning cmdResult digReturnCode response
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
remote_os_domain="versions.pi-hole.net"
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
cmdResult="$(dig +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
cmdResult="$(dig +short -t txt ${remote_os_domain} @ns1.pi-hole.net 2>&1; echo $?)"
# Gets the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
@@ -260,11 +276,11 @@ os_check() {
}
# Compatibility
package_manager_detect() {
# First check to see if apt-get is installed.
distro_check() {
# 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 installed package manager might be rpm, so these values would be different
# 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"
@@ -272,25 +288,79 @@ if is_command apt-get ; then
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
# Some distros vary slightly so these fixes for dependencies may apply
# on Ubuntu 18.04.1 LTS we need to add the universe repository to gain access to dhcpcd5
APT_SOURCES="/etc/apt/sources.list"
if awk 'BEGIN{a=1;b=0}/bionic main/{a=0}/bionic.*universe/{b=1}END{exit a + b}' ${APT_SOURCES}; then
if ! whiptail --defaultno --title "Dependencies Require Update to Allowed Repositories" --yesno "Would you like to enable 'universe' repository?\\n\\nThis repository is required by the following packages:\\n\\n- dhcpcd5" "${r}" "${c}"; then
printf " %b Aborting installation: Dependencies could not be installed.\\n" "${CROSS}"
exit 1
else
printf " %b Enabling universe package repository for Ubuntu Bionic\\n" "${INFO}"
cp -p ${APT_SOURCES} ${APT_SOURCES}.backup # Backup current repo list
printf " %b Backed up current configuration to %s\\n" "${TICK}" "${APT_SOURCES}.backup"
add-apt-repository universe
printf " %b Enabled %s\\n" "${TICK}" "'universe' repository"
fi
fi
# 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
local phpVer="php"
if is_command php ; then
printf " %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "$(php <<< "<?php echo PHP_VERSION ?>")"
printf -v phpInsMajor "%d" "$(php <<< "<?php echo PHP_MAJOR_VERSION ?>")"
printf -v phpInsMinor "%d" "$(php <<< "<?php echo PHP_MINOR_VERSION ?>")"
# Is installed php version 7.0 or greater
if [ "${phpInsMajor}" -ge 7 ]; then
phpInsNewer=true
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
else
printf " %b Aborting installation: No PHP packages were found in APT repository.\\n" "${CROSS}"
exit 1
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
# Packages required to perfom the os_check (stored as an array)
OS_CHECK_DEPS=(grep dnsutils)
# 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 run this install script (stored as an array)
INSTALLER_DEPS=(git iproute2 whiptail ca-certificates)
INSTALLER_DEPS=(dhcpcd5 git "${iproute_pkg}" whiptail dnsutils)
# 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)
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}-sqlite3" "${phpVer}-xml" "${phpVer}-intl")
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")
@@ -318,7 +388,7 @@ if is_command apt-get ; then
return 0
}
# If apt-get is not found, check for rpm.
# 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
@@ -327,110 +397,108 @@ elif is_command rpm ; then
PKG_MANAGER="yum"
fi
# These variable names match the ones for apt-get. See above for an explanation of what they are for.
# 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 ca-certificates)
PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc sqlite libcap lsof)
INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig bind-utils)
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"
# 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
: # continue
# or if host OS is CentOS,
elif grep -qiE 'centos|scientific' /etc/redhat-release; then
# Pi-Hole currently supports CentOS 7+ with PHP7+
SUPPORTED_CENTOS_VERSION=7
SUPPORTED_CENTOS_PHP_VERSION=7
# Check current CentOS major release version
CURRENT_CENTOS_VERSION=$(grep -oP '(?<= )[0-9]+(?=\.?)' /etc/redhat-release)
# Check if CentOS version is supported
if [[ $CURRENT_CENTOS_VERSION -lt $SUPPORTED_CENTOS_VERSION ]]; then
printf " %b CentOS %s is not supported.\\n" "${CROSS}" "${CURRENT_CENTOS_VERSION}"
printf " Please update to CentOS release %s or later.\\n" "${SUPPORTED_CENTOS_VERSION}"
# exit the installer
exit
fi
# php-json is not required on CentOS 7 as it is already compiled into php
# verifiy via `php -m | grep json`
if [[ $CURRENT_CENTOS_VERSION -eq 7 ]]; then
# create a temporary array as arrays are not designed for use as mutable data structures
CENTOS7_PIHOLE_WEB_DEPS=()
for i in "${!PIHOLE_WEB_DEPS[@]}"; do
if [[ ${PIHOLE_WEB_DEPS[i]} != "php-json" ]]; then
CENTOS7_PIHOLE_WEB_DEPS+=( "${PIHOLE_WEB_DEPS[i]}" )
fi
done
# re-assign the clean dependency array back to PIHOLE_WEB_DEPS
PIHOLE_WEB_DEPS=("${CENTOS7_PIHOLE_WEB_DEPS[@]}")
unset CENTOS7_PIHOLE_WEB_DEPS
fi
# CentOS requires the EPEL repository to gain access to Fedora packages
EPEL_PKG="epel-release"
rpm -q ${EPEL_PKG} &> /dev/null || rc=$?
if [[ $rc -ne 0 ]]; then
printf " %b Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)\\n" "${INFO}"
"${PKG_INSTALL[@]}" ${EPEL_PKG} &> /dev/null
printf " %b Installed %s\\n" "${TICK}" "${EPEL_PKG}"
fi
# The default php on CentOS 7.x is 5.4 which is EOL
# Check if the version of PHP available via installed repositories is >= to PHP 7
AVAILABLE_PHP_VERSION=$("${PKG_MANAGER}" info php | grep -i version | grep -o '[0-9]\+' | head -1)
if [[ $AVAILABLE_PHP_VERSION -ge $SUPPORTED_CENTOS_PHP_VERSION ]]; then
# Since PHP 7 is available by default, install via default PHP package names
: # do nothing as PHP is current
else
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}"
else
printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
exit 1
fi
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
# we cannot install required packages
printf " %b No supported package manager found\\n" "${CROSS}"
# it's not an OS we can support,
printf " %b OS distribution not supported\\n" "${CROSS}"
# so exit the installer
exit
fi
}
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
: # continue
# or if host OS is CentOS,
elif grep -qiE 'centos|scientific' /etc/redhat-release; then
# Pi-Hole currently supports CentOS 7+ with PHP7+
SUPPORTED_CENTOS_VERSION=7
SUPPORTED_CENTOS_PHP_VERSION=7
# Check current CentOS major release version
CURRENT_CENTOS_VERSION=$(grep -oP '(?<= )[0-9]+(?=\.?)' /etc/redhat-release)
# Check if CentOS version is supported
if [[ $CURRENT_CENTOS_VERSION -lt $SUPPORTED_CENTOS_VERSION ]]; then
printf " %b CentOS %s is not supported.\\n" "${CROSS}" "${CURRENT_CENTOS_VERSION}"
printf " Please update to CentOS release %s or later.\\n" "${SUPPORTED_CENTOS_VERSION}"
# exit the installer
exit
fi
# php-json is not required on CentOS 7 as it is already compiled into php
# verifiy via `php -m | grep json`
if [[ $CURRENT_CENTOS_VERSION -eq 7 ]]; then
# create a temporary array as arrays are not designed for use as mutable data structures
CENTOS7_PIHOLE_WEB_DEPS=()
for i in "${!PIHOLE_WEB_DEPS[@]}"; do
if [[ ${PIHOLE_WEB_DEPS[i]} != "php-json" ]]; then
CENTOS7_PIHOLE_WEB_DEPS+=( "${PIHOLE_WEB_DEPS[i]}" )
fi
done
# re-assign the clean dependency array back to PIHOLE_WEB_DEPS
PIHOLE_WEB_DEPS=("${CENTOS7_PIHOLE_WEB_DEPS[@]}")
unset CENTOS7_PIHOLE_WEB_DEPS
fi
# CentOS requires the EPEL repository to gain access to Fedora packages
EPEL_PKG="epel-release"
rpm -q ${EPEL_PKG} &> /dev/null || rc=$?
if [[ $rc -ne 0 ]]; then
printf " %b Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)\\n" "${INFO}"
"${PKG_INSTALL[@]}" ${EPEL_PKG} &> /dev/null
printf " %b Installed %s\\n" "${TICK}" "${EPEL_PKG}"
fi
# The default php on CentOS 7.x is 5.4 which is EOL
# Check if the version of PHP available via installed repositories is >= to PHP 7
AVAILABLE_PHP_VERSION=$("${PKG_MANAGER}" info php | grep -i version | grep -o '[0-9]\+' | head -1)
if [[ $AVAILABLE_PHP_VERSION -ge $SUPPORTED_CENTOS_PHP_VERSION ]]; then
# Since PHP 7 is available by default, install via default PHP package names
: # do nothing as PHP is current
else
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}"
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
}
# A function for checking if a directory is a git repository
is_repo() {
# Use a named, local variable instead of the vague $1, which is the first argument passed to this function
@@ -514,7 +582,7 @@ 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 --no-rebase --quiet &> /dev/null || return $?
git pull --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)
@@ -624,17 +692,9 @@ welcomeDialogs() {
whiptail --msgbox --backtitle "Plea" --title "Free and open source" "\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/" "${r}" "${c}"
# Explain the need for a static address
if whiptail --defaultno --backtitle "Initiating network interface" --title "Static IP Needed" --yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.
whiptail --msgbox --backtitle "Initiating network interface" --title "Static IP Needed" "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.
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
In the next section, you can choose to use your current network settings (DHCP) or to manually edit them." "${r}" "${c}"
}
# A function that lets the user pick an interface to use with Pi-hole
@@ -716,8 +776,9 @@ testIPv6() {
fi
}
find_IPv6_information() {
# Detects IPv6 address used for communication to WAN addresses.
# A dialog for showing the user about IPv6 blocking
useIPv6dialog() {
# Determine the IPv6 address used for blocking
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
@@ -737,34 +798,73 @@ find_IPv6_information() {
# set the IPv6 address to the ULA address
IPV6_ADDRESS="${ULA_ADDRESS}"
# Show this info to the user
printf " %b Found IPv6 ULA address\\n" "${INFO}"
printf " %b Found IPv6 ULA address, using it for blocking IPv6 ads\\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\\n" "${INFO}"
printf " %b Found IPv6 GUA address, using it for blocking IPv6 ads\\n" "${INFO}"
# And assign it to the global variable
IPV6_ADDRESS="${GUA_ADDRESS}"
# If none of those work,
else
printf " %b Unable to find IPv6 ULA/GUA address\\n" "${INFO}"
# 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}"
# 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 collect IPv4 and IPv6 information of the device
collect_v4andv6_information() {
find_IPv4_information
# 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
getStaticIPv4Settings
setStaticIPv4
fi
# If IPv6 is to be used,
if [[ "${useIPv6}" ]]; then
# Run our function to get this information
useIPv6dialog
fi
# Echo the information to the user
printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
# 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
setDHCPCD
fi
find_IPv6_information
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
fi
}
getStaticIPv4Settings() {
@@ -833,6 +933,93 @@ setDHCPCD() {
fi
}
# Configure networking ifcfg-xxxx file found at /etc/sysconfig/network-scripts/
# This function requires the full path of an ifcfg file passed as an argument
setIFCFG() {
# Local, named variables
local IFCFG_FILE
local IPADDR
local CIDR
IFCFG_FILE=$1
printf -v IPADDR "%s" "${IPV4_ADDRESS%%/*}"
# Check if the desired IP is already set
if grep -Eq "${IPADDR}(\\b|\\/)" "${IFCFG_FILE}"; then
printf " %b Static IP already configured\\n" "${INFO}"
else
# Otherwise, put the IP in variables without the CIDR notation
printf -v CIDR "%s" "${IPV4_ADDRESS##*/}"
# Backup existing interface configuration:
cp -p "${IFCFG_FILE}" "${IFCFG_FILE}".pihole.orig
# Build Interface configuration file using the GLOBAL variables we have
{
echo "# Configured via Pi-hole installer"
echo "DEVICE=$PIHOLE_INTERFACE"
echo "BOOTPROTO=none"
echo "ONBOOT=yes"
echo "IPADDR=$IPADDR"
echo "PREFIX=$CIDR"
echo "GATEWAY=$IPv4gw"
echo "DNS1=$PIHOLE_DNS_1"
echo "DNS2=$PIHOLE_DNS_2"
echo "USERCTL=no"
}> "${IFCFG_FILE}"
chmod 644 "${IFCFG_FILE}"
chown root:root "${IFCFG_FILE}"
# Use ip to immediately set the new address
ip addr replace dev "${PIHOLE_INTERFACE}" "${IPV4_ADDRESS}"
# If NetworkMangler command line interface exists and ready to mangle,
if is_command nmcli && nmcli general status &> /dev/null; then
# Tell NetworkManagler to read our new sysconfig file
nmcli con load "${IFCFG_FILE}" > /dev/null
fi
# Show a warning that the user may need to restart
printf " %b Set IP address to %s\\n You may need to restart after the install is complete\\n" "${TICK}" "${IPV4_ADDRESS%%/*}"
fi
}
setStaticIPv4() {
# Local, named variables
local IFCFG_FILE
local CONNECTION_NAME
# If a static interface is already configured, we are done.
if [[ -r "/etc/sysconfig/network/ifcfg-${PIHOLE_INTERFACE}" ]]; then
if grep -q '^BOOTPROTO=.static.' "/etc/sysconfig/network/ifcfg-${PIHOLE_INTERFACE}"; then
return 0
fi
fi
# For the Debian family, if dhcpcd.conf exists then we can just configure using DHCPD.
if [[ -f "/etc/dhcpcd.conf" ]]; then
setDHCPCD
return 0
fi
# If a DHCPCD config file was not found, check for an ifcfg config file based on the interface name
if [[ -f "/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}" ]];then
# If it exists, then we can configure using IFCFG
IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}
setIFCFG "${IFCFG_FILE}"
return 0
fi
# If an ifcfg config does not exists for the interface name, search for one based on the connection name via network manager
if is_command nmcli && nmcli general status &> /dev/null; then
CONNECTION_NAME=$(nmcli dev show "${PIHOLE_INTERFACE}" | grep 'GENERAL.CONNECTION' | cut -d: -f2 | sed 's/^System//' | xargs | tr ' ' '_')
IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${CONNECTION_NAME}
if [[ -f "${IFCFG_FILE}" ]];then
# If it exists,
setIFCFG "${IFCFG_FILE}"
return 0
else
printf " %b Warning: sysconfig network script not found. Creating ${IFCFG_FILE}\\n" "${INFO}"
touch "${IFCFG_FILE}"
setIFCFG "${IFCFG_FILE}"
return 0
fi
fi
# If previous conditions failed, show an error and exit
printf " %b Warning: Unable to locate configuration file to set static IPv4 address\\n" "${INFO}"
exit 1
}
# Check an IP address to see if it is a valid one
valid_ip() {
# Local, named variables
@@ -1148,10 +1335,8 @@ 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_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"
local dnsmasq_pihole_01_snippet="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf"
local dnsmasq_pihole_01_location="/etc/dnsmasq.d/01-pihole.conf"
# If the dnsmasq config file exists
if [[ -f "${dnsmasq_conf}" ]]; then
@@ -1180,48 +1365,44 @@ version_check_dnsmasq() {
printf "%b %b No dnsmasq.conf found... restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}"
fi
printf " %b Installing %s..." "${INFO}" "${dnsmasq_pihole_01_target}"
printf " %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..." "${INFO}"
# 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_source}" "${dnsmasq_pihole_01_target}"
printf "%b %b Installed %s\n" "${OVER}" "${TICK}" "${dnsmasq_pihole_01_target}"
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}"
# 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_target}"
sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_location}"
if [[ "${PIHOLE_DNS_1}" != "" ]]; then
# then swap in the primary DNS server.
sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_target}"
sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_location}"
else
# Otherwise, remove the line which sets DNS1.
sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_target}"
sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_location}"
fi
# Ditto if DNS2 is not empty
if [[ "${PIHOLE_DNS_2}" != "" ]]; then
sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_target}"
sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_location}"
else
sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_target}"
sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_location}"
fi
# Set the cache size
sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" "${dnsmasq_pihole_01_target}"
sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" ${dnsmasq_pihole_01_location}
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_target}"
sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_location}"
else
# Otherwise, enable it by uncommenting the directive in the DNS config file
sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_target}"
sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_location}"
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
@@ -1312,18 +1493,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 "${lighttpdConfig}" ]]; then
elif [[ -f "/etc/lighttpd/lighttpd.conf" ]]; then
# back up the original
mv "${lighttpdConfig}"{,.orig}
mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
fi
# and copy in the config file Pi-hole needs
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}"
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf
# 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"/' "${lighttpdConfig}"
sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' /etc/lighttpd/lighttpd.conf
fi
# Make the directories if they do not exist and set the owners
mkdir -p /run/lighttpd
@@ -1470,6 +1651,9 @@ 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.
@@ -1482,7 +1666,7 @@ update_package_cache() {
else
# Otherwise, show an error and exit
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
printf " %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "${UPDATE_PKG_CACHE}" "${COL_NC}"
return 1
fi
}
@@ -1509,7 +1693,20 @@ notify_package_updates_available() {
fi
}
# This counter is outside of install_dependent_packages so that it can count the number of times the function is called.
counter=0
install_dependent_packages() {
# Local, named variables should be used here, especially for an iterator
# Add one to the counter
counter=$((counter+1))
if [[ "${counter}" == 1 ]]; then
# On the first loop, print a special message
printf " %b Installer Dependency checks...\\n" "${INFO}"
else
# On all subsequent loops, print a generic message.
printf " %b Main Dependency checks...\\n" "${INFO}"
fi
# Install packages passed in via argument array
# No spinner - conflicts with set -e
@@ -1534,8 +1731,6 @@ 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[@]}"
@@ -1571,18 +1766,18 @@ install_dependent_packages() {
# Install the Web interface dashboard
installPiholeWeb() {
printf "\\n %b Installing 404 page...\\n" "${INFO}"
printf "\\n %b Installing blocking page...\\n" "${INFO}"
local str="Creating directory for 404 page, and copying files"
local str="Creating directory for blocking page, and copying files"
printf " %b %s..." "${INFO}" "${str}"
# Install the directory
install -d -m 0755 ${PI_HOLE_404_DIR}
# and the 404 handler
install -D -m 644 ${PI_HOLE_LOCAL_REPO}/advanced/index.php ${PI_HOLE_404_DIR}/
# Install the directory,
install -d -m 0755 ${PI_HOLE_BLOCKPAGE_DIR}
# and the blockpage
install -D -m 644 ${PI_HOLE_LOCAL_REPO}/advanced/{index,blockingpage}.* ${PI_HOLE_BLOCKPAGE_DIR}/
# Remove superseded file
if [[ -e "${PI_HOLE_404_DIR}/index.js" ]]; then
rm "${PI_HOLE_404_DIR}/index.js"
if [[ -e "${PI_HOLE_BLOCKPAGE_DIR}/index.js" ]]; then
rm "${PI_HOLE_BLOCKPAGE_DIR}/index.js"
fi
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
@@ -1714,7 +1909,7 @@ 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;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/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;' "${setupVars}"
fi
# echo the information to the user
{
@@ -1728,8 +1923,6 @@ finalExports() {
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}"
@@ -1751,17 +1944,9 @@ finalExports() {
# Install the logrotate script
installLogrotate() {
local str="Installing latest logrotate script"
local target=/etc/pihole/logrotate
printf "\\n %b %s..." "${INFO}" "${str}"
if [[ -f ${target} ]]; then
printf "\\n\\t%b Existing logrotate file found. No changes made.\\n" "${INFO}"
# Return value isn't that important, using 2 to indicate that it's not a fatal error but
# the function did not complete.
return 2
fi
# Copy the file over from the local repo
install -D -m 644 -T "${PI_HOLE_LOCAL_REPO}"/advanced/Templates/logrotate ${target}
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/Templates/logrotate /etc/pihole/logrotate
# Different operating systems have different user / group
# settings for logrotate that makes it impossible to create
# a static logrotate file that will work with e.g.
@@ -1770,13 +1955,34 @@ installLogrotate() {
# the local properties of the /var/log directory
logusergroup="$(stat -c '%U %G' /var/log)"
# If there is a usergroup for log rotation,
if [[ -n "${logusergroup}" ]]; then
if [[ ! -z "${logusergroup}" ]]; then
# replace the line in the logrotate script with that usergroup.
sed -i "s/# su #/su ${logusergroup}/g;" ${target}
sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate
fi
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,
@@ -1807,6 +2013,10 @@ 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}"
@@ -1824,10 +2034,8 @@ installPihole() {
fi
# Install the cron file
installCron
# Install the logrotate file
installLogrotate || true
installLogrotate
# Check if dnsmasq is present. If so, disable it and back up any possible
# config file
disable_dnsmasq
@@ -1891,7 +2099,7 @@ displayFinalMessage() {
if [[ "${#1}" -gt 0 ]] ; then
# set the password to the first argument.
pwstring="$1"
elif [[ $(grep 'WEBPASSWORD' -c "${setupVars}") -gt 0 ]]; then
elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then
# Else if the password exists from previous setup, we'll load it later
pwstring="unchanged"
else
@@ -1912,7 +2120,7 @@ Your Admin Webpage login password is ${pwstring}"
IPv4: ${IPV4_ADDRESS%/*}
IPv6: ${IPV6_ADDRESS:-"Not Configured"}
If you have not done so already, the above IP should be set to static.
If you set a new IP address, you should restart the Pi.
The install log is in /etc/pihole.
@@ -1933,7 +2141,7 @@ update_dialogs() {
strAdd="You will be updated to the latest version."
fi
opt2a="Reconfigure"
opt2b="Resets Pi-hole and allows re-selecting settings."
opt2b="This will reset your Pi-hole and allow you to enter new 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 \
@@ -2028,7 +2236,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 --no-rebase || return 1)
git_pull=$(git pull || return 1)
if [[ "$git_pull" == *"up-to-date"* ]]; then
printf " %b %s\\n" "${INFO}" "${git_pull}"
@@ -2118,6 +2326,8 @@ FTLinstall() {
# Before stopping FTL, we download the macvendor database
curl -sSL "https://ftl.pi-hole.net/macvendor.db" -o "${PI_HOLE_CONFIG_DIR}/macvendor.db" || true
chmod 644 "${PI_HOLE_CONFIG_DIR}/macvendor.db"
chown pihole:pihole "${PI_HOLE_CONFIG_DIR}/macvendor.db"
# Stop pihole-FTL service if available
stop_service pihole-FTL &> /dev/null
@@ -2422,30 +2632,8 @@ main() {
fi
fi
# Check for supported package managers so that we may install dependencies
package_manager_detect
# Notify user of package availability
notify_package_updates_available
# Install packages necessary to perform os_check
printf " %b Checking for / installing Required dependencies for OS Check...\\n" "${INFO}"
install_dependent_packages "${OS_CHECK_DEPS[@]}"
# Check that the installed OS is officially supported - display warning if not
os_check
# Install packages used by this installation script
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
# Check for supported distribution
distro_check
# If the setup variable file exists,
if [[ -f "${setupVars}" ]]; then
@@ -2462,6 +2650,19 @@ main() {
fi
fi
# Start the installer
# Notify user of package availability
notify_package_updates_available
# Install packages used by this installation script
install_dependent_packages "${INSTALLER_DEPS[@]}"
# Check that the installed OS is officially supported - display warning if not
os_check
# Check if SELinux is Enforcing
checkSelinux
if [[ "${useUpdateVars}" == false ]]; then
# Display welcome dialogs
welcomeDialogs
@@ -2475,8 +2676,8 @@ main() {
setDNS
# Give the user a choice of blocklists to include in their install. Or not.
chooseBlocklists
# find IPv4 and IPv6 information of the device
collect_v4andv6_information
# 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...
@@ -2508,8 +2709,6 @@ main() {
dep_install_list+=("${PIHOLE_WEB_DEPS[@]}")
fi
# Install packages used by the actual software
printf " %b Checking for / installing Required dependencies for Pi-hole software...\\n" "${INFO}"
install_dependent_packages "${dep_install_list[@]}"
unset dep_install_list
@@ -2549,7 +2748,7 @@ main() {
# Add password to web UI if there is none
pw=""
# If no password is set,
if [[ $(grep 'WEBPASSWORD' -c "${setupVars}") == 0 ]] ; then
if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then
# generate a random password
pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
# shellcheck disable=SC1091
@@ -2614,7 +2813,7 @@ main() {
printf " %b You may now configure your devices to use the Pi-hole as their DNS server\\n" "${INFO}"
[[ -n "${IPV4_ADDRESS%/*}" ]] && printf " %b Pi-hole DNS (IPv4): %s\\n" "${INFO}" "${IPV4_ADDRESS%/*}"
[[ -n "${IPV6_ADDRESS}" ]] && printf " %b Pi-hole DNS (IPv6): %s\\n" "${INFO}" "${IPV6_ADDRESS}"
printf " %b If you have not done so already, the above IP should be set to static.\\n" "${INFO}"
printf " %b If you set a new IP address, please restart the server running the Pi-hole\\n" "${INFO}"
INSTALL_TYPE="Installation"
else
INSTALL_TYPE="Update"

View File

@@ -42,8 +42,8 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# setupVars set in basic-install.sh
source "${setupVars}"
# package_manager_detect() sourced from basic-install.sh
package_manager_detect
# distro_check() sourced from basic-install.sh
distro_check
# Install packages used by the Pi-hole
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
@@ -113,7 +113,7 @@ removeNoPurge() {
fi
fi
echo -e "${OVER} ${TICK} Removed Web Interface"
# Attempt to preserve backwards compatibility with older versions
# to guarantee no additional changes were made to /etc/crontab after
# the installation of pihole, /etc/crontab.pihole should be permanently
@@ -145,7 +145,6 @@ 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
@@ -207,7 +206,11 @@ removeNoPurge() {
}
######### SCRIPT ###########
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
if command -v vcgencmd &> /dev/null; then
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
else
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
fi
while true; do
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
echo -n " "

View File

@@ -15,6 +15,8 @@ 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"
@@ -45,6 +47,16 @@ domainsExtension="domains"
setupVars="${piholeDir}/setupVars.conf"
if [[ -f "${setupVars}" ]];then
source "${setupVars}"
# Remove CIDR mask from IPv4/6 addresses
IPV4_ADDRESS="${IPV4_ADDRESS%/*}"
IPV6_ADDRESS="${IPV6_ADDRESS%/*}"
# Determine if IPv4/6 addresses exist
if [[ -z "${IPV4_ADDRESS}" ]] && [[ -z "${IPV6_ADDRESS}" ]]; then
echo -e " ${COL_LIGHT_RED}No IP addresses found! Please run 'pihole -r' to reconfigure${COL_NC}"
exit 1
fi
else
echo -e " ${COL_LIGHT_RED}Installation Failure: ${setupVars} does not exist! ${COL_NC}
Please run 'pihole -r', and choose the 'reconfigure' option to fix."
@@ -61,8 +73,6 @@ fi
# have changed
gravityDBfile="${GRAVITYDB}"
gravityTEMPfile="${GRAVITYDB}_temp"
gravityDIR="$(dirname -- "${gravityDBfile}")"
gravityOLDfile="${gravityDIR}/gravity_old.db"
if [[ -z "${BLOCKINGMODE}" ]] ; then
BLOCKINGMODE="NULL"
@@ -113,19 +123,8 @@ gravity_swap_databases() {
fi
echo -e "${OVER} ${TICK} ${str}"
# Swap databases and remove or conditionally rename old database
# Number of available blocks on disk
availableBlocks=$(stat -f --format "%a" "${gravityDIR}")
# Number of blocks, used by gravity.db
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
echo -e " ${TICK} The old database remains available."
mv "${gravityDBfile}" "${gravityOLDfile}"
else
rm "${gravityDBfile}"
fi
# Swap databases and remove old database
rm "${gravityDBfile}"
mv "${gravityTEMPfile}" "${gravityDBfile}"
}
@@ -565,7 +564,7 @@ compareLists() {
# Download specified URL and perform checks on HTTP status and file content
gravity_DownloadBlocklistFromUrl() {
local url="${1}" cmd_ext="${2}" agent="${3}" adlistID="${4}" saveLocation="${5}" target="${6}" compression="${7}"
local heisenbergCompensator="" patternBuffer str httpCode success="" ip
local heisenbergCompensator="" patternBuffer str httpCode success=""
# Create temp file to store content on disk instead of RAM
patternBuffer=$(mktemp -p "/tmp" --suffix=".phgpb")
@@ -583,10 +582,7 @@ 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
if [[ $(dig "${domain}" +short | grep "${IPV4_ADDRESS}" -c) -ge 1 ]]; then
blocked=true
fi;;
"NXDOMAIN")
@@ -789,12 +785,43 @@ gravity_ShowCount() {
gravity_Table_Count "vw_regex_whitelist" "regex whitelist filters"
}
# Parse list of domains into hosts format
gravity_ParseDomainsIntoHosts() {
awk -v ipv4="$IPV4_ADDRESS" -v ipv6="$IPV6_ADDRESS" '{
# Remove windows CR line endings
sub(/\r$/, "")
# Parse each line as "ipaddr domain"
if(ipv6 && ipv4) {
print ipv4" "$0"\n"ipv6" "$0
} else if(!ipv6) {
print ipv4" "$0
} else {
print ipv6" "$0
}
}' >> "${2}" < "${1}"
}
# Create "localhost" entries into hosts format
gravity_generateLocalList() {
local hostname
if [[ -s "/etc/hostname" ]]; then
hostname=$(< "/etc/hostname")
elif command -v hostname &> /dev/null; then
hostname=$(hostname -f)
else
echo -e " ${CROSS} Unable to determine fully qualified domain name of host"
return 0
fi
echo -e "${hostname}\\npi.hole" > "${localList}.tmp"
# Empty $localList if it already exists, otherwise, create it
echo "### Do not modify this file, it will be overwritten by pihole -g" > "${localList}"
: > "${localList}"
chmod 644 "${localList}"
gravity_ParseDomainsIntoHosts "${localList}.tmp" "${localList}"
# Add additional LAN hosts provided by OpenVPN (if available)
if [[ -f "${VPNList}" ]]; then
awk -F, '{printf $2"\t"$1".vpn\n"}' "${VPNList}" >> "${localList}"
@@ -863,11 +890,6 @@ for var in "$@"; do
esac
done
# Remove OLD (backup) gravity file, if it exists
if [[ -f "${gravityOLDfile}" ]]; then
rm "${gravityOLDfile}"
fi
# Trap Ctrl-C
gravity_Trap

View File

@@ -56,7 +56,7 @@ Available commands and options:
\fB-w, whitelist\fR [options] [<domain1> <domain2 ...>]
.br
Adds or removes specified domain or domains to the Whitelist
Adds or removes specified domain or domains tho the Whitelist
.br
\fB-b, blacklist\fR [options] [<domain1> <domain2 ...>]

50
pihole
View File

@@ -242,7 +242,7 @@ Time:
echo "BLOCKING_ENABLED=true" >> "${setupVars}"
fi
restartDNS reload-lists
restartDNS reload
echo -e "${OVER} ${TICK} ${str}"
}
@@ -363,13 +363,16 @@ tailFunc() {
fi
echo -e " ${INFO} Press Ctrl-C to exit"
# Retrieve IPv4/6 addresses
source /etc/pihole/setupVars.conf
# Strip date from each line
# Color blocklist/blacklist/wildcard entries as red
# Color A/AAAA/DHCP strings as white
# Color everything else as gray
tail -f /var/log/pihole.log | grep --line-buffered "${1}" | sed -E \
tail -f /var/log/pihole.log | sed -E \
-e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \
-e "s,(.*(blacklisted |gravity blocked ).*),${COL_RED}&${COL_NC}," \
-e "s,(.*(blacklisted |gravity blocked ).* is (0.0.0.0|::|NXDOMAIN|${IPV4_ADDRESS%/*}|${IPV6_ADDRESS:-NULL}).*),${COL_RED}&${COL_NC}," \
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
-e "s,.*,${COL_GRAY}&${COL_NC},"
exit 0
@@ -399,24 +402,34 @@ Branches:
}
tricorderFunc() {
local tricorder_token
if [[ ! -p "/dev/stdin" ]]; then
echo -e " ${INFO} Please do not call Tricorder directly"
exit 1
fi
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
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 "$?"
fi
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
exit 0
}
updateCheckFunc() {
@@ -443,10 +456,7 @@ Debugging Options:
Add '-a' to automatically upload the log to tricorder.pi-hole.net
-f, flush Flush the Pi-hole log
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
-t, tail [arg] View the live output of the Pi-hole log.
Add an optional argument to filter the log
(regular expressions are supported)
-t, tail View the live output of the Pi-hole log
Options:
-a, admin Web interface options
@@ -520,7 +530,7 @@ case "${1}" in
"status" ) statusFunc "$2";;
"restartdns" ) restartDNS "$2";;
"-a" | "admin" ) webpageFunc "$@";;
"-t" | "tail" ) tailFunc "$2";;
"-t" | "tail" ) tailFunc;;
"checkout" ) piholeCheckoutFunc "$@";;
"tricorder" ) tricorderFunc;;
"updatechecker" ) updateCheckFunc "$@";;

5
supportedos.txt Normal file
View File

@@ -0,0 +1,5 @@
Raspbian=9,10
Ubuntu=16,18,20
Debian=9,10
Fedora=32,33
CentOS=7,8

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -1,17 +0,0 @@
FROM buildpack-deps:bullseye-scm
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -13,6 +13,5 @@ RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -1,18 +0,0 @@
FROM buildpack-deps:hirsute-scm
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
ENV DEBIAN_FRONTEND=noninteractive
RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -8,6 +8,8 @@ check_output = testinfra.get_backend(
SETUPVARS = {
'PIHOLE_INTERFACE': 'eth99',
'IPV4_ADDRESS': '1.1.1.1',
'IPV6_ADDRESS': 'FE80::240:D0FF:FE48:4672',
'PIHOLE_DNS_1': '4.2.2.1',
'PIHOLE_DNS_2': '4.2.2.2'
}

View File

@@ -11,20 +11,20 @@ from .conftest import (
)
def test_supported_package_manager(Pihole):
def test_supported_operating_system(Pihole):
'''
confirm installer exits when no supported package manager found
confirm installer exists on unsupported distribution
'''
# break supported package managers
# 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('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
distro_check
''')
expected_stdout = cross_box + ' No supported package manager found'
assert expected_stdout in package_manager_detect.stdout
# assert package_manager_detect.rc == 1
expected_stdout = cross_box + ' OS distribution not supported'
assert expected_stdout in distro_check.stdout
# assert distro_check.rc == 1
def test_setupVars_are_sourced_to_global_scope(Pihole):
@@ -45,6 +45,8 @@ def test_setupVars_are_sourced_to_global_scope(Pihole):
# Currently debug test function only
echo "Outputting sourced variables"
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}"
}
@@ -112,9 +114,9 @@ def test_installPiholeWeb_fresh_install_no_errors(Pihole):
source /opt/pihole/basic-install.sh
installPiholeWeb
''')
expected_stdout = info_box + ' Installing 404 page...'
expected_stdout = info_box + ' Installing blocking page...'
assert expected_stdout in installWeb.stdout
expected_stdout = tick_box + (' Creating directory for 404 page, '
expected_stdout = tick_box + (' Creating directory for blocking page, '
'and copying files')
assert expected_stdout in installWeb.stdout
expected_stdout = info_box + ' Backing up index.lighttpd.html'
@@ -126,6 +128,7 @@ def test_installPiholeWeb_fresh_install_no_errors(Pihole):
assert expected_stdout in installWeb.stdout
web_directory = Pihole.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):
@@ -134,7 +137,7 @@ def test_update_package_cache_success_no_errors(Pihole):
'''
updateCache = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
distro_check
update_package_cache
''')
expected_stdout = tick_box + ' Update local cache of available packages'
@@ -149,7 +152,7 @@ def test_update_package_cache_failure_no_errors(Pihole):
mock_command('apt-get', {'update': ('', '1')}, Pihole)
updateCache = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
distro_check
update_package_cache
''')
expected_stdout = cross_box + ' Update local cache of available packages'
@@ -356,7 +359,7 @@ def test_FTL_download_aarch64_no_errors(Pihole):
mock_command('whiptail', {'*': ('', '0')}, Pihole)
Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
distro_check
install_dependent_packages ${INSTALLER_DEPS[@]}
''')
download_binary = Pihole.run('''
@@ -420,9 +423,10 @@ def test_IPv6_only_link_local(Pihole):
)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
find_IPv6_information
useIPv6dialog
''')
expected_stdout = ('Unable to find IPv6 ULA/GUA address')
expected_stdout = ('Unable to find IPv6 ULA/GUA address, '
'IPv6 adblocking will not be enabled')
assert expected_stdout in detectPlatform.stdout
@@ -443,9 +447,9 @@ def test_IPv6_only_ULA(Pihole):
)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
find_IPv6_information
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address'
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
@@ -466,9 +470,9 @@ def test_IPv6_only_GUA(Pihole):
)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
find_IPv6_information
useIPv6dialog
''')
expected_stdout = 'Found IPv6 GUA address'
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
@@ -490,9 +494,9 @@ def test_IPv6_GUA_ULA_test(Pihole):
)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
find_IPv6_information
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address'
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
@@ -514,9 +518,9 @@ def test_IPv6_ULA_GUA_test(Pihole):
)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
find_IPv6_information
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address'
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
@@ -565,8 +569,7 @@ def test_os_check_fails(Pihole):
''' Confirms install fails on unsupported OS '''
Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${OS_CHECK_DEPS[@]}
distro_check
install_dependent_packages ${INSTALLER_DEPS[@]}
cat <<EOT > /etc/os-release
ID=UnsupportedOS
@@ -585,8 +588,7 @@ def test_os_check_passes(Pihole):
''' Confirms OS meets the requirements '''
Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${OS_CHECK_DEPS[@]}
distro_check
install_dependent_packages ${INSTALLER_DEPS[@]}
''')
detectOS = Pihole.run('''
@@ -595,44 +597,3 @@ def test_os_check_passes(Pihole):
''')
expected_stdout = 'Supported OS detected'
assert expected_stdout in detectOS.stdout
def test_package_manager_has_installer_deps(Pihole):
''' Confirms OS is able to install the required packages for the installer'''
mock_command('whiptail', {'*': ('', '0')}, Pihole)
output = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
install_dependent_packages ${INSTALLER_DEPS[@]}
''')
assert 'No package' not in output.stdout # centos7 still exits 0...
assert output.rc == 0
def test_package_manager_has_pihole_deps(Pihole):
''' Confirms OS is able to install the required packages for Pi-hole '''
mock_command('whiptail', {'*': ('', '0')}, Pihole)
output = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
install_dependent_packages ${PIHOLE_DEPS[@]}
''')
assert 'No package' not in output.stdout # centos7 still exits 0...
assert output.rc == 0
def test_package_manager_has_web_deps(Pihole):
''' Confirms OS is able to install the required packages for web '''
mock_command('whiptail', {'*': ('', '0')}, Pihole)
output = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
install_dependent_packages ${PIHOLE_WEB_DEPS[@]}
''')
assert 'No package' not in output.stdout # centos7 still exits 0...
assert output.rc == 0

View File

@@ -9,14 +9,13 @@ def test_php_upgrade_default_optout_centos_eq_7(Pihole):
'''
confirms the default behavior to opt-out of installing PHP7 from REMI
'''
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -28,14 +27,13 @@ def test_php_upgrade_user_optout_centos_eq_7(Pihole):
'''
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*': ('', '1')}, Pihole)
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -47,17 +45,16 @@ def test_php_upgrade_user_optin_centos_eq_7(Pihole):
'''
# Whiptail dialog returns Continue for user prompt
mock_command('whiptail', {'*': ('', '0')}, Pihole)
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
assert 'opt-out' not in package_manager_detect.stdout
assert 'opt-out' not in distro_check.stdout
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
'(https://rpms.remirepo.net)')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert remi_package.is_installed

View File

@@ -10,14 +10,13 @@ def test_php_upgrade_default_continue_centos_gte_8(Pihole):
confirms the latest version of CentOS continues / does not optout
(should trigger on CentOS7 only)
'''
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert unexpected_stdout not in distro_check.stdout
# ensure remi was not installed on latest CentOS
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -31,14 +30,13 @@ def test_php_upgrade_user_optout_skipped_centos_gte_8(Pihole):
'''
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*': ('', '1')}, Pihole)
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert unexpected_stdout not in distro_check.stdout
# ensure remi was not installed on latest CentOS
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -52,17 +50,16 @@ def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
'''
# Whiptail dialog returns Continue for user prompt
mock_command('whiptail', {'*': ('', '0')}, Pihole)
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
assert 'opt-out' not in package_manager_detect.stdout
assert 'opt-out' not in distro_check.stdout
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
'(https://rpms.remirepo.net)')
assert unexpected_stdout not in package_manager_detect.stdout
assert unexpected_stdout not in distro_check.stdout
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert unexpected_stdout not in package_manager_detect.stdout
assert unexpected_stdout not in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed

View File

@@ -13,31 +13,29 @@ def test_release_supported_version_check_centos(Pihole):
'''
# 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('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
expected_stdout = cross_box + (' CentOS 6 is not supported.')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
expected_stdout = 'Please update to CentOS release 7 or later'
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
def test_enable_epel_repository_centos(Pihole):
'''
confirms the EPEL package repository is enabled when installed on CentOS
'''
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
expected_stdout = info_box + (' Enabling EPEL package repository '
'(https://fedoraproject.org/wiki/EPEL)')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
expected_stdout = tick_box + ' Installed epel-release'
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
epel_package = Pihole.package('epel-release')
assert epel_package.is_installed
@@ -53,14 +51,13 @@ def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
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('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -78,14 +75,13 @@ def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
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('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
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
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert not remi_package.is_installed
@@ -103,21 +99,20 @@ def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
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('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
install_dependent_packages PIHOLE_WEB_DEPS[@]
''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.')
assert expected_stdout not in package_manager_detect.stdout
assert expected_stdout not in distro_check.stdout
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
'(https://rpms.remirepo.net)')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout
assert expected_stdout in distro_check.stdout
remi_package = Pihole.package('remi-release')
assert remi_package.is_installed
updated_php_package = Pihole.package('php')

View File

@@ -3,12 +3,11 @@ def test_epel_and_remi_not_installed_fedora(Pihole):
confirms installer does not attempt to install EPEL/REMI repositories
on Fedora
'''
package_manager_detect = Pihole.run('''
distro_check = Pihole.run('''
source /opt/pihole/basic-install.sh
package_manager_detect
select_rpm_php
distro_check
''')
assert package_manager_detect.stdout == ''
assert distro_check.stdout == ''
epel_package = Pihole.package('epel-release')
assert not epel_package.is_installed

View File

@@ -1,8 +0,0 @@
[tox]
envlist = py37
[testenv]
whitelist_externals = docker
deps = -rrequirements.txt
commands = docker build -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_automated_install.py

View File

@@ -1,8 +0,0 @@
[tox]
envlist = py37
[testenv]
whitelist_externals = docker
deps = -rrequirements.txt
commands = docker build -f _ubuntu_21.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_automated_install.py