Merge branch 'development' into fix-version.sh

This commit is contained in:
Adam Warner 2021-11-28 15:29:57 +00:00 committed by GitHub
commit cda952a569
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 1520 additions and 1003 deletions

10
.github/dependabot.yml vendored Normal file
View file

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

40
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,40 @@
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,21 +5,44 @@ on:
types: [opened, synchronize, reopened, ready_for_review] types: [opened, synchronize, reopened, ready_for_review]
jobs: 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: distro-test:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: smoke-test
strategy: strategy:
matrix: 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, debian_11, ubuntu_16, ubuntu_18, ubuntu_20, ubuntu_21, centos_7, centos_8, fedora_33, fedora_34]
env: env:
DISTRO: ${{matrix.distro}} DISTRO: ${{matrix.distro}}
steps: steps:
- uses: actions/checkout@v1 -
- name: Set up Python 3.7 name: Checkout repository
uses: actions/checkout@v2
-
name: Set up Python 3.8
uses: actions/setup-python@v2 uses: actions/setup-python@v2
with: with:
python-version: 3.7 python-version: 3.8
- name: Install dependencies -
name: Install dependencies
run: pip install -r test/requirements.txt run: pip install -r test/requirements.txt
- name: Test with tox -
name: Test with tox
run: tox -c test/tox.${DISTRO}.ini run: tox -c test/tox.${DISTRO}.ini

68
.gitignore vendored
View file

@ -7,70 +7,6 @@ __pycache__
.tox .tox
.eggs .eggs
*.egg-info *.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 *.iml
.idea/misc.xml .vscode/
*.ipr
# End of https://www.gitignore.io/api/jetbrains+iml

View file

@ -1,25 +0,0 @@
<?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>

View file

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

View file

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

View file

@ -11,9 +11,9 @@
</p> </p>
<!-- markdownlint-enable MD033 --> <!-- 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 - **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 - **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/) - **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 - **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 - **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 - **Modern**: blocks ads over both IPv4 and IPv6
- **Free**: open source software which helps ensure _you_ are the sole person in control of your privacy - **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
----- -----
@ -57,21 +57,21 @@ Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-h
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention. Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention.
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); just be sure to disable DHCP on your router first (if it has that feature available). If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
As a last resort, you can always manually set each device to use Pi-hole as their DNS server. As a last resort, you can manually set each device to use Pi-hole as their DNS server.
----- -----
## Pi-hole is free, but powered by your support ## Pi-hole is free but powered by your support
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained. There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
Make no mistake: **your support is absolutely vital to help keep us innovating!** Make no mistake: **your support is absolutely vital to help keep us innovating!**
### [Donations](https://pi-hole.net/donate) ### [Donations](https://pi-hole.net/donate)
Sending a donation using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses and rewarding our dedicated development team: Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
### Alternative support ### 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_ - [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_ - [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_ - [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 ### Contributing via GitHub
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests. We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions that it asks will help the volunteers quickly understand what you're aiming to achieve. If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions it asks will help the volunteers quickly understand what you're aiming to achieve.
You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) and the [debug script](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/piholeDebug.sh) have an abundance of comments, which will help you better understand how Pi-hole works. They're also a valuable resource to those who want to learn how to write scripts or code a program! We encourage anyone who likes to tinker to read through it and submit a pull request for us to review. 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 ## Getting in touch with us
While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on a variety of social media outlets. While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on various social media outlets.
**Please be sure to check the FAQ's** before starting a new discussion. Many user questions already have answers and can be solved without any additional assistance. **Please be sure to check the FAQs** before starting a new discussion, as we do not have the spare time to reply to every request for assistance.
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs) - [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes) - [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 - Queries cached
- Unique clients - Unique clients
The API can be accessed via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863). Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
### The Command Line Interface ### The Command Line Interface
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to be able to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`. The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
Some notable features include: 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) - [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) - [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) - [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: Some notable features include:
- Mobile friendly interface - Mobile-friendly interface
- Password protection - Password protection
- Detailed graphs and doughnut charts - Detailed graphs and doughnut charts
- Top lists of domains and clients - Top lists of domains and clients

View file

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

42
advanced/06-rfc6761.conf Normal file
View file

@ -0,0 +1,42 @@
# Pi-hole: A black hole for Internet advertisements
# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# RFC 6761 config file for Pi-hole
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
###############################################################################
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
# WITHIN /etc/dnsmasq.d/yourname.conf #
###############################################################################
# RFC 6761: Caching DNS servers SHOULD recognize
# test, localhost, invalid
# names as special and SHOULD NOT attempt to look up NS records for them, or
# otherwise query authoritative DNS servers in an attempt to resolve these
# names.
server=/test/
server=/localhost/
server=/invalid/
# The same RFC requests something similar for
# 10.in-addr.arpa. 21.172.in-addr.arpa. 27.172.in-addr.arpa.
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 28.172.in-addr.arpa.
# 17.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
# 18.172.in-addr.arpa. 24.172.in-addr.arpa. 30.172.in-addr.arpa.
# 19.172.in-addr.arpa. 25.172.in-addr.arpa. 31.172.in-addr.arpa.
# 20.172.in-addr.arpa. 26.172.in-addr.arpa. 168.192.in-addr.arpa.
# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
# 01-pihole.conf) because this also covers IPv6.
# OpenWRT furthermore blocks bind, local, onion domains
# see https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob_plain;f=package/network/services/dnsmasq/files/rfc6761.conf;hb=HEAD
# and https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
# We do not include the ".local" rule ourselves, see https://github.com/pi-hole/pi-hole/pull/4282#discussion_r689112972
server=/bind/
server=/onion/

View file

@ -329,8 +329,8 @@ get_sys_stats() {
*) cpu_col="$COL_URG_RED";; *) cpu_col="$COL_URG_RED";;
esac esac
# $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
elif [[ "$temp_unit" == "F" ]]; then elif [[ "$temp_unit" == "F" ]]; then
cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
@ -445,7 +445,7 @@ get_strings() {
lan_info="Gateway: $net_gateway" lan_info="Gateway: $net_gateway"
dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max" dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
ads_info="$total_str$ads_blocked_today of $dns_queries_today" ads_info="$total_str$ads_blocked_today of $dns_queries_today"
dns_info="$dns_count DNS servers" dns_info="$dns_count DNS servers"
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}" [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
@ -488,7 +488,7 @@ chronoFunc() {
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC} ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
${COL_DARK_GRAY}$scr_line_str${COL_NC}" ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
else else
echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str\\n| ¯_/¯|_| ' \\/ _ \\ / -_)$lte_ver_str\\n|_| |_| |_||_\\___/_\\___|$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}" echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str\\n| ¯_/¯|_| ' \\/ _ \\ / -_)$lte_ver_str\\n|_| |_| |_||_\\___/_\\___|$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
fi fi
printFunc " Hostname: " "$sys_name" "$host_info" printFunc " Hostname: " "$sys_name" "$host_info"

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

@ -122,4 +122,10 @@ upgrade_gravityDB(){
sqlite3 "${database}" < "${scriptPath}/13_to_14.sql" sqlite3 "${database}" < "${scriptPath}/13_to_14.sql"
version=14 version=14
fi fi
if [[ "$version" == "14" ]]; then
# Changes the vw_adlist created in 5_to_6
echo -e " ${INFO} Upgrading gravity database from version 14 to 15"
sqlite3 "${database}" < "${scriptPath}/14_to_15.sql"
version=15
fi
} }

View file

@ -10,4 +10,4 @@ ALTER TABLE adlist ADD COLUMN status INTEGER NOT NULL DEFAULT 0;
UPDATE info SET value = 14 WHERE property = 'version'; UPDATE info SET value = 14 WHERE property = 'version';
COMMIT; COMMIT;

View file

@ -0,0 +1,15 @@
.timeout 30000
PRAGMA FOREIGN_KEYS=OFF;
BEGIN TRANSACTION;
DROP VIEW vw_adlist;
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
FROM adlist
WHERE enabled = 1
ORDER BY id;
UPDATE info SET value = 15 WHERE property = 'version';
COMMIT;

View file

@ -16,14 +16,14 @@ GRAVITYDB="${piholeDir}/gravity.db"
# Source pihole-FTL from install script # Source pihole-FTL from install script
pihole_FTL="${piholeDir}/pihole-FTL.conf" pihole_FTL="${piholeDir}/pihole-FTL.conf"
if [[ -f "${pihole_FTL}" ]]; then if [[ -f "${pihole_FTL}" ]]; then
source "${pihole_FTL}" source "${pihole_FTL}"
fi fi
# Set this only after sourcing pihole-FTL.conf as the gravity database path may # Set this only after sourcing pihole-FTL.conf as the gravity database path may
# have changed # have changed
gravityDBfile="${GRAVITYDB}" gravityDBfile="${GRAVITYDB}"
reload=false noReloadRequested=false
addmode=true addmode=true
verbose=true verbose=true
wildcard=false wildcard=false
@ -35,6 +35,7 @@ typeId=""
comment="" comment=""
declare -i domaincount declare -i domaincount
domaincount=0 domaincount=0
reload=false
colfile="/opt/pihole/COL_TABLE" colfile="/opt/pihole/COL_TABLE"
source ${colfile} source ${colfile}
@ -132,7 +133,7 @@ ProcessDomainList() {
else else
RemoveDomain "${dom}" RemoveDomain "${dom}"
fi fi
done done
} }
AddDomain() { AddDomain() {
@ -144,19 +145,19 @@ AddDomain() {
requestedListname="$(GetListnameFromTypeId "${typeId}")" requestedListname="$(GetListnameFromTypeId "${typeId}")"
if [[ "${num}" -ne 0 ]]; then if [[ "${num}" -ne 0 ]]; then
existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")" existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
if [[ "${existingTypeId}" == "${typeId}" ]]; then if [[ "${existingTypeId}" == "${typeId}" ]]; then
if [[ "${verbose}" == true ]]; then if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!" echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
fi
else
existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
fi
fi fi
else return
existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
fi
fi
return
fi fi
# Domain not found in the table, add it! # Domain not found in the table, add it!
@ -184,10 +185,10 @@ RemoveDomain() {
requestedListname="$(GetListnameFromTypeId "${typeId}")" requestedListname="$(GetListnameFromTypeId "${typeId}")"
if [[ "${num}" -eq 0 ]]; then if [[ "${num}" -eq 0 ]]; then
if [[ "${verbose}" == true ]]; then if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!" echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
fi fi
return return
fi fi
# Domain found in the table, remove it! # Domain found in the table, remove it!
@ -242,21 +243,21 @@ Displaylist() {
NukeList() { NukeList() {
count=$(sqlite3 "${gravityDBfile}" "SELECT COUNT(1) FROM domainlist WHERE type = ${typeId};") count=$(sqlite3 "${gravityDBfile}" "SELECT COUNT(1) FROM domainlist WHERE type = ${typeId};")
listname="$(GetListnameFromTypeId "${typeId}")" listname="$(GetListnameFromTypeId "${typeId}")"
if [ "$count" -gt 0 ];then if [ "$count" -gt 0 ];then
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};" sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};"
echo " ${TICK} Removed ${count} domain(s) from the ${listname}" echo " ${TICK} Removed ${count} domain(s) from the ${listname}"
else else
echo " ${INFO} ${listname} already empty. Nothing to do!" echo " ${INFO} ${listname} already empty. Nothing to do!"
fi fi
exit 0; exit 0;
} }
GetComment() { GetComment() {
comment="$1" comment="$1"
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
echo " ${CROSS} Found invalid characters in domain comment!" echo " ${CROSS} Found invalid characters in domain comment!"
exit exit
fi fi
} }
@ -268,7 +269,7 @@ while (( "$#" )); do
"--white-wild" | "white-wild" ) typeId=2; wildcard=true;; "--white-wild" | "white-wild" ) typeId=2; wildcard=true;;
"--wild" | "wildcard" ) typeId=3; wildcard=true;; "--wild" | "wildcard" ) typeId=3; wildcard=true;;
"--regex" | "regex" ) typeId=3;; "--regex" | "regex" ) typeId=3;;
"-nr"| "--noreload" ) reload=false;; "-nr"| "--noreload" ) noReloadRequested=true;;
"-d" | "--delmode" ) addmode=false;; "-d" | "--delmode" ) addmode=false;;
"-q" | "--quiet" ) verbose=false;; "-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;; "-h" | "--help" ) helpFunc;;
@ -291,9 +292,9 @@ ProcessDomainList
# Used on web interface # Used on web interface
if $web; then if $web; then
echo "DONE" echo "DONE"
fi fi
if [[ "${reload}" != false ]]; then if [[ ${reload} == true && ${noReloadRequested} == false ]]; then
pihole restartdns reload-lists pihole restartdns reload-lists
fi fi

0
advanced/Scripts/piholeCheckout.sh Normal file → Executable file
View file

View file

@ -27,7 +27,7 @@ PIHOLE_COLTABLE_FILE="${PIHOLE_SCRIPTS_DIRECTORY}/COL_TABLE"
# These provide the colors we need for making the log more readable # These provide the colors we need for making the log more readable
if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then
source ${PIHOLE_COLTABLE_FILE} source ${PIHOLE_COLTABLE_FILE}
else else
COL_NC='\e[0m' # No Color COL_NC='\e[0m' # No Color
COL_RED='\e[1;91m' COL_RED='\e[1;91m'
@ -73,15 +73,12 @@ HTML_DIRECTORY="/var/www/html"
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin" WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
#BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole" #BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
SHM_DIRECTORY="/dev/shm" SHM_DIRECTORY="/dev/shm"
ETC="/etc"
# Files required by Pi-hole # Files required by Pi-hole
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 # https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
PIHOLE_CRON_FILE="${CRON_D_DIRECTORY}/pihole" 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_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf" WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
@ -136,6 +133,9 @@ PIHOLE_FTL_LOG="$(get_ftl_conf_value "LOGFILE" "${LOG_DIRECTORY}/pihole-FTL.log"
PIHOLE_WEB_SERVER_ACCESS_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/access.log" PIHOLE_WEB_SERVER_ACCESS_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/access.log"
PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.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 # 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 # We can loop through the array at any time to see if it matches a value
#SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") #SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
@ -160,9 +160,6 @@ PIHOLE_PROCESSES=( "lighttpd" "pihole-FTL" )
# Store the required directories in an array so it can be parsed through # Store the required directories in an array so it can be parsed through
REQUIRED_FILES=("${PIHOLE_CRON_FILE}" REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
"${PIHOLE_DNS_CONFIG_FILE}"
"${PIHOLE_DHCP_CONFIG_FILE}"
"${PIHOLE_WILDCARD_CONFIG_FILE}"
"${WEB_SERVER_CONFIG_FILE}" "${WEB_SERVER_CONFIG_FILE}"
"${WEB_SERVER_CUSTOM_CONFIG_FILE}" "${WEB_SERVER_CUSTOM_CONFIG_FILE}"
"${PIHOLE_INSTALL_LOG_FILE}" "${PIHOLE_INSTALL_LOG_FILE}"
@ -180,7 +177,9 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
"${PIHOLE_DEBUG_LOG}" "${PIHOLE_DEBUG_LOG}"
"${PIHOLE_FTL_LOG}" "${PIHOLE_FTL_LOG}"
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") "${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
"${RESOLVCONF}"
"${DNSMASQ_CONF}")
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net. DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
@ -586,6 +585,27 @@ processor_check() {
fi fi
} }
disk_usage() {
local file_system
local hide
echo_current_diagnostic "Disk usage"
mapfile -t file_system < <(df -h)
# Some lines of df might contain sensitive information like usernames and passwords.
# E.g. curlftpfs filesystems (https://www.looklinux.com/mount-ftp-share-on-linux-using-curlftps/)
# We are not interested in those lines so we collect keyword, to remove them from the output
# Additinal keywords can be added, separated by "|"
hide="curlftpfs"
# only show those lines not containg a sensitive phrase
for line in "${file_system[@]}"; do
if [[ ! $line =~ $hide ]]; then
log_write " ${line}"
fi
done
}
parse_setup_vars() { parse_setup_vars() {
echo_current_diagnostic "Setup variables" echo_current_diagnostic "Setup variables"
# If the file exists, # If the file exists,
@ -1074,12 +1094,16 @@ list_files_in_dir() {
elif [[ "${dir_to_parse}" == "${SHM_DIRECTORY}" ]]; then 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 # 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}")" log_write "$(ls -lhd "${dir_to_parse}"/"${each_file}")"
elif [[ "${dir_to_parse}" == "${DNSMASQ_D_DIRECTORY}" ]]; then
# in case of the dnsmasq directory inlcuede all files in the debug output
log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
make_array_from_file "${dir_to_parse}/${each_file}"
else else
# Then, parse the file's content into an array so each line can be analyzed if need be # Then, parse the file's content into an array so each line can be analyzed if need be
for i in "${!REQUIRED_FILES[@]}"; do for i in "${!REQUIRED_FILES[@]}"; do
if [[ "${dir_to_parse}/${each_file}" == "${REQUIRED_FILES[$i]}" ]]; then if [[ "${dir_to_parse}/${each_file}" == "${REQUIRED_FILES[$i]}" ]]; then
# display the filename # display the filename
log_write "\\n${COL_GREEN}$(ls -ld "${dir_to_parse}"/"${each_file}")${COL_NC}" log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
# Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing) # 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 case "${dir_to_parse}/${each_file}" in
# If it's Web server error log, give the first and last 25 lines # If it's Web server error log, give the first and last 25 lines
@ -1118,6 +1142,7 @@ show_content_of_pihole_files() {
show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}" show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}"
show_content_of_files_in_dir "${LOG_DIRECTORY}" show_content_of_files_in_dir "${LOG_DIRECTORY}"
show_content_of_files_in_dir "${SHM_DIRECTORY}" show_content_of_files_in_dir "${SHM_DIRECTORY}"
show_content_of_files_in_dir "${ETC}"
} }
head_tail_log() { head_tail_log() {
@ -1234,10 +1259,10 @@ show_messages() {
} }
analyze_gravity_list() { analyze_gravity_list() {
echo_current_diagnostic "Gravity List and Database" echo_current_diagnostic "Gravity Database"
local gravity_permissions local gravity_permissions
gravity_permissions=$(ls -ld "${PIHOLE_GRAVITY_DB_FILE}") gravity_permissions=$(ls -lhd "${PIHOLE_GRAVITY_DB_FILE}")
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}" log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
show_db_entries "Info table" "SELECT property,value FROM info" "20 40" show_db_entries "Info table" "SELECT property,value FROM info" "20 40"
@ -1316,7 +1341,7 @@ analyze_pihole_log() {
OLD_IFS="$IFS" OLD_IFS="$IFS"
# Get the lines that are in the file(s) and store them in an array for parsing later # Get the lines that are in the file(s) and store them in an array for parsing later
IFS=$'\r\n' IFS=$'\r\n'
pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}") pihole_log_permissions=$(ls -lhd "${PIHOLE_LOG}")
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}" log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG}) mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}" log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
@ -1333,11 +1358,15 @@ analyze_pihole_log() {
curl_to_tricorder() { curl_to_tricorder() {
# Users can submit their debug logs using curl (encrypted) # Users can submit their debug logs using curl (encrypted)
log_write " * Using ${COL_GREEN}curl${COL_NC} for transmission." log_write " * Using ${COL_GREEN}curl${COL_NC} for transmission."
# transmit he log via TLS and store the token returned in a variable # transmit the 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_token=$(curl --silent --fail --show-error --upload-file ${PIHOLE_DEBUG_LOG} https://tricorder.pi-hole.net 2>&1)
if [ -z "${tricorder_token}" ]; then if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
# curl failed, fallback to nc
log_write " * ${COL_GREEN}curl${COL_NC} failed, contact Pi-hole support for assistance." log_write " * ${COL_GREEN}curl${COL_NC} failed, contact Pi-hole support for assistance."
# Log curl error (if available)
if [ -n "${tricorder_token}" ]; then
log_write " * Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
tricorder_token=""
fi
fi fi
} }
@ -1382,15 +1411,14 @@ upload_to_tricorder() {
# Again, try to make this visually striking so the user realizes they need to do something with this information # 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 # Namely, provide the Pi-hole devs with the token
log_write "" log_write ""
log_write "${COL_PURPLE}***********************************${COL_NC}" log_write "${COL_PURPLE}*****************************************************************${COL_NC}"
log_write "${COL_PURPLE}***********************************${COL_NC}" log_write "${COL_PURPLE}*****************************************************************${COL_NC}\\n"
log_write "${TICK} Your debug token is: ${COL_GREEN}${tricorder_token}${COL_NC}" log_write "${TICK} Your debug token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
log_write "${INFO}${COL_RED} Logs are deleted 48 hours after upload.${COL_NC}" log_write "${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 ""
log_write " * Provide the token above to the Pi-hole team for assistance at" log_write " * Provide the token above to the Pi-hole team for assistance at ${FORUMS_URL}"
log_write " * ${FORUMS_URL}"
# If no token was generated # If no token was generated
else else
@ -1414,6 +1442,7 @@ diagnose_operating_system
check_selinux check_selinux
check_firewalld check_firewalld
processor_check processor_check
disk_usage
check_networking check_networking
check_name_resolution check_name_resolution
check_dhcp_servers check_dhcp_servers

View file

@ -21,7 +21,7 @@ matchType="match"
# Source pihole-FTL from install script # Source pihole-FTL from install script
pihole_FTL="${piholeDir}/pihole-FTL.conf" pihole_FTL="${piholeDir}/pihole-FTL.conf"
if [[ -f "${pihole_FTL}" ]]; then if [[ -f "${pihole_FTL}" ]]; then
source "${pihole_FTL}" source "${pihole_FTL}"
fi fi
# Set this only after sourcing pihole-FTL.conf as the gravity database path may # Set this only after sourcing pihole-FTL.conf as the gravity database path may
@ -48,7 +48,7 @@ scanList(){
# Iterate through each regexp and check whether it matches the domainQuery # Iterate through each regexp and check whether it matches the domainQuery
# If it does, print the matching regexp and continue looping # If it does, print the matching regexp and continue looping
# Input 1 - regexps | Input 2 - domainQuery # Input 1 - regexps | Input 2 - domainQuery
"regex" ) "regex" )
for list in ${lists}; do for list in ${lists}; do
if [[ "${domain}" =~ ${list} ]]; then if [[ "${domain}" =~ ${list} ]]; then
printf "%b\n" "${list}"; printf "%b\n" "${list}";
@ -109,15 +109,15 @@ scanDatabaseTable() {
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched # behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores. # as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
if [[ "${table}" == "gravity" ]]; then if [[ "${table}" == "gravity" ]]; then
case "${exact}" in case "${exact}" in
"exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";; "exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";; * ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
esac esac
else else
case "${exact}" in case "${exact}" in
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";; "exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";; * ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
esac esac
fi fi
# Send prepared query to gravity database # Send prepared query to gravity database
@ -128,8 +128,8 @@ scanDatabaseTable() {
fi fi
if [[ "${table}" == "gravity" ]]; then if [[ "${table}" == "gravity" ]]; then
echo "${result}" echo "${result}"
return return
fi fi
# Mark domain as having been white-/blacklist matched (global variable) # Mark domain as having been white-/blacklist matched (global variable)
@ -233,9 +233,9 @@ for result in "${results[@]}"; do
adlistAddress="${extra/|*/}" adlistAddress="${extra/|*/}"
extra="${extra#*|}" extra="${extra#*|}"
if [[ "${extra}" == "0" ]]; then if [[ "${extra}" == "0" ]]; then
extra="(disabled)" extra="(disabled)"
else else
extra="" extra=""
fi fi
if [[ -n "${blockpage}" ]]; then if [[ -n "${blockpage}" ]]; then

View file

@ -95,6 +95,10 @@ main() {
# shellcheck disable=1090,2154 # shellcheck disable=1090,2154
source "${setupVars}" 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 # This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!" echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
@ -196,7 +200,7 @@ main() {
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \ ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
echo -e "${basicError}" && exit 1 echo -e "${basicError}" && exit 1
fi fi
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then

View file

@ -118,7 +118,7 @@ getLocalBranch(){
local directory="${1}" local directory="${1}"
local branch local branch
# Local FTL btranch is stored in /etc/pihole/ftlbranch # Local FTL btranch is stored in /etc/pihole/ftlbranch
if [[ "$1" == "FTL" ]]; then if [[ "$1" == "FTL" ]]; then
branch="$(pihole-FTL branch)" branch="$(pihole-FTL branch)"
else else

View file

@ -54,7 +54,7 @@ add_setting() {
} }
delete_setting() { delete_setting() {
sed -i "/${1}/d" "${setupVars}" sed -i "/^${1}/d" "${setupVars}"
} }
change_setting() { change_setting() {
@ -67,7 +67,7 @@ addFTLsetting() {
} }
deleteFTLsetting() { deleteFTLsetting() {
sed -i "/${1}/d" "${FTLconf}" sed -i "/^${1}/d" "${FTLconf}"
} }
changeFTLsetting() { changeFTLsetting() {
@ -84,7 +84,7 @@ add_dnsmasq_setting() {
} }
delete_dnsmasq_setting() { delete_dnsmasq_setting() {
sed -i "/${1}/d" "${dnsmasqconfig}" sed -i "/^${1}/d" "${dnsmasqconfig}"
} }
SetTemperatureUnit() { SetTemperatureUnit() {
@ -122,14 +122,14 @@ SetWebPassword() {
read -s -r -p "Enter New Password (Blank for no password): " PASSWORD read -s -r -p "Enter New Password (Blank for no password): " PASSWORD
echo "" echo ""
if [ "${PASSWORD}" == "" ]; then if [ "${PASSWORD}" == "" ]; then
change_setting "WEBPASSWORD" "" change_setting "WEBPASSWORD" ""
echo -e " ${TICK} Password Removed" echo -e " ${TICK} Password Removed"
exit 0 exit 0
fi fi
read -s -r -p "Confirm Password: " CONFIRM read -s -r -p "Confirm Password: " CONFIRM
echo "" echo ""
fi fi
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
@ -247,8 +247,8 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
3 ) REV_SERVER_CIDR="${arrRev[0]}.0.0.0/8";; 3 ) REV_SERVER_CIDR="${arrRev[0]}.0.0.0/8";;
esac esac
else else
# Set REV_SERVER_CIDR to whatever value it was set to # Set REV_SERVER_CIDR to whatever value it was set to
REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}" REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}"
fi fi
# If REV_SERVER_CIDR is not converted by the above, then use the REV_SERVER_TARGET variable to derive it # If REV_SERVER_CIDR is not converted by the above, then use the REV_SERVER_TARGET variable to derive it
@ -267,11 +267,21 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
delete_setting "CONDITIONAL_FORWARDING_IP" delete_setting "CONDITIONAL_FORWARDING_IP"
fi fi
delete_dnsmasq_setting "rev-server"
if [[ "${REV_SERVER}" == true ]]; then if [[ "${REV_SERVER}" == true ]]; then
add_dnsmasq_setting "rev-server=${REV_SERVER_CIDR},${REV_SERVER_TARGET}" add_dnsmasq_setting "rev-server=${REV_SERVER_CIDR},${REV_SERVER_TARGET}"
if [ -n "${REV_SERVER_DOMAIN}" ]; then 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}" add_dnsmasq_setting "server=/${REV_SERVER_DOMAIN}/${REV_SERVER_TARGET}"
fi 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 fi
# We need to process DHCP settings here as well to account for possible # We need to process DHCP settings here as well to account for possible
@ -361,34 +371,34 @@ ProcessDHCPSettings() {
source "${setupVars}" source "${setupVars}"
if [[ "${DHCP_ACTIVE}" == "true" ]]; then if [[ "${DHCP_ACTIVE}" == "true" ]]; then
interface="${PIHOLE_INTERFACE}" interface="${PIHOLE_INTERFACE}"
# Use eth0 as fallback interface # Use eth0 as fallback interface
if [ -z ${interface} ]; then if [ -z ${interface} ]; then
interface="eth0" interface="eth0"
fi fi
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
PIHOLE_DOMAIN="lan" PIHOLE_DOMAIN="lan"
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
fi fi
if [[ "${DHCP_LEASETIME}" == "0" ]]; then if [[ "${DHCP_LEASETIME}" == "0" ]]; then
leasetime="infinite" leasetime="infinite"
elif [[ "${DHCP_LEASETIME}" == "" ]]; then elif [[ "${DHCP_LEASETIME}" == "" ]]; then
leasetime="24" leasetime="24"
change_setting "DHCP_LEASETIME" "${leasetime}" change_setting "DHCP_LEASETIME" "${leasetime}"
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
#Installation is affected by known bug, introduced in a previous version. #Installation is affected by known bug, introduced in a previous version.
#This will automatically clean up setupVars.conf and remove the unnecessary "h" #This will automatically clean up setupVars.conf and remove the unnecessary "h"
leasetime="24" leasetime="24"
change_setting "DHCP_LEASETIME" "${leasetime}" change_setting "DHCP_LEASETIME" "${leasetime}"
else else
leasetime="${DHCP_LEASETIME}h" leasetime="${DHCP_LEASETIME}h"
fi fi
# Write settings to file # Write settings to file
echo "############################################################################### echo "###############################################################################
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. # # DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE # # ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
############################################################################### ###############################################################################
@ -398,34 +408,34 @@ dhcp-option=option:router,${DHCP_ROUTER}
dhcp-leasefile=/etc/pihole/dhcp.leases dhcp-leasefile=/etc/pihole/dhcp.leases
#quiet-dhcp #quiet-dhcp
" > "${dhcpconfig}" " > "${dhcpconfig}"
chmod 644 "${dhcpconfig}" chmod 644 "${dhcpconfig}"
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
# When there is a Pi-hole domain set and "Never forward non-FQDNs" is # When there is a Pi-hole domain set and "Never forward non-FQDNs" is
# ticked, we add `local=/domain/` to tell FTL that this domain is purely # ticked, we add `local=/domain/` to tell FTL that this domain is purely
# local and FTL may answer queries from /etc/hosts or DHCP but should # local and FTL may answer queries from /etc/hosts or DHCP but should
# never forward queries on that domain to any upstream servers # never forward queries on that domain to any upstream servers
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}" echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}"
fi
fi fi
fi
# Sourced from setupVars # Sourced from setupVars
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [[ "${DHCP_rapid_commit}" == "true" ]]; then if [[ "${DHCP_rapid_commit}" == "true" ]]; then
echo "dhcp-rapid-commit" >> "${dhcpconfig}" echo "dhcp-rapid-commit" >> "${dhcpconfig}"
fi fi
if [[ "${DHCP_IPv6}" == "true" ]]; then if [[ "${DHCP_IPv6}" == "true" ]]; then
echo "#quiet-dhcp6 echo "#quiet-dhcp6
#enable-ra #enable-ra
dhcp-option=option6:dns-server,[::] 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,64,3600
ra-param=*,0,0 ra-param=*,0,0
" >> "${dhcpconfig}" " >> "${dhcpconfig}"
fi fi
else else
if [[ -f "${dhcpconfig}" ]]; then if [[ -f "${dhcpconfig}" ]]; then
@ -522,25 +532,6 @@ CustomizeAdLists() {
fi fi
} }
SetPrivacyMode() {
if [[ "${args[2]}" == "true" ]]; then
change_setting "API_PRIVACY_MODE" "true"
else
change_setting "API_PRIVACY_MODE" "false"
fi
}
ResolutionSettings() {
typ="${args[2]}"
state="${args[3]}"
if [[ "${typ}" == "forward" ]]; then
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
elif [[ "${typ}" == "clients" ]]; then
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
fi
}
AddDHCPStaticAddress() { AddDHCPStaticAddress() {
mac="${args[2]}" mac="${args[2]}"
ip="${args[3]}" ip="${args[3]}"
@ -614,7 +605,7 @@ Interfaces:
single Listen only on ${PIHOLE_INTERFACE} interface single Listen only on ${PIHOLE_INTERFACE} interface
all Listen on all interfaces, permit all origins" all Listen on all interfaces, permit all origins"
exit 0 exit 0
fi fi
if [[ "${args[2]}" == "all" ]]; then if [[ "${args[2]}" == "all" ]]; then
echo -e " ${INFO} Listening on all interfaces, permitting all origins. Please use a firewall!" echo -e " ${INFO} Listening on all interfaces, permitting all origins. Please use a firewall!"
@ -663,18 +654,18 @@ addAudit()
domains="" domains=""
for domain in "$@" for domain in "$@"
do do
# Check domain to be added. Only continue if it is valid # Check domain to be added. Only continue if it is valid
validDomain="$(checkDomain "${domain}")" validDomain="$(checkDomain "${domain}")"
if [[ -n "${validDomain}" ]]; then if [[ -n "${validDomain}" ]]; then
# Put comma in between domains when there is # Put comma in between domains when there is
# more than one domains to be added # more than one domains to be added
# SQL INSERT allows adding multiple rows at once using the format # SQL INSERT allows adding multiple rows at once using the format
## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st'); ## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
if [[ -n "${domains}" ]]; then if [[ -n "${domains}" ]]; then
domains="${domains}," domains="${domains},"
fi
domains="${domains}('${domain}')"
fi fi
domains="${domains}('${domain}')"
fi
done done
# Insert only the domain here. The date_added field will be # Insert only the domain here. The date_added field will be
# filled with its default value (date_added = current timestamp) # filled with its default value (date_added = current timestamp)
@ -699,10 +690,25 @@ AddCustomDNSAddress() {
ip="${args[2]}" ip="${args[2]}"
host="${args[3]}" host="${args[3]}"
echo "${ip} ${host}" >> "${dnscustomfile}" reload="${args[4]}"
# Restart dnsmasq to load new custom DNS entries validHost="$(checkDomain "${host}")"
RestartDNS if [[ -n "${validHost}" ]]; then
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
echo "${ip} ${validHost}" >> "${dnscustomfile}"
else
echo -e " ${CROSS} Invalid IP has been passed"
exit 1
fi
else
echo " ${CROSS} Invalid Domain passed!"
exit 1
fi
# Restart dnsmasq to load new custom DNS entries only if $reload not false
if [[ ! $reload == "false" ]]; then
RestartDNS
fi
} }
RemoveCustomDNSAddress() { RemoveCustomDNSAddress() {
@ -710,16 +716,25 @@ RemoveCustomDNSAddress() {
ip="${args[2]}" ip="${args[2]}"
host="${args[3]}" host="${args[3]}"
reload="${args[4]}"
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then validHost="$(checkDomain "${host}")"
sed -i "/^${ip} ${host}$/d" "${dnscustomfile}" if [[ -n "${validHost}" ]]; then
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
sed -i "/^${ip} ${validHost}$/d" "${dnscustomfile}"
else
echo -e " ${CROSS} Invalid IP has been passed"
exit 1
fi
else else
echo -e " ${CROSS} Invalid IP has been passed" echo " ${CROSS} Invalid Domain passed!"
exit 1 exit 1
fi fi
# Restart dnsmasq to update removed custom DNS entries # Restart dnsmasq to load new custom DNS entries only if reload is not false
RestartDNS if [[ ! $reload == "false" ]]; then
RestartDNS
fi
} }
AddCustomCNAMERecord() { AddCustomCNAMERecord() {
@ -727,11 +742,25 @@ AddCustomCNAMERecord() {
domain="${args[2]}" domain="${args[2]}"
target="${args[3]}" target="${args[3]}"
reload="${args[4]}"
echo "cname=${domain},${target}" >> "${dnscustomcnamefile}" validDomain="$(checkDomain "${domain}")"
if [[ -n "${validDomain}" ]]; then
# Restart dnsmasq to load new custom CNAME records validTarget="$(checkDomain "${target}")"
RestartDNS if [[ -n "${validTarget}" ]]; then
echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
else
echo " ${CROSS} Invalid Target Passed!"
exit 1
fi
else
echo " ${CROSS} Invalid Domain passed!"
exit 1
fi
# Restart dnsmasq to load new custom CNAME records only if reload is not false
if [[ ! $reload == "false" ]]; then
RestartDNS
fi
} }
RemoveCustomCNAMERecord() { RemoveCustomCNAMERecord() {
@ -739,11 +768,12 @@ RemoveCustomCNAMERecord() {
domain="${args[2]}" domain="${args[2]}"
target="${args[3]}" target="${args[3]}"
reload="${args[4]}"
validDomain="$(checkDomain "${domain}")" validDomain="$(checkDomain "${domain}")"
if [[ -n "${validDomain}" ]]; then if [[ -n "${validDomain}" ]]; then
validTarget="$(checkDomain "${target}")" validTarget="$(checkDomain "${target}")"
if [[ -n "${validDomain}" ]]; then if [[ -n "${validTarget}" ]]; then
sed -i "/cname=${validDomain},${validTarget}$/d" "${dnscustomcnamefile}" sed -i "/cname=${validDomain},${validTarget}$/d" "${dnscustomcnamefile}"
else else
echo " ${CROSS} Invalid Target Passed!" echo " ${CROSS} Invalid Target Passed!"
@ -754,8 +784,10 @@ RemoveCustomCNAMERecord() {
exit 1 exit 1
fi fi
# Restart dnsmasq to update removed custom CNAME records # Restart dnsmasq to update removed custom CNAME records only if $reload not false
RestartDNS if [[ ! $reload == "false" ]]; then
RestartDNS
fi
} }
main() { main() {
@ -778,8 +810,6 @@ main() {
"layout" ) SetWebUILayout;; "layout" ) SetWebUILayout;;
"theme" ) SetWebUITheme;; "theme" ) SetWebUITheme;;
"-h" | "--help" ) helpFunc;; "-h" | "--help" ) helpFunc;;
"privacymode" ) SetPrivacyMode;;
"resolve" ) ResolutionSettings;;
"addstaticdhcp" ) AddDHCPStaticAddress;; "addstaticdhcp" ) AddDHCPStaticAddress;;
"removestaticdhcp" ) RemoveDHCPStaticAddress;; "removestaticdhcp" ) RemoveDHCPStaticAddress;;
"-e" | "email" ) SetAdminEmail "$3";; "-e" | "email" ) SetAdminEmail "$3";;

View file

@ -1,28 +0,0 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Provides an automated migration subroutine to convert Pi-hole v3.x wildcard domains to Pi-hole v4.x regex filters
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# regexFile set in gravity.sh
wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
convert_wildcard_to_regex() {
if [ ! -f "${wildcardFile}" ]; then
return
fi
local addrlines domains uniquedomains
# Obtain wildcard domains from old file
addrlines="$(grep -oE "/.*/" ${wildcardFile})"
# Strip "/" from domain names and convert "." to regex-compatible "\."
domains="$(sed 's/\///g;s/\./\\./g' <<< "${addrlines}")"
# Remove repeated domains (may have been inserted two times due to A and AAAA blocking)
uniquedomains="$(uniq <<< "${domains}")"
# Automatically generate regex filters and remove old wildcards file
awk '{print "(^|\\.)"$0"$"}' <<< "${uniquedomains}" >> "${regexFile:?}" && rm "${wildcardFile}"
}

View file

@ -57,7 +57,7 @@ CREATE TABLE info
value TEXT NOT NULL value TEXT NOT NULL
); );
INSERT INTO "info" VALUES('version','14'); INSERT INTO "info" VALUES('version','15');
CREATE TABLE domain_audit CREATE TABLE domain_audit
( (
@ -143,12 +143,10 @@ CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1); WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1);
CREATE VIEW vw_adlist AS SELECT DISTINCT address, adlist.id AS id CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
FROM adlist FROM adlist
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id WHERE enabled = 1
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id ORDER BY id;
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1)
ORDER BY adlist.id;
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
BEGIN BEGIN

View file

@ -24,10 +24,14 @@ start() {
touch /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases touch /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
# Ensure that permissions are set so that pihole-FTL can edit all necessary files # 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 chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases /run/pihole /etc/pihole
chmod 0644 /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases /etc/pihole/macvendor.db chmod 0644 /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
# Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist
chmod -f 0644 /etc/pihole/macvendor.db
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist # Chown 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 chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE+eip "/usr/bin/pihole-FTL"; then # Chown database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist
chmod -f 0664 /etc/pihole/pihole-FTL.db
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
else else
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system" echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"

View file

@ -78,11 +78,6 @@ $HTTP["url"] =~ "^/admin/" {
"X-Pi-hole" => "The Pi-hole Web interface is working!", "X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY" "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 # Block . files from being served, such as .git, .github, .gitignore
@ -90,5 +85,12 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("") url.access-deny = ("")
} }
# allow teleporter iframe on settings page
$HTTP["url"] =~ "/teleporter\.php$" {
$HTTP["referer"] =~ "/admin/settings\.php" {
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
}
}
# Default expire header # Default expire header
expire.url = ( "" => "access plus 0 seconds" ) expire.url = ( "" => "access plus 0 seconds" )

View file

@ -86,11 +86,6 @@ $HTTP["url"] =~ "^/admin/" {
"X-Pi-hole" => "The Pi-hole Web interface is working!", "X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY" "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 # Block . files from being served, such as .git, .github, .gitignore
@ -98,5 +93,12 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("") url.access-deny = ("")
} }
# allow teleporter iframe on settings page
$HTTP["url"] =~ "/teleporter\.php$" {
$HTTP["referer"] =~ "/admin/settings\.php" {
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
}
}
# Default expire header # Default expire header
expire.url = ( "" => "access plus 0 seconds" ) expire.url = ( "" => "access plus 0 seconds" )

View file

@ -34,27 +34,26 @@ export PATH+=':/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
# List of supported DNS servers # List of supported DNS servers
DNS_SERVERS=$(cat << EOM DNS_SERVERS=$(cat << EOM
Google (ECS);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844 Google (ECS, DNSSEC);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844
OpenDNS (ECS, DNSSEC);208.67.222.222;208.67.220.220;2620:119:35::35;2620:119:53::53 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;; Level3;4.2.2.1;4.2.2.2;;
Comodo;8.26.56.26;8.20.247.20;; Comodo;8.26.56.26;8.20.247.20;;
DNS.WATCH;84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b DNS.WATCH (DNSSEC);84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b
Quad9 (filtered, DNSSEC);9.9.9.9;149.112.112.112;2620:fe::fe;2620:fe::9 Quad9 (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 (unfiltered, no DNSSEC);9.9.9.10;149.112.112.10;2620:fe::10;2620:fe::fe:10
Quad9 (filtered + ECS);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11 Quad9 (filtered, ECS, DNSSEC);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 Cloudflare (DNSSEC);1.1.1.1;1.0.0.1;2606:4700:4700::1111;2606:4700:4700::1001
EOM EOM
) )
# Location for final installation log storage # 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 # 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 # Pi-hole uses lighttpd as a Web server, and this is the config file for it
# shellcheck disable=SC2034 lighttpdConfig="/etc/lighttpd/lighttpd.conf"
lighttpdConfig=/etc/lighttpd/lighttpd.conf
# This is a file used for the colorized output # This is a file used for the colorized output
coltable=/opt/pihole/COL_TABLE coltable="/opt/pihole/COL_TABLE"
# Root of the web server # Root of the web server
webroot="/var/www/html" webroot="/var/www/html"
@ -77,7 +76,7 @@ PI_HOLE_CONFIG_DIR="/etc/pihole"
PI_HOLE_BIN_DIR="/usr/local/bin" PI_HOLE_BIN_DIR="/usr/local/bin"
PI_HOLE_BLOCKPAGE_DIR="${webroot}/pihole" PI_HOLE_BLOCKPAGE_DIR="${webroot}/pihole"
if [ -z "$useUpdateVars" ]; then if [ -z "$useUpdateVars" ]; then
useUpdateVars=false useUpdateVars=false
fi fi
adlistFile="/etc/pihole/adlists.list" adlistFile="/etc/pihole/adlists.list"
@ -91,27 +90,12 @@ PRIVACY_LEVEL=0
CACHE_SIZE=10000 CACHE_SIZE=10000
if [ -z "${USER}" ]; then if [ -z "${USER}" ]; then
USER="$(id -un)" USER="$(id -un)"
fi fi
# whiptail dialog dimensions: 20 rows and 70 chars width assures to fit on small screens and is known to hold all content.
# Check if we are running on a real terminal and find the rows and columns r=20
# If there is no real terminal, we will default to 80x24 c=70
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 ######## ######## Undocumented Flags. Shhh ########
# These are undocumented flags; some of which we can use when repairing an installation # These are undocumented flags; some of which we can use when repairing an installation
@ -149,7 +133,7 @@ fi
# A simple function that just echoes out our logo in ASCII format # A simple function that just echoes out our logo in ASCII format
# This lets users know that it is a Pi-hole, LLC product # This lets users know that it is a Pi-hole, LLC product
show_ascii_berry() { show_ascii_berry() {
echo -e " echo -e "
${COL_LIGHT_GREEN}.;;,. ${COL_LIGHT_GREEN}.;;,.
.ccccc:,. .ccccc:,.
:cccclll:. ..,, :cccclll:. ..,,
@ -277,123 +261,93 @@ os_check() {
# Compatibility # Compatibility
package_manager_detect() { package_manager_detect() {
# If apt-get is installed, then we know it's part of the Debian family # First check to see if apt-get is installed.
if is_command apt-get ; then if is_command apt-get ; then
# Set some global variables here # Set some global variables here
# We don't set them earlier since the family might be Red Hat, so these values would be different # We don't set them earlier since the installed package manager might be rpm, so these values would be different
PKG_MANAGER="apt-get" PKG_MANAGER="apt-get"
# A variable to store the command used to update the package cache # A variable to store the command used to update the package cache
UPDATE_PKG_CACHE="${PKG_MANAGER} update" UPDATE_PKG_CACHE="${PKG_MANAGER} update"
# The command we will use to actually install packages # The command we will use to actually install packages
PKG_INSTALL=("${PKG_MANAGER}" -qq --no-install-recommends install) 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. # 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" PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
# Update package cache. This is required already here to assure apt-cache calls have package lists available. # Update package cache
update_package_cache || exit 1 update_package_cache || exit 1
# Debian 7 doesn't have iproute2 so check if it's available first # Check for and determine version number (major and minor) of current php install
if apt-cache show iproute2 > /dev/null 2>&1; then local phpVer="php"
iproute_pkg="iproute2" if is_command php ; then
# Otherwise, check if iproute is available printf " %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "$(php <<< "<?php echo PHP_VERSION ?>")"
elif apt-cache show iproute > /dev/null 2>&1; then printf -v phpInsMajor "%d" "$(php <<< "<?php echo PHP_MAJOR_VERSION ?>")"
iproute_pkg="iproute" printf -v phpInsMinor "%d" "$(php <<< "<?php echo PHP_MINOR_VERSION ?>")"
# Else print error and exit phpVer="php$phpInsMajor.$phpInsMinor"
else
printf " %b Aborting installation: iproute2 and iproute packages were not found in APT repository.\\n" "${CROSS}"
exit 1
fi
# Check for and determine version number (major and minor) of current php install
if is_command php ; then
printf " %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "$(php <<< "<?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
fi # Packages required to perfom the os_check (stored as an array)
# Several other packages depend on the version of PHP. If PHP is not installed, or an insufficient version, OS_CHECK_DEPS=(grep dnsutils)
# those packages should fall back to the default (latest?) # Packages required to run this install script (stored as an array)
if [[ "$phpInsNewer" != true ]]; then INSTALLER_DEPS=(git iproute2 whiptail ca-certificates)
# Prefer the php metapackage if it's there # Packages required to run Pi-hole (stored as an array)
if apt-cache show php > /dev/null 2>&1; then PIHOLE_DEPS=(cron curl iputils-ping lsof psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2)
phpVer="php" # Packages required for the Web admin interface (stored as an array)
# Else fall back on the php5 package if it's there # It's useful to separate this from Pi-hole, since the two repos are also setup separately
elif apt-cache show php5 > /dev/null 2>&1; then PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-sqlite3" "${phpVer}-xml" "${phpVer}-intl")
phpVer="php5" # Prior to PHP8.0, JSON functionality is provided as dedicated module, required by Pi-hole AdminLTE: https://www.php.net/manual/json.installation.php
# Else print error and exit if [[ -z "${phpInsMajor}" || "${phpInsMajor}" -lt 8 ]]; then
PIHOLE_WEB_DEPS+=("${phpVer}-json")
fi
# The Web server user,
LIGHTTPD_USER="www-data"
# group,
LIGHTTPD_GROUP="www-data"
# and config file
LIGHTTPD_CFG="lighttpd.conf.debian"
# This function waits for dpkg to unlock, which signals that the previous apt-get command has finished.
test_dpkg_lock() {
i=0
# fuser is a program to show which processes use the named files, sockets, or filesystems
# So while the lock is held,
while fuser /var/lib/dpkg/lock >/dev/null 2>&1
do
# we wait half a second,
sleep 0.5
# increase the iterator,
((i=i+1))
done
# and then report success once dpkg is unlocked.
return 0
}
# If apt-get is not found, check for rpm.
elif is_command rpm ; then
# Then check if dnf or yum is the package manager
if is_command dnf ; then
PKG_MANAGER="dnf"
else else
printf " %b Aborting installation: No PHP packages were found in APT repository.\\n" "${CROSS}" PKG_MANAGER="yum"
exit 1
fi fi
else
# Else, PHP is already installed at a version beyond v7.0, so the additional packages
# should match version with the current PHP version.
phpVer="php$phpInsMajor.$phpInsMinor"
fi
# We also need the correct version for `php-sqlite` (which differs across distros)
if apt-cache show "${phpVer}-sqlite3" > /dev/null 2>&1; then
phpSqlite="sqlite3"
elif apt-cache show "${phpVer}-sqlite" > /dev/null 2>&1; then
phpSqlite="sqlite"
else
printf " %b Aborting installation: No SQLite PHP module was found in APT repository.\\n" "${CROSS}"
exit 1
fi
# Packages required to perfom the os_check (stored as an array)
OS_CHECK_DEPS=(grep dnsutils)
# Packages required to run this install script (stored as an array)
INSTALLER_DEPS=(git "${iproute_pkg}" whiptail)
# Packages required to run Pi-hole (stored as an array)
PIHOLE_DEPS=(cron curl iputils-ping lsof netcat psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2)
# Packages required for the Web admin interface (stored as an array)
# It's useful to separate this from Pi-hole, since the two repos are also setup separately
PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-${phpSqlite}" "${phpVer}-xml" "${phpVer}-intl")
# Prior to PHP8.0, JSON functionality is provided as dedicated module, required by Pi-hole AdminLTE: https://www.php.net/manual/json.installation.php
if [[ "${phpInsNewer}" != true || "${phpInsMajor}" -lt 8 ]]; then
PIHOLE_WEB_DEPS+=("${phpVer}-json")
fi
# The Web server user,
LIGHTTPD_USER="www-data"
# group,
LIGHTTPD_GROUP="www-data"
# and config file
LIGHTTPD_CFG="lighttpd.conf.debian"
# This function waits for dpkg to unlock, which signals that the previous apt-get command has finished. # These variable names match the ones for apt-get. See above for an explanation of what they are for.
test_dpkg_lock() { PKG_INSTALL=("${PKG_MANAGER}" install -y)
i=0 PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
# fuser is a program to show which processes use the named files, sockets, or filesystems OS_CHECK_DEPS=(grep bind-utils)
# So while the lock is held, INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig ca-certificates)
while fuser /var/lib/dpkg/lock >/dev/null 2>&1 PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc sqlite libcap lsof)
do PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl)
# we wait half a second, LIGHTTPD_USER="lighttpd"
sleep 0.5 LIGHTTPD_GROUP="lighttpd"
# increase the iterator, LIGHTTPD_CFG="lighttpd.conf.fedora"
((i=i+1))
done
# and then report success once dpkg is unlocked.
return 0
}
# If apt-get is not found, check for rpm to see if it's a Red Hat family OS # If neither apt-get or yum/dnf package managers were found
elif is_command rpm ; then
# Then check if dnf or yum is the package manager
if is_command dnf ; then
PKG_MANAGER="dnf"
else else
PKG_MANAGER="yum" # we cannot install required packages
printf " %b No supported package manager found\\n" "${CROSS}"
# so exit the installer
exit
fi fi
}
# These variable names match the ones in the Debian family. See above for an explanation of what they are for. select_rpm_php(){
PKG_INSTALL=("${PKG_MANAGER}" install -y)
PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
OS_CHECK_DEPS=(grep bind-utils)
INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig)
PIHOLE_DEPS=(cronie curl findutils nmap-ncat sudo unzip libidn2 psmisc sqlite libcap lsof)
PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl)
LIGHTTPD_USER="lighttpd"
LIGHTTPD_GROUP="lighttpd"
LIGHTTPD_CFG="lighttpd.conf.fedora"
# If the host OS is Fedora, # If the host OS is Fedora,
if grep -qiE 'fedora|fedberry' /etc/redhat-release; then if grep -qiE 'fedora|fedberry' /etc/redhat-release; then
# all required packages should be available by default with the latest fedora release # all required packages should be available by default with the latest fedora release
@ -445,46 +399,36 @@ elif is_command rpm ; then
REMI_PKG="remi-release" REMI_PKG="remi-release"
REMI_REPO="remi-php72" REMI_REPO="remi-php72"
rpm -q ${REMI_PKG} &> /dev/null || rc=$? rpm -q ${REMI_PKG} &> /dev/null || rc=$?
if [[ $rc -ne 0 ]]; then if [[ $rc -ne 0 ]]; then
# The PHP version available via default repositories is older than version 7 # 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 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 # 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}" printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
: # continue with unsupported php version : # 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 else
printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}" printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
exit 1 "${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 # 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 fi
fi fi
else
# Warn user of unsupported version of Fedora or CentOS
if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" "${r}" "${c}"; then
printf " %b Aborting installation due to unsupported RPM based distribution\\n" "${CROSS}"
exit
else
printf " %b Continuing installation with unsupported RPM based distribution\\n" "${INFO}"
fi
fi
# If neither apt-get or yum/dnf package managers were found
else
# it's not an OS we can support,
printf " %b OS distribution not supported\\n" "${CROSS}"
# so exit the installer
exit
fi
} }
# A function for checking if a directory is a git repository # A function for checking if a directory is a git repository
@ -570,12 +514,12 @@ update_repo() {
git stash --all --quiet &> /dev/null || true # Okay for stash failure git stash --all --quiet &> /dev/null || true # Okay for stash failure
git clean --quiet --force -d || true # Okay for already clean directory git clean --quiet --force -d || true # Okay for already clean directory
# Pull the latest commits # Pull the latest commits
git pull --quiet &> /dev/null || return $? git pull --no-rebase --quiet &> /dev/null || return $?
# Check current branch. If it is master, then reset to the latest available tag. # 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) # 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) curBranch=$(git rev-parse --abbrev-ref HEAD)
if [[ "${curBranch}" == "master" ]]; then if [[ "${curBranch}" == "master" ]]; then
git reset --hard "$(git describe --abbrev=0 --tags)" || return $? git reset --hard "$(git describe --abbrev=0 --tags)" || return $?
fi fi
# Show a completion message # Show a completion message
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
@ -685,12 +629,12 @@ welcomeDialogs() {
IMPORTANT: If you have not already done so, you must ensure that this device has a static IP. Either through DHCP reservation, or by manually assigning one. Depending on your operating system, there are many ways to achieve this. 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 Choose yes to indicate that you have understood this message, and wish to continue" "${r}" "${c}"; then
#Nothing to do, continue #Nothing to do, continue
echo echo
else else
printf " %b Installer exited at static IP message.\\n" "${INFO}" printf " %b Installer exited at static IP message.\\n" "${INFO}"
exit 1 exit 1
fi fi
} }
# A function that lets the user pick an interface to use with Pi-hole # A function that lets the user pick an interface to use with Pi-hole
@ -730,7 +674,7 @@ chooseInterface() {
# Feed the available interfaces into this while loop # Feed the available interfaces into this while loop
done <<< "${availableInterfaces}" done <<< "${availableInterfaces}"
# The whiptail command that will be run, stored in a variable # The whiptail command that will be run, stored in a variable
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" "${interfaceCount}") chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" 6)
# Now run the command using the interfaces saved into the array # Now run the command using the interfaces saved into the array
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \ chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
# If the user chooses Cancel, exit # If the user chooses Cancel, exit
@ -772,9 +716,8 @@ testIPv6() {
fi fi
} }
# A dialog for showing the user about IPv6 blocking find_IPv6_information() {
useIPv6dialog() { # Detects IPv6 address used for communication to WAN addresses.
# Determine the IPv6 address used for blocking
IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}')) 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 # For each address in the array above, determine the type of IPv6 address it is
@ -794,122 +737,91 @@ useIPv6dialog() {
# set the IPv6 address to the ULA address # set the IPv6 address to the ULA address
IPV6_ADDRESS="${ULA_ADDRESS}" IPV6_ADDRESS="${ULA_ADDRESS}"
# Show this info to the user # Show this info to the user
printf " %b Found IPv6 ULA address, using it for blocking IPv6 ads\\n" "${INFO}" printf " %b Found IPv6 ULA address\\n" "${INFO}"
# Otherwise, if the GUA_ADDRESS has a value, # Otherwise, if the GUA_ADDRESS has a value,
elif [[ ! -z "${GUA_ADDRESS}" ]]; then elif [[ ! -z "${GUA_ADDRESS}" ]]; then
# Let the user know # Let the user know
printf " %b Found IPv6 GUA address, using it for blocking IPv6 ads\\n" "${INFO}" printf " %b Found IPv6 GUA address\\n" "${INFO}"
# And assign it to the global variable # And assign it to the global variable
IPV6_ADDRESS="${GUA_ADDRESS}" IPV6_ADDRESS="${GUA_ADDRESS}"
# If none of those work, # If none of those work,
else else
# explain that IPv6 blocking will not be used printf " %b Unable to find IPv6 ULA/GUA address\\n" "${INFO}"
printf " %b Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled\\n" "${INFO}"
# So set the variable to be empty # So set the variable to be empty
IPV6_ADDRESS="" IPV6_ADDRESS=""
fi fi
# If the IPV6_ADDRESS contains a value
if [[ ! -z "${IPV6_ADDRESS}" ]]; then
# Display that IPv6 is supported and will be used
whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." "${r}" "${c}"
fi
} }
# A function to check if we should use IPv4 and/or IPv6 for blocking ads # A function to collect IPv4 and IPv6 information of the device
use4andor6() { collect_v4andv6_information() {
# Named local variables find_IPv4_information
local useIPv4
local useIPv6
# Let user choose IPv4 and/or IPv6 via a checklist
cmd=(whiptail --separate-output --checklist "Select Protocols (press space to toggle selection)" "${r}" "${c}" 2)
# In an array, show the options available:
# IPv4 (on by default)
options=(IPv4 "Block ads over IPv4" on
# or IPv6 (on by default if available)
IPv6 "Block ads over IPv6" on)
# In a variable, show the choices available; exit if Cancel is selected
choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
# For each choice available,
for choice in ${choices}
do
# Set the values to true
case ${choice} in
IPv4 ) useIPv4=true;;
IPv6 ) useIPv6=true;;
esac
done
# If IPv4 is to be used,
if [[ "${useIPv4}" ]]; then
# Run our function to get the information we need
find_IPv4_information
if [[ -f "/etc/dhcpcd.conf" ]]; then
# configure networking via dhcpcd
getStaticIPv4Settings
setDHCPCD
fi
fi
# If IPv6 is to be used,
if [[ "${useIPv6}" ]]; then
# Run our function to get this information
useIPv6dialog
fi
# Echo the information to the user # Echo the information to the user
printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}" printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}" # if `dhcpcd` is used offer to set this as static IP for the device
# If neither protocol is selected, if [[ -f "/etc/dhcpcd.conf" ]]; then
if [[ ! "${useIPv4}" ]] && [[ ! "${useIPv6}" ]]; then # configure networking via dhcpcd
# Show an error in red getStaticIPv4Settings
printf " %bError: Neither IPv4 or IPv6 selected%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
# and exit with an error
exit 1
fi fi
find_IPv6_information
printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
} }
getStaticIPv4Settings() { getStaticIPv4Settings() {
# Local, named variables # Local, named variables
local ipSettingsCorrect local ipSettingsCorrect
local DHCPChoice
# Ask if the user wants to use DHCP settings as their static IP # Ask if the user wants to use DHCP settings as their static IP
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions # This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address? DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n
IP address: ${IPV4_ADDRESS} IP address: ${IPV4_ADDRESS} \\n
Gateway: ${IPv4gw}" "${r}" "${c}"; then Gateway: ${IPv4gw} \\n" "${r}" "${c}" 3\
"Yes" "Set static IP using current values" \
"No" "Set static IP using custom values" \
"Skip" "I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3) || \
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
case ${DHCPChoice} in
"Yes")
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict. # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that. whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}" It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
# Nothing else to do since the variables are already set above # Nothing else to do since the variables are already set above
else setDHCPCD
# Otherwise, we need to ask the user to input their desired settings. ;;
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
until [[ "${ipSettingsCorrect}" = True ]]; do
# Ask for the IPv4 address "No")
IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" "${r}" "${c}" "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \ # Otherwise, we need to ask the user to input their desired settings.
# Canceling IPv4 settings window # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
{ ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; } # Start a loop to let the user enter their information with the chance to go back and edit it if necessary
printf " %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}" until [[ "${ipSettingsCorrect}" = True ]]; do
# Ask for the gateway # Ask for the IPv4 address
IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" "${r}" "${c}" "${IPv4gw}" 3>&1 1>&2 2>&3) || \ IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" "${r}" "${c}" "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \
# Canceling gateway settings window # Canceling IPv4 settings window
{ ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; } { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
printf " %b Your static IPv4 gateway: %s\\n" "${INFO}" "${IPv4gw}" printf " %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
# Give the user a chance to review their settings before moving on # Ask for the gateway
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct? IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" "${r}" "${c}" "${IPv4gw}" 3>&1 1>&2 2>&3) || \
IP address: ${IPV4_ADDRESS} # Canceling gateway settings window
Gateway: ${IPv4gw}" "${r}" "${c}"; then { ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
# After that's done, the loop ends and we move on printf " %b Your static IPv4 gateway: %s\\n" "${INFO}" "${IPv4gw}"
ipSettingsCorrect=True
else # Give the user a chance to review their settings before moving on
# If the settings are wrong, the loop continues if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
ipSettingsCorrect=False IP address: ${IPV4_ADDRESS}
fi Gateway: ${IPv4gw}" "${r}" "${c}"; then
done # After that's done, the loop ends and we move on
# End the if statement for DHCP vs. static ipSettingsCorrect=True
fi else
# If the settings are wrong, the loop continues
ipSettingsCorrect=False
fi
done
setDHCPCD
;;
esac
} }
# Configure networking via dhcpcd # Configure networking via dhcpcd
@ -1001,8 +913,8 @@ setDNS() {
IFS=${OIFS} IFS=${OIFS}
# In a whiptail dialog, show the options # In a whiptail dialog, show the options
DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." "${r}" "${c}" 7 \ DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." "${r}" "${c}" 7 \
"${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \ "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
# Exit if the user selects "Cancel" # Exit if the user selects "Cancel"
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; } { printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
# Depending on the user's choice, set the GLOBAL variables to the IP of the respective provider # Depending on the user's choice, set the GLOBAL variables to the IP of the respective provider
@ -1247,8 +1159,10 @@ version_check_dnsmasq() {
local dnsmasq_pihole_id_string="addn-hosts=/etc/pihole/gravity.list" local dnsmasq_pihole_id_string="addn-hosts=/etc/pihole/gravity.list"
local dnsmasq_pihole_id_string2="# Dnsmasq config for Pi-hole's FTLDNS" 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_original_config="${PI_HOLE_LOCAL_REPO}/advanced/dnsmasq.conf.original"
local dnsmasq_pihole_01_snippet="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf" local dnsmasq_pihole_01_source="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf"
local dnsmasq_pihole_01_location="/etc/dnsmasq.d/01-pihole.conf" local dnsmasq_pihole_01_target="/etc/dnsmasq.d/01-pihole.conf"
local dnsmasq_rfc6761_06_source="${PI_HOLE_LOCAL_REPO}/advanced/06-rfc6761.conf"
local dnsmasq_rfc6761_06_target="/etc/dnsmasq.d/06-rfc6761.conf"
# If the dnsmasq config file exists # If the dnsmasq config file exists
if [[ -f "${dnsmasq_conf}" ]]; then if [[ -f "${dnsmasq_conf}" ]]; then
@ -1266,8 +1180,8 @@ version_check_dnsmasq() {
install -D -m 644 -T "${dnsmasq_original_config}" "${dnsmasq_conf}" install -D -m 644 -T "${dnsmasq_original_config}" "${dnsmasq_conf}"
printf "%b %b Restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}" printf "%b %b Restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}"
else else
# Otherwise, don't to anything # Otherwise, don't to anything
printf " it is not a Pi-hole file, leaving alone!\\n" printf " it is not a Pi-hole file, leaving alone!\\n"
fi fi
else else
# If a file cannot be found, # If a file cannot be found,
@ -1277,44 +1191,48 @@ version_check_dnsmasq() {
printf "%b %b No dnsmasq.conf found... restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}" printf "%b %b No dnsmasq.conf found... restoring default dnsmasq.conf...\\n" "${OVER}" "${TICK}"
fi fi
printf " %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..." "${INFO}" printf " %b Installing %s..." "${INFO}" "${dnsmasq_pihole_01_target}"
# Check to see if dnsmasq directory exists (it may not due to being a fresh install and dnsmasq no longer being a dependency) # 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 if [[ ! -d "/etc/dnsmasq.d" ]];then
install -d -m 755 "/etc/dnsmasq.d" install -d -m 755 "/etc/dnsmasq.d"
fi fi
# Copy the new Pi-hole DNS config file into the dnsmasq.d directory # Copy the new Pi-hole DNS config file into the dnsmasq.d directory
install -D -m 644 -T "${dnsmasq_pihole_01_snippet}" "${dnsmasq_pihole_01_location}" install -D -m 644 -T "${dnsmasq_pihole_01_source}" "${dnsmasq_pihole_01_target}"
printf "%b %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf\\n" "${OVER}" "${TICK}" printf "%b %b Installed %s\n" "${OVER}" "${TICK}" "${dnsmasq_pihole_01_target}"
# Replace our placeholder values with the GLOBAL DNS variables that we populated earlier # Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
# First, swap in the interface to listen on, # First, swap in the interface to listen on,
sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_location}" sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_target}"
if [[ "${PIHOLE_DNS_1}" != "" ]]; then if [[ "${PIHOLE_DNS_1}" != "" ]]; then
# then swap in the primary DNS server. # then swap in the primary DNS server.
sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_location}" sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_target}"
else else
# Otherwise, remove the line which sets DNS1. # Otherwise, remove the line which sets DNS1.
sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_location}" sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_target}"
fi fi
# Ditto if DNS2 is not empty # Ditto if DNS2 is not empty
if [[ "${PIHOLE_DNS_2}" != "" ]]; then if [[ "${PIHOLE_DNS_2}" != "" ]]; then
sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_location}" sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_target}"
else else
sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_location}" sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_target}"
fi fi
# Set the cache size # Set the cache size
sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" ${dnsmasq_pihole_01_location} sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" "${dnsmasq_pihole_01_target}"
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' "${dnsmasq_conf}" 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 the user does not want to enable logging,
if [[ "${QUERY_LOGGING}" == false ]] ; then if [[ "${QUERY_LOGGING}" == false ]] ; then
# disable it by commenting out the directive in the DNS config file # disable it by commenting out the directive in the DNS config file
sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_location}" sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_target}"
else else
# Otherwise, enable it by uncommenting the directive in the DNS config file # Otherwise, enable it by uncommenting the directive in the DNS config file
sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_location}" sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_target}"
fi 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 # Clean an existing installation to prepare for upgrade/reinstall
@ -1405,18 +1323,18 @@ installConfigs() {
# make it and set the owners # make it and set the owners
install -d -m 755 -o "${USER}" -g root /etc/lighttpd install -d -m 755 -o "${USER}" -g root /etc/lighttpd
# Otherwise, if the config file already exists # Otherwise, if the config file already exists
elif [[ -f "/etc/lighttpd/lighttpd.conf" ]]; then elif [[ -f "${lighttpdConfig}" ]]; then
# back up the original # back up the original
mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig mv "${lighttpdConfig}"{,.orig}
fi fi
# and copy in the config file Pi-hole needs # and copy in the config file Pi-hole needs
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}"
# Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it # Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it
touch /etc/lighttpd/external.conf touch /etc/lighttpd/external.conf
chmod 644 /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 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 if [[ -f "${PI_HOLE_BLOCKPAGE_DIR}/custom.php" ]]; then
sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' /etc/lighttpd/lighttpd.conf sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' "${lighttpdConfig}"
fi fi
# Make the directories if they do not exist and set the owners # Make the directories if they do not exist and set the owners
mkdir -p /run/lighttpd mkdir -p /run/lighttpd
@ -1563,9 +1481,6 @@ disable_resolved_stublistener() {
} }
update_package_cache() { 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 # Update package cache on apt based OSes. Do this every time since
# it's quick and packages can be updated at any time. # it's quick and packages can be updated at any time.
@ -1577,8 +1492,14 @@ update_package_cache() {
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else else
# Otherwise, show an error and exit # Otherwise, show an error and exit
# In case we used apt-get and apt is also available, we use this as recommendation as we have seen it
# gives more user-friendly (interactive) advice
if [[ ${PKG_MANAGER} == "apt-get" ]] && is_command apt ; then
UPDATE_PKG_CACHE="apt update"
fi
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "${UPDATE_PKG_CACHE}" "${COL_NC}" printf " %bError: Unable to update package cache. Please try \"%s\"%b\\n" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
return 1 return 1
fi fi
} }
@ -1630,6 +1551,8 @@ install_dependent_packages() {
# If there's anything to install, install everything in the list. # If there's anything to install, install everything in the list.
if [[ "${#installArray[@]}" -gt 0 ]]; then if [[ "${#installArray[@]}" -gt 0 ]]; then
test_dpkg_lock 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 " %b Processing %s install(s) for: %s, please wait...\\n" "${INFO}" "${PKG_MANAGER}" "${installArray[*]}"
printf '%*s\n' "$columns" '' | tr " " -; printf '%*s\n' "$columns" '' | tr " " -;
"${PKG_INSTALL[@]}" "${installArray[@]}" "${PKG_INSTALL[@]}" "${installArray[@]}"
@ -1642,7 +1565,7 @@ install_dependent_packages() {
# Install Fedora/CentOS packages # Install Fedora/CentOS packages
for i in "$@"; do for i in "$@"; do
# For each package, check if it's already installed (and if so, don't add it to the installArray) # For each package, check if it's already installed (and if so, don't add it to the installArray)
printf " %b Checking for %s..." "${INFO}" "${i}" printf " %b Checking for %s..." "${INFO}" "${i}"
if "${PKG_MANAGER}" -q list installed "${i}" &> /dev/null; then if "${PKG_MANAGER}" -q list installed "${i}" &> /dev/null; then
printf "%b %b Checking for %s\\n" "${OVER}" "${TICK}" "${i}" printf "%b %b Checking for %s\\n" "${OVER}" "${TICK}" "${i}"
@ -1808,20 +1731,22 @@ finalExports() {
# If the setup variable file exists, # If the setup variable file exists,
if [[ -e "${setupVars}" ]]; then if [[ -e "${setupVars}" ]]; then
# update the variables in the file # update the variables in the file
sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;' "${setupVars}" sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/d;' "${setupVars}"
fi fi
# echo the information to the user # echo the information to the user
{ {
echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}" echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
echo "IPV4_ADDRESS=${IPV4_ADDRESS}" echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
echo "IPV6_ADDRESS=${IPV6_ADDRESS}" echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}" echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}" echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
echo "QUERY_LOGGING=${QUERY_LOGGING}" echo "QUERY_LOGGING=${QUERY_LOGGING}"
echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}" echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}"
echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}" echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}"
echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}" echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}"
echo "CACHE_SIZE=${CACHE_SIZE}" echo "CACHE_SIZE=${CACHE_SIZE}"
echo "DNS_FQDN_REQUIRED=${DNS_FQDN_REQUIRED:-true}"
echo "DNS_BOGUS_PRIV=${DNS_BOGUS_PRIV:-true}"
}>> "${setupVars}" }>> "${setupVars}"
chmod 644 "${setupVars}" chmod 644 "${setupVars}"
@ -1869,27 +1794,6 @@ installLogrotate() {
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" 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 # Install base files and web interface
installPihole() { installPihole() {
# If the user wants to install the Web interface, # If the user wants to install the Web interface,
@ -1920,10 +1824,6 @@ installPihole() {
fi fi
fi fi
fi fi
# For updates and unattended install.
if [[ "${useUpdateVars}" == true ]]; then
accountForRefactor
fi
# Install base files and web interface # Install base files and web interface
if ! installScripts; then if ! installScripts; then
printf " %b Failure in dependent script copy function.\\n" "${CROSS}" printf " %b Failure in dependent script copy function.\\n" "${CROSS}"
@ -2008,7 +1908,7 @@ displayFinalMessage() {
if [[ "${#1}" -gt 0 ]] ; then if [[ "${#1}" -gt 0 ]] ; then
# set the password to the first argument. # set the password to the first argument.
pwstring="$1" pwstring="$1"
elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then elif [[ $(grep 'WEBPASSWORD' -c "${setupVars}") -gt 0 ]]; then
# Else if the password exists from previous setup, we'll load it later # Else if the password exists from previous setup, we'll load it later
pwstring="unchanged" pwstring="unchanged"
else else
@ -2021,7 +1921,7 @@ displayFinalMessage() {
additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin
Your Admin Webpage login password is ${pwstring}" Your Admin Webpage login password is ${pwstring}"
fi fi
# Final completion message to user # Final completion message to user
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using: whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using:
@ -2031,8 +1931,6 @@ IPv6: ${IPV6_ADDRESS:-"Not Configured"}
If you have not done so already, the above IP should be set to static. If you have not done so already, the above IP should be set to static.
The install log is in /etc/pihole.
${additional}" "${r}" "${c}" ${additional}" "${r}" "${c}"
} }
@ -2050,7 +1948,7 @@ update_dialogs() {
strAdd="You will be updated to the latest version." strAdd="You will be updated to the latest version."
fi fi
opt2a="Reconfigure" opt2a="Reconfigure"
opt2b="This will reset your Pi-hole and allow you to enter new settings." opt2b="Resets Pi-hole and allows re-selecting settings."
# Display the information to the user # 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 \ UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the following options: \\n($strAdd)" "${r}" "${c}" 2 \
@ -2145,7 +2043,7 @@ checkout_pull_branch() {
# Data in the repositories is public anyway so we can make it readable by everyone (+r to keep executable permission if already set by git) # 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}" chmod -R a+rX "${directory}"
git_pull=$(git pull || return 1) git_pull=$(git pull --no-rebase || return 1)
if [[ "$git_pull" == *"up-to-date"* ]]; then if [[ "$git_pull" == *"up-to-date"* ]]; then
printf " %b %s\\n" "${INFO}" "${git_pull}" printf " %b %s\\n" "${INFO}" "${git_pull}"
@ -2556,6 +2454,11 @@ main() {
printf " %b Checking for / installing Required dependencies for this install script...\\n" "${INFO}" printf " %b Checking for / installing Required dependencies for this install script...\\n" "${INFO}"
install_dependent_packages "${INSTALLER_DEPS[@]}" 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 # Check if SELinux is Enforcing
checkSelinux checkSelinux
@ -2583,12 +2486,12 @@ main() {
get_available_interfaces get_available_interfaces
# Find interfaces and let the user choose one # Find interfaces and let the user choose one
chooseInterface chooseInterface
# find IPv4 and IPv6 information of the device
collect_v4andv6_information
# Decide what upstream DNS Servers to use # Decide what upstream DNS Servers to use
setDNS setDNS
# Give the user a choice of blocklists to include in their install. Or not. # Give the user a choice of blocklists to include in their install. Or not.
chooseBlocklists chooseBlocklists
# Let the user decide if they want to block ads over IPv4 and/or IPv6
use4andor6
# Let the user decide if they want the web interface to be installed automatically # Let the user decide if they want the web interface to be installed automatically
setAdminFlag setAdminFlag
# Let the user decide if they want query logging enabled... # Let the user decide if they want query logging enabled...
@ -2661,7 +2564,7 @@ main() {
# Add password to web UI if there is none # Add password to web UI if there is none
pw="" pw=""
# If no password is set, # If no password is set,
if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then if [[ $(grep 'WEBPASSWORD' -c "${setupVars}") == 0 ]] ; then
# generate a random password # generate a random password
pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8) pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
# shellcheck disable=SC1091 # shellcheck disable=SC1091

View file

@ -145,6 +145,7 @@ removeNoPurge() {
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null ${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/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 /var/log/*pihole* &> /dev/null
${SUDO} rm -rf /etc/pihole/ &> /dev/null ${SUDO} rm -rf /etc/pihole/ &> /dev/null
${SUDO} rm -rf /etc/.pihole/ &> /dev/null ${SUDO} rm -rf /etc/.pihole/ &> /dev/null

View file

@ -15,8 +15,6 @@ export LC_ALL=C
coltable="/opt/pihole/COL_TABLE" coltable="/opt/pihole/COL_TABLE"
source "${coltable}" source "${coltable}"
regexconverter="/opt/pihole/wildcard_regex_converter.sh"
source "${regexconverter}"
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh" source "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh"
@ -122,7 +120,7 @@ gravity_swap_databases() {
gravityBlocks=$(stat --format "%b" ${gravityDBfile}) 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. # 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... # Better be safe than sorry...
if [ "${availableBlocks}" -gt "$(("${gravityBlocks}" * 2))" ] && [ -f "${gravityDBfile}" ]; then if [ "${availableBlocks}" -gt "$((gravityBlocks * 2))" ] && [ -f "${gravityDBfile}" ]; then
echo -e " ${TICK} The old database remains available." echo -e " ${TICK} The old database remains available."
mv "${gravityDBfile}" "${gravityOLDfile}" mv "${gravityDBfile}" "${gravityOLDfile}"
else else
@ -215,7 +213,7 @@ database_table_from_file() {
# Move source file to backup directory, create directory if not existing # Move source file to backup directory, create directory if not existing
mkdir -p "${backup_path}" mkdir -p "${backup_path}"
mv "${source}" "${backup_file}" 2> /dev/null || \ mv "${source}" "${backup_file}" 2> /dev/null || \
echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}" echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
# Delete tmpFile # Delete tmpFile
rm "${tmpFile}" > /dev/null 2>&1 || \ rm "${tmpFile}" > /dev/null 2>&1 || \
@ -432,9 +430,9 @@ gravity_DownloadBlocklists() {
compression="--compressed" compression="--compressed"
echo -e " ${INFO} Using libz compression\n" echo -e " ${INFO} Using libz compression\n"
else else
compression="" compression=""
echo -e " ${INFO} Libz compression not available\n" echo -e " ${INFO} Libz compression not available\n"
fi fi
# Loop through $sources and download each one # Loop through $sources and download each one
for ((i = 0; i < "${#sources[@]}"; i++)); do for ((i = 0; i < "${#sources[@]}"; i++)); do
url="${sources[$i]}" url="${sources[$i]}"
@ -464,9 +462,9 @@ gravity_DownloadBlocklists() {
check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$url" )" check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$url" )"
if [[ "${check_url}" =~ ${regex} ]]; then if [[ "${check_url}" =~ ${regex} ]]; then
echo -e " ${CROSS} Invalid Target" echo -e " ${CROSS} Invalid Target"
else else
gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}" gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}"
fi fi
echo "" echo ""
done done
@ -585,28 +583,28 @@ gravity_DownloadBlocklistFromUrl() {
blocked=false blocked=false
case $BLOCKINGMODE in case $BLOCKINGMODE in
"IP-NODATA-AAAA"|"IP") "IP-NODATA-AAAA"|"IP")
# Get IP address of this domain # Get IP address of this domain
ip="$(dig "${domain}" +short)" ip="$(dig "${domain}" +short)"
# Check if this IP matches any IP of the system # Check if this IP matches any IP of the system
if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<< "$(ip a)") -gt 0 ]]; then if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<< "$(ip a)") -gt 0 ]]; then
blocked=true blocked=true
fi;; fi;;
"NXDOMAIN") "NXDOMAIN")
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
blocked=true blocked=true
fi;; fi;;
"NULL"|*) "NULL"|*)
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
blocked=true blocked=true
fi;; fi;;
esac esac
if [[ "${blocked}" == true ]]; then if [[ "${blocked}" == true ]]; then
printf -v ip_addr "%s" "${PIHOLE_DNS_1%#*}" printf -v ip_addr "%s" "${PIHOLE_DNS_1%#*}"
if [[ ${PIHOLE_DNS_1} != *"#"* ]]; then if [[ ${PIHOLE_DNS_1} != *"#"* ]]; then
port=53 port=53
else else
printf -v port "%s" "${PIHOLE_DNS_1#*#}" printf -v port "%s" "${PIHOLE_DNS_1#*#}"
fi fi
ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}" | tail -1) ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}" | tail -1)
if [[ $(echo "${url}" | awk -F '://' '{print $1}') = "https" ]]; then if [[ $(echo "${url}" | awk -F '://' '{print $1}') = "https" ]]; then
@ -625,11 +623,11 @@ gravity_DownloadBlocklistFromUrl() {
case $url in case $url in
# Did we "download" a local file? # Did we "download" a local file?
"file"*) "file"*)
if [[ -s "${patternBuffer}" ]]; then if [[ -s "${patternBuffer}" ]]; then
echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
else else
echo -e "${OVER} ${CROSS} ${str} Not found / empty list" echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
fi;; fi;;
# Did we "download" a remote file? # Did we "download" a remote file?
*) *)
# Determine "Status:" output based on HTTP response # Determine "Status:" output based on HTTP response

34
pihole
View file

@ -398,34 +398,24 @@ Branches:
} }
tricorderFunc() { tricorderFunc() {
local tricorder_token
if [[ ! -p "/dev/stdin" ]]; then if [[ ! -p "/dev/stdin" ]]; then
echo -e " ${INFO} Please do not call Tricorder directly" echo -e " ${INFO} Please do not call Tricorder directly"
exit 1 exit 1
fi fi
if ! (echo > /dev/tcp/tricorder.pi-hole.net/9998) >/dev/null 2>&1; then tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
echo -e " ${CROSS} Unable to connect to Pi-hole's Tricorder server" if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
exit 1 echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
fi # Log curl error (if available)
if [ -n "${tricorder_token}" ]; then
if command -v openssl &> /dev/null; then echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin tricorder_token=""
exit "$?" fi
else exit 1
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 fi
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
exit 0
} }
updateCheckFunc() { updateCheckFunc() {

View file

@ -18,8 +18,8 @@ py.test -vv -n auto -m "build_stage"
py.test -vv -n auto -m "not build_stage" py.test -vv -n auto -m "not build_stage"
``` ```
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change. The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
# How do I debug python? # How do I debug python?
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :) Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)

View file

@ -1,4 +1,5 @@
FROM centos:7 FROM centos:7
RUN yum install -y git
ENV GITDIR /etc/.pihole ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole ENV SCRIPTDIR /opt/pihole

View file

@ -1,4 +1,5 @@
FROM centos:8 FROM centos:8
RUN yum install -y git
ENV GITDIR /etc/.pihole ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole ENV SCRIPTDIR /opt/pihole

View file

@ -1,4 +1,5 @@
FROM fedora:33 FROM fedora:33
RUN dnf install -y git
ENV GITDIR /etc/.pihole ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole ENV SCRIPTDIR /opt/pihole

View file

@ -1,4 +1,5 @@
FROM fedora:32 FROM fedora:34
RUN dnf install -y git
ENV GITDIR /etc/.pihole ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole ENV SCRIPTDIR /opt/pihole

View file

@ -1,10 +1,9 @@
import pytest import pytest
import testinfra import testinfra
import testinfra.backend.docker
import subprocess
from textwrap import dedent from textwrap import dedent
check_output = testinfra.get_backend(
"local://"
).get_module("Command").check_output
SETUPVARS = { SETUPVARS = {
'PIHOLE_INTERFACE': 'eth99', 'PIHOLE_INTERFACE': 'eth99',
@ -12,85 +11,42 @@ SETUPVARS = {
'PIHOLE_DNS_2': '4.2.2.2' 'PIHOLE_DNS_2': '4.2.2.2'
} }
IMAGE = 'pytest_pihole:test_container'
tick_box = "[\x1b[1;32m\u2713\x1b[0m]" tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
cross_box = "[\x1b[1;31m\u2717\x1b[0m]" cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
info_box = "[i]" info_box = "[i]"
@pytest.fixture # Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
def Pihole(Docker): # https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
''' def run_bash(self, command, *args, **kwargs):
used to contain some script stubbing, now pretty much an alias. cmd = self.get_command(command, *args)
Also provides bash as the default run function shell if self.user is not None:
''' out = self.run_local(
def run_bash(self, command, *args, **kwargs): "docker exec -u %s %s /bin/bash -c %s", self.user, self.name, cmd
cmd = self.get_command(command, *args) )
if self.user is not None: else:
out = self.run_local( out = self.run_local("docker exec %s /bin/bash -c %s", self.name, cmd)
"docker exec -u %s %s /bin/bash -c %s", out.command = self.encode(cmd)
self.user, self.name, cmd) return out
else:
out = self.run_local(
"docker exec %s /bin/bash -c %s", self.name, cmd)
out.command = self.encode(cmd)
return out
funcType = type(Docker.run)
Docker.run = funcType(run_bash, Docker) testinfra.backend.docker.DockerBackend.run = run_bash
return Docker
@pytest.fixture @pytest.fixture
def Docker(request, args, image, cmd): def host():
''' # run a container
combine our fixtures into a docker run command and setup finalizer to docker_id = subprocess.check_output(
cleanup ['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
'''
assert 'docker' in check_output('id'), "Are you in the docker group?"
docker_run = "docker run {} {} {}".format(args, image, cmd)
docker_id = check_output(docker_run)
def teardown(): # return a testinfra connection to the container
check_output("docker rm -f %s", docker_id) docker_host = testinfra.get_host("docker://" + docker_id)
request.addfinalizer(teardown)
docker_container = testinfra.get_backend("docker://" + docker_id) yield docker_host
docker_container.id = docker_id # at the end of the test suite, destroy the container
return docker_container subprocess.check_call(['docker', 'rm', '-f', docker_id])
@pytest.fixture
def args(request):
'''
-t became required when tput began being used
'''
return '-t -d'
@pytest.fixture(params=[
'test_container'
])
def tag(request):
'''
consumed by image to make the test matrix
'''
return request.param
@pytest.fixture()
def image(request, tag):
'''
built by test_000_build_containers.py
'''
return 'pytest_pihole:{}'.format(tag)
@pytest.fixture()
def cmd(request):
'''
default to doing nothing by tailing null, but don't exit
'''
return 'tail -f /dev/null'
# Helper functions # Helper functions
@ -100,7 +56,7 @@ def mock_command(script, args, container):
in unit tests in unit tests
''' '''
full_script_path = '/usr/local/bin/{}'.format(script) full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent('''\ mock_script = dedent(r'''\
#!/bin/bash -e #!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script} echo "\$0 \$@" >> /var/log/{script}
case "\$1" in'''.format(script=script)) case "\$1" in'''.format(script=script))
@ -121,13 +77,75 @@ def mock_command(script, args, container):
scriptlog=script)) scriptlog=script))
def mock_command_passthrough(script, args, container):
'''
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
be passed through to the actual command.
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
'''
orig_script_path = container.check_output('command -v {}'.format(script))
full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent(r'''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1" in'''.format(script=script))
for k, v in args.items():
case = dedent('''
{arg})
echo {res}
exit {retcode}
;;'''.format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent(r'''
*)
{orig_script_path} "\$@"
;;'''.format(orig_script_path=orig_script_path))
mock_script += dedent('''
esac''')
container.run('''
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
content=mock_script,
scriptlog=script))
def mock_command_run(script, args, container):
'''
Allows for setup of commands we don't really want to have to run for real
in unit tests
'''
full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent(r'''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in'''.format(script=script))
for k, v in args.items():
case = dedent('''
\"{arg}\")
echo {res}
exit {retcode}
;;'''.format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent('''
esac''')
container.run('''
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
content=mock_script,
scriptlog=script))
def mock_command_2(script, args, container): def mock_command_2(script, args, container):
''' '''
Allows for setup of commands we don't really want to have to run for real Allows for setup of commands we don't really want to have to run for real
in unit tests in unit tests
''' '''
full_script_path = '/usr/local/bin/{}'.format(script) full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent('''\ mock_script = dedent(r'''\
#!/bin/bash -e #!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script} echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in'''.format(script=script)) case "\$1 \$2" in'''.format(script=script))

View file

@ -1,6 +1,6 @@
docker-compose==1.23.2 docker-compose
pytest==4.3.0 pytest
pytest-xdist==1.26.1 pytest-xdist
pytest-cov==2.6.1 pytest-cov
testinfra==1.19.0 pytest-testinfra
tox==3.7.0 tox

File diff suppressed because it is too large Load diff

View file

@ -5,49 +5,52 @@ from .conftest import (
) )
def test_php_upgrade_default_optout_centos_eq_7(Pihole): def test_php_upgrade_default_optout_centos_eq_7(host):
''' '''
confirms the default behavior to opt-out of installing PHP7 from REMI confirms the default behavior to opt-out of installing PHP7 from REMI
''' '''
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. ' expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.') 'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_upgrade_user_optout_centos_eq_7(Pihole): def test_php_upgrade_user_optout_centos_eq_7(host):
''' '''
confirms installer behavior when user opt-out of installing PHP7 from REMI confirms installer behavior when user opt-out of installing PHP7 from REMI
(php not currently installed) (php not currently installed)
''' '''
# Whiptail dialog returns Cancel for user prompt # Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*': ('', '1')}, Pihole) mock_command('whiptail', {'*': ('', '1')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. ' expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.') 'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_upgrade_user_optin_centos_eq_7(Pihole): def test_php_upgrade_user_optin_centos_eq_7(host):
''' '''
confirms installer behavior when user opt-in to installing PHP7 from REMI confirms installer behavior when user opt-in to installing PHP7 from REMI
(php not currently installed) (php not currently installed)
''' '''
# Whiptail dialog returns Continue for user prompt # Whiptail dialog returns Continue for user prompt
mock_command('whiptail', {'*': ('', '0')}, Pihole) mock_command('whiptail', {'*': ('', '0')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
assert 'opt-out' not in package_manager_detect.stdout assert 'opt-out' not in package_manager_detect.stdout
expected_stdout = info_box + (' Enabling Remi\'s RPM repository ' expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
@ -56,5 +59,5 @@ def test_php_upgrade_user_optin_centos_eq_7(Pihole):
expected_stdout = tick_box + (' Remi\'s RPM repository has ' expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7') 'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert remi_package.is_installed assert remi_package.is_installed

View file

@ -5,54 +5,57 @@ from .conftest import (
) )
def test_php_upgrade_default_continue_centos_gte_8(Pihole): def test_php_upgrade_default_continue_centos_gte_8(host):
''' '''
confirms the latest version of CentOS continues / does not optout confirms the latest version of CentOS continues / does not optout
(should trigger on CentOS7 only) (should trigger on CentOS7 only)
''' '''
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.' unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
' Deprecated PHP may be in use.') ' Deprecated PHP may be in use.')
assert unexpected_stdout not in package_manager_detect.stdout assert unexpected_stdout not in package_manager_detect.stdout
# ensure remi was not installed on latest CentOS # ensure remi was not installed on latest CentOS
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_upgrade_user_optout_skipped_centos_gte_8(Pihole): def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
''' '''
confirms installer skips user opt-out of installing PHP7 from REMI on confirms installer skips user opt-out of installing PHP7 from REMI on
latest CentOS (should trigger on CentOS7 only) latest CentOS (should trigger on CentOS7 only)
(php not currently installed) (php not currently installed)
''' '''
# Whiptail dialog returns Cancel for user prompt # Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*': ('', '1')}, Pihole) mock_command('whiptail', {'*': ('', '1')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.' unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
' Deprecated PHP may be in use.') ' Deprecated PHP may be in use.')
assert unexpected_stdout not in package_manager_detect.stdout assert unexpected_stdout not in package_manager_detect.stdout
# ensure remi was not installed on latest CentOS # ensure remi was not installed on latest CentOS
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole): def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
''' '''
confirms installer skips user opt-in to installing PHP7 from REMI on confirms installer skips user opt-in to installing PHP7 from REMI on
latest CentOS (should trigger on CentOS7 only) latest CentOS (should trigger on CentOS7 only)
(php not currently installed) (php not currently installed)
''' '''
# Whiptail dialog returns Continue for user prompt # Whiptail dialog returns Continue for user prompt
mock_command('whiptail', {'*': ('', '0')}, Pihole) mock_command('whiptail', {'*': ('', '0')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
assert 'opt-out' not in package_manager_detect.stdout assert 'opt-out' not in package_manager_detect.stdout
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository ' unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
@ -61,5 +64,5 @@ def test_php_upgrade_user_optin_skipped_centos_gte_8(Pihole):
unexpected_stdout = tick_box + (' Remi\'s RPM repository has ' unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7') 'been enabled for PHP7')
assert unexpected_stdout not in package_manager_detect.stdout assert unexpected_stdout not in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed

View file

@ -7,15 +7,16 @@ from .conftest import (
) )
def test_release_supported_version_check_centos(Pihole): def test_release_supported_version_check_centos(host):
''' '''
confirms installer exits on unsupported releases of CentOS confirms installer exits on unsupported releases of CentOS
''' '''
# modify /etc/redhat-release to mock an unsupported CentOS release # modify /etc/redhat-release to mock an unsupported CentOS release
Pihole.run('echo "CentOS Linux release 6.9" > /etc/redhat-release') host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = cross_box + (' CentOS 6 is not supported.') expected_stdout = cross_box + (' CentOS 6 is not supported.')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
@ -23,85 +24,89 @@ def test_release_supported_version_check_centos(Pihole):
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
def test_enable_epel_repository_centos(Pihole): def test_enable_epel_repository_centos(host):
''' '''
confirms the EPEL package repository is enabled when installed on CentOS confirms the EPEL package repository is enabled when installed on CentOS
''' '''
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = info_box + (' Enabling EPEL package repository ' expected_stdout = info_box + (' Enabling EPEL package repository '
'(https://fedoraproject.org/wiki/EPEL)') '(https://fedoraproject.org/wiki/EPEL)')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
expected_stdout = tick_box + ' Installed epel-release' expected_stdout = tick_box + ' Installed epel-release'
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
epel_package = Pihole.package('epel-release') epel_package = host.package('epel-release')
assert epel_package.is_installed assert epel_package.is_installed
def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole): def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
''' '''
confirms the default behavior to opt-out of upgrading to PHP7 from REMI confirms the default behavior to opt-out of upgrading to PHP7 from REMI
''' '''
# first we will install the default php version to test installer behavior # first we will install the default php version to test installer behavior
php_install = Pihole.run('yum install -y php') php_install = host.run('yum install -y php')
assert php_install.rc == 0 assert php_install.rc == 0
php_package = Pihole.package('php') php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0] default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7") pytest.skip("Test deprecated . Detected default PHP version >= 7")
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. ' expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.') 'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole): def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
''' '''
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
''' '''
# first we will install the default php version to test installer behavior # first we will install the default php version to test installer behavior
php_install = Pihole.run('yum install -y php') php_install = host.run('yum install -y php')
assert php_install.rc == 0 assert php_install.rc == 0
php_package = Pihole.package('php') php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0] default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7") pytest.skip("Test deprecated . Detected default PHP version >= 7")
# Whiptail dialog returns Cancel for user prompt # Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*': ('', '1')}, Pihole) mock_command('whiptail', {'*': ('', '1')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
''') ''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. ' expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
'Deprecated PHP may be in use.') 'Deprecated PHP may be in use.')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert not remi_package.is_installed assert not remi_package.is_installed
def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole): def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
''' '''
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
''' '''
# first we will install the default php version to test installer behavior # first we will install the default php version to test installer behavior
php_install = Pihole.run('yum install -y php') php_install = host.run('yum install -y php')
assert php_install.rc == 0 assert php_install.rc == 0
php_package = Pihole.package('php') php_package = host.package('php')
default_centos_php_version = php_package.version.split('.')[0] default_centos_php_version = php_package.version.split('.')[0]
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
pytest.skip("Test deprecated . Detected default PHP version >= 7") pytest.skip("Test deprecated . Detected default PHP version >= 7")
# Whiptail dialog returns Continue for user prompt # Whiptail dialog returns Continue for user prompt
mock_command('whiptail', {'*': ('', '0')}, Pihole) mock_command('whiptail', {'*': ('', '0')}, host)
package_manager_detect = Pihole.run(''' package_manager_detect = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
select_rpm_php
install_dependent_packages PIHOLE_WEB_DEPS[@] install_dependent_packages PIHOLE_WEB_DEPS[@]
''') ''')
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. ' expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
@ -113,8 +118,8 @@ def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
expected_stdout = tick_box + (' Remi\'s RPM repository has ' expected_stdout = tick_box + (' Remi\'s RPM repository has '
'been enabled for PHP7') 'been enabled for PHP7')
assert expected_stdout in package_manager_detect.stdout assert expected_stdout in package_manager_detect.stdout
remi_package = Pihole.package('remi-release') remi_package = host.package('remi-release')
assert remi_package.is_installed assert remi_package.is_installed
updated_php_package = Pihole.package('php') updated_php_package = host.package('php')
updated_php_version = updated_php_package.version.split('.')[0] updated_php_version = updated_php_package.version.split('.')[0]
assert int(updated_php_version) == 7 assert int(updated_php_version) == 7

View file

@ -5,7 +5,7 @@ from .conftest import (
) )
def mock_selinux_config(state, Pihole): def mock_selinux_config(state, host):
''' '''
Creates a mock SELinux config file with expected content Creates a mock SELinux config file with expected content
''' '''
@ -13,20 +13,20 @@ def mock_selinux_config(state, Pihole):
valid_states = ['enforcing', 'permissive', 'disabled'] valid_states = ['enforcing', 'permissive', 'disabled']
assert state in valid_states assert state in valid_states
# getenforce returns the running state of SELinux # getenforce returns the running state of SELinux
mock_command('getenforce', {'*': (state.capitalize(), '0')}, Pihole) mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
# create mock configuration with desired content # create mock configuration with desired content
Pihole.run(''' host.run('''
mkdir /etc/selinux mkdir /etc/selinux
echo "SELINUX={state}" > /etc/selinux/config echo "SELINUX={state}" > /etc/selinux/config
'''.format(state=state.lower())) '''.format(state=state.lower()))
def test_selinux_enforcing_exit(Pihole): def test_selinux_enforcing_exit(host):
''' '''
confirms installer prompts to exit when SELinux is Enforcing by default confirms installer prompts to exit when SELinux is Enforcing by default
''' '''
mock_selinux_config("enforcing", Pihole) mock_selinux_config("enforcing", host)
check_selinux = Pihole.run(''' check_selinux = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
checkSelinux checkSelinux
''') ''')
@ -37,12 +37,12 @@ def test_selinux_enforcing_exit(Pihole):
assert check_selinux.rc == 1 assert check_selinux.rc == 1
def test_selinux_permissive(Pihole): def test_selinux_permissive(host):
''' '''
confirms installer continues when SELinux is Permissive confirms installer continues when SELinux is Permissive
''' '''
mock_selinux_config("permissive", Pihole) mock_selinux_config("permissive", host)
check_selinux = Pihole.run(''' check_selinux = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
checkSelinux checkSelinux
''') ''')
@ -51,12 +51,12 @@ def test_selinux_permissive(Pihole):
assert check_selinux.rc == 0 assert check_selinux.rc == 0
def test_selinux_disabled(Pihole): def test_selinux_disabled(host):
''' '''
confirms installer continues when SELinux is Disabled confirms installer continues when SELinux is Disabled
''' '''
mock_selinux_config("disabled", Pihole) mock_selinux_config("disabled", host)
check_selinux = Pihole.run(''' check_selinux = host.run('''
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
checkSelinux checkSelinux
''') ''')

View file

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

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

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

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker

View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py37 envlist = py38
[testenv] [testenv]
whitelist_externals = docker whitelist_externals = docker